diff options
| author | Sebastian <sebasjm@gmail.com> | 2023-06-05 10:04:09 -0300 |
|---|---|---|
| committer | Sebastian <sebasjm@gmail.com> | 2023-06-05 10:04:09 -0300 |
| commit | c680f5aa71b08e978444df07f93c381f9d47ab82 (patch) | |
| tree | 81903fac003bb1e202cf69551e06ba41a6e960a5 /packages/exchange-backoffice-ui/src/pages | |
| parent | df53866e6b148ea5fd2ab57e906a4aa36b535ed3 (diff) | |
rename aml
Diffstat (limited to 'packages/exchange-backoffice-ui/src/pages')
11 files changed, 0 insertions, 1192 deletions
diff --git a/packages/exchange-backoffice-ui/src/pages/AntiMoneyLaunderingForm.tsx b/packages/exchange-backoffice-ui/src/pages/AntiMoneyLaunderingForm.tsx deleted file mode 100644 index 713c0d7c1..000000000 --- a/packages/exchange-backoffice-ui/src/pages/AntiMoneyLaunderingForm.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { h } from "preact"; -import { NiceForm } from "../NiceForm.js"; -import { v1 as form_902_11e_v1 } from "../forms/902_11e.js"; -import { v1 as form_902_12e_v1 } from "../forms/902_12e.js"; -import { v1 as form_902_13e_v1 } from "../forms/902_13e.js"; -import { v1 as form_902_15e_v1 } from "../forms/902_15e.js"; -import { v1 as form_902_1e_v1 } from "../forms/902_1e.js"; -import { v1 as form_902_4e_v1 } from "../forms/902_4e.js"; -import { v1 as form_902_5e_v1 } from "../forms/902_5e.js"; -import { v1 as form_902_9e_v1 } from "../forms/902_9e.js"; -import { v1 as simplest } from "../forms/simplest.js"; -import { DocumentDuplicateIcon } from "@heroicons/react/24/solid"; -import { AbsoluteTime } from "@gnu-taler/taler-util"; -import { AmlState } from "../types.js"; -import { AmountJson, Amounts } from "@gnu-taler/taler-util"; - -export function AntiMoneyLaunderingForm({ number }: { number?: string }) { - const selectedForm = Number.parseInt(number ?? "0", 10); - if (Number.isNaN(selectedForm)) { - return <div>WHAT! {number}</div>; - } - const showingFrom = allForms[selectedForm].impl; - const storedValue = { - fullName: "loggedIn_user_fullname", - when: AbsoluteTime.now(), - }; - return ( - <NiceForm - initial={storedValue} - form={showingFrom({ - state: AmlState.pending, - threshold: Amounts.parseOrThrow("USD:10"), - })} - onUpdate={() => {}} - /> - ); -} - -export interface State { - state: AmlState; - threshold: AmountJson; -} - -export const allForms = [ - { - name: "Simple comment", - icon: DocumentDuplicateIcon, - impl: simplest, - }, - { - name: "Identification form (902.1e)", - icon: DocumentDuplicateIcon, - impl: form_902_1e_v1, - }, - { - name: "Operational legal entity or partnership (902.11e)", - icon: DocumentDuplicateIcon, - impl: form_902_11e_v1, - }, - { - name: "Foundations (902.12e)", - icon: DocumentDuplicateIcon, - impl: form_902_12e_v1, - }, - { - name: "Declaration for trusts (902.13e)", - icon: DocumentDuplicateIcon, - impl: form_902_13e_v1, - }, - { - name: "Information on life insurance policies (902.15e)", - icon: DocumentDuplicateIcon, - impl: form_902_15e_v1, - }, - { - name: "Declaration of beneficial owner (902.9e)", - icon: DocumentDuplicateIcon, - impl: form_902_9e_v1, - }, - { - name: "Customer profile (902.5e)", - icon: DocumentDuplicateIcon, - impl: form_902_5e_v1, - }, - { - name: "Risk profile (902.4e)", - icon: DocumentDuplicateIcon, - impl: form_902_4e_v1, - }, -]; diff --git a/packages/exchange-backoffice-ui/src/pages/CaseDetails.tsx b/packages/exchange-backoffice-ui/src/pages/CaseDetails.tsx deleted file mode 100644 index e5fb8eaba..000000000 --- a/packages/exchange-backoffice-ui/src/pages/CaseDetails.tsx +++ /dev/null @@ -1,447 +0,0 @@ -import { Fragment, VNode, h } from "preact"; -import { - AmlDecisionDetail, - AmlDecisionDetails, - AmlState, - KycDetail, -} from "../types.js"; -import { - AbsoluteTime, - AmountJson, - Amounts, - TranslatedString, -} from "@gnu-taler/taler-util"; -import { format } from "date-fns"; -import { ArrowDownCircleIcon, ClockIcon } from "@heroicons/react/20/solid"; -import { useState } from "preact/hooks"; -import { NiceForm } from "../NiceForm.js"; -import { FlexibleForm } from "../forms/index.js"; -import { UIFormField } from "../handlers/forms.js"; -import { Pages } from "../pages.js"; - -const response: AmlDecisionDetails = { - aml_history: [ - { - justification: "Lack of documentation", - decider_pub: "ASDASDASD", - decision_time: { - t_s: Date.now() / 1000, - }, - new_state: 2, - new_threshold: "USD:0", - }, - { - justification: "Doing a transfer of high amount", - decider_pub: "ASDASDASD", - decision_time: { - t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 6, - }, - new_state: 1, - new_threshold: "USD:2000", - }, - { - justification: "Account is known to the system", - decider_pub: "ASDASDASD", - decision_time: { - t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 9, - }, - new_state: 0, - new_threshold: "USD:100", - }, - ], - kyc_attributes: [ - { - collection_time: { - t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 8, - }, - expiration_time: { - t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 4, - }, - provider_section: "asdasd", - attributes: { - name: "Sebastian", - }, - }, - { - collection_time: { - t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 5, - }, - expiration_time: { - t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 2, - }, - provider_section: "asdasd", - attributes: { - creditCard: "12312312312", - }, - }, - ], -}; -type AmlEvent = AmlFormEvent | KycCollectionEvent | KycExpirationEvent; -type AmlFormEvent = { - type: "aml-form"; - when: AbsoluteTime; - title: TranslatedString; - state: AmlState; - threshold: AmountJson; -}; -type KycCollectionEvent = { - type: "kyc-collection"; - when: AbsoluteTime; - title: TranslatedString; - values: object; - provider: string; -}; -type KycExpirationEvent = { - type: "kyc-expiration"; - when: AbsoluteTime; - title: TranslatedString; - fields: string[]; -}; - -type WithTime = { when: AbsoluteTime }; - -function selectSooner(a: WithTime, b: WithTime) { - return AbsoluteTime.cmp(a.when, b.when); -} - -function getEventsFromAmlHistory( - aml: AmlDecisionDetail[], - kyc: KycDetail[], -): AmlEvent[] { - const ae: AmlEvent[] = aml.map((a) => { - return { - type: "aml-form", - state: a.new_state, - threshold: Amounts.parseOrThrow(a.new_threshold), - title: a.justification as TranslatedString, - when: { - t_ms: - a.decision_time.t_s === "never" - ? "never" - : a.decision_time.t_s * 1000, - }, - } as AmlEvent; - }); - const ke = kyc.reduce((prev, k) => { - prev.push({ - type: "kyc-collection", - title: "collection" as TranslatedString, - when: AbsoluteTime.fromProtocolTimestamp(k.collection_time), - values: !k.attributes ? {} : k.attributes, - provider: k.provider_section, - }); - prev.push({ - type: "kyc-expiration", - title: "expired" as TranslatedString, - when: AbsoluteTime.fromProtocolTimestamp(k.expiration_time), - fields: !k.attributes ? [] : Object.keys(k.attributes), - }); - return prev; - }, [] as AmlEvent[]); - return ae.concat(ke).sort(selectSooner); -} - -export function CaseDetails({ account }: { account?: string }) { - const events = getEventsFromAmlHistory( - response.aml_history, - response.kyc_attributes, - ); - console.log("DETAILS", events, events[events.length - 1 - 2]); - const [selected, setSelected] = useState<AmlEvent>( - events[events.length - 1 - 2], - ); - return ( - <div> - <a - href={Pages.newFormEntry.url({ account })} - class="m-4 block rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700" - > - New AML form - </a> - - <header class="flex items-center justify-between border-b border-white/5 px-4 py-4 sm:px-6 sm:py-6 lg:px-8"> - <h1 class="text-base font-semibold leading-7 text-black"> - Case history - </h1> - </header> - <div class="flow-root"> - <ul role="list"> - {events.map((e, idx) => { - const isLast = events.length - 1 === idx; - return ( - <li - class="hover:bg-gray-200 p-2 rounded cursor-pointer" - onClick={() => { - setSelected(e); - }} - > - <div class="relative pb-6"> - {!isLast ? ( - <span - class="absolute left-4 top-4 -ml-px h-full w-1 bg-gray-200" - aria-hidden="true" - ></span> - ) : undefined} - <div class="relative flex space-x-3"> - {(() => { - switch (e.type) { - case "aml-form": { - switch (e.state) { - case AmlState.normal: { - return ( - <div> - <span class="inline-flex items-center rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20"> - Normal - </span> - <span class="inline-flex items-center px-2 py-1 text-xs font-medium text-gray-700 "> - {e.threshold.currency}{" "} - {Amounts.stringifyValue(e.threshold)} - </span> - </div> - ); - } - case AmlState.pending: { - return ( - <div> - <span class="inline-flex items-center rounded-md bg-yellow-50 px-2 py-1 text-xs font-medium text-yellow-700 ring-1 ring-inset ring-green-600/20"> - Pending - </span> - <span class="inline-flex items-center px-2 py-1 text-xs font-medium text-gray-700 "> - {e.threshold.currency}{" "} - {Amounts.stringifyValue(e.threshold)} - </span> - </div> - ); - } - case AmlState.frozen: { - return ( - <div> - <span class="inline-flex items-center rounded-md bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 ring-inset ring-green-600/20"> - Frozen - </span> - <span class="inline-flex items-center px-2 py-1 text-xs font-medium text-gray-700 "> - {e.threshold.currency}{" "} - {Amounts.stringifyValue(e.threshold)} - </span> - </div> - ); - } - } - } - case "kyc-collection": { - return ( - <ArrowDownCircleIcon class="h-8 w-8 text-green-700" /> - ); - } - case "kyc-expiration": { - return <ClockIcon class="h-8 w-8 text-gray-700" />; - } - } - })()} - <div class="flex min-w-0 flex-1 justify-between space-x-4 pt-1.5"> - <div> - <p class="text-sm text-gray-900">{e.title}</p> - </div> - <div class="whitespace-nowrap text-right text-sm text-gray-500"> - {e.when.t_ms === "never" ? ( - "never" - ) : ( - <time dateTime={format(e.when.t_ms, "dd MMM yyyy")}> - {format(e.when.t_ms, "dd MMM yyyy")} - </time> - )} - </div> - </div> - </div> - </div> - </li> - ); - })} - </ul> - </div> - {selected && <ShowEventDetails event={selected} />} - {selected && <ShowConsolidated history={events} until={selected} />} - </div> - ); -} - -function ShowEventDetails({ event }: { event: AmlEvent }): VNode { - return <div>type {event.type}</div>; -} - -function ShowConsolidated({ - history, - until, -}: { - history: AmlEvent[]; - until: AmlEvent; -}): VNode { - console.log("UNTIL", until); - const cons = getConsolidated(history, until.when); - - const form: FlexibleForm<Consolidated> = { - versionId: "1", - behavior: (form) => { - return {}; - }, - design: [ - { - title: "AML" as TranslatedString, - fields: [ - { - type: "amount", - props: { - label: "Threshold" as TranslatedString, - name: "aml.threshold", - }, - }, - { - type: "choiceHorizontal", - props: { - label: "State" as TranslatedString, - name: "aml.state", - converter: amlStateConverter, - choices: [ - { - label: "Frozen" as TranslatedString, - value: AmlState.frozen, - }, - { - label: "Pending" as TranslatedString, - value: AmlState.pending, - }, - { - label: "Normal" as TranslatedString, - value: AmlState.normal, - }, - ], - }, - }, - ], - }, - Object.entries(cons.kyc).length > 0 - ? { - title: "KYC" as TranslatedString, - fields: Object.entries(cons.kyc).map(([key, field]) => { - const result: UIFormField = { - type: "text", - props: { - label: key as TranslatedString, - name: `kyc.${key}.value`, - help: `${field.provider} since ${ - field.since.t_ms === "never" - ? "never" - : format(field.since.t_ms, "dd/MM/yyyy") - }` as TranslatedString, - }, - }; - return result; - }), - } - : undefined, - ], - }; - return ( - <Fragment> - <h1 class="text-base font-semibold leading-7 text-black"> - Consolidated information after{" "} - {until.when.t_ms === "never" - ? "never" - : format(until.when.t_ms, "dd MMMM yyyy")} - </h1> - <NiceForm - key={`${String(Date.now())}`} - form={form} - initial={cons} - onUpdate={() => {}} - /> - </Fragment> - ); -} - -interface Consolidated { - aml: { - state?: AmlState; - threshold?: AmountJson; - since: AbsoluteTime; - }; - kyc: { - [field: string]: { - value: any; - provider: string; - since: AbsoluteTime; - }; - }; -} - -function getConsolidated( - history: AmlEvent[], - when: AbsoluteTime, -): Consolidated { - const initial: Consolidated = { - aml: { - since: AbsoluteTime.never(), - }, - kyc: {}, - }; - return history.reduce((prev, cur) => { - if (AbsoluteTime.cmp(when, cur.when) < 0) { - return prev; - } - switch (cur.type) { - case "kyc-expiration": { - cur.fields.forEach((field) => { - delete prev.kyc[field]; - }); - break; - } - case "aml-form": { - prev.aml.threshold = cur.threshold; - prev.aml.state = cur.state; - prev.aml.since = cur.when; - break; - } - case "kyc-collection": { - Object.keys(cur.values).forEach((field) => { - prev.kyc[field] = { - value: (cur.values as any)[field], - provider: cur.provider, - since: cur.when, - }; - }); - break; - } - } - return prev; - }, initial); -} - -export const amlStateConverter = { - toStringUI: stringifyAmlState, - fromStringUI: parseAmlState, -}; - -function stringifyAmlState(s: AmlState | undefined): string { - if (s === undefined) return ""; - switch (s) { - case AmlState.normal: - return "normal"; - case AmlState.pending: - return "pending"; - case AmlState.frozen: - return "frozen"; - } -} - -function parseAmlState(s: string | undefined): AmlState { - switch (s) { - case "normal": - return AmlState.normal; - case "pending": - return AmlState.pending; - case "frozen": - return AmlState.frozen; - default: - throw Error(`unknown AML state: ${s}`); - } -} diff --git a/packages/exchange-backoffice-ui/src/pages/Cases.tsx b/packages/exchange-backoffice-ui/src/pages/Cases.tsx deleted file mode 100644 index 28b9d2a88..000000000 --- a/packages/exchange-backoffice-ui/src/pages/Cases.tsx +++ /dev/null @@ -1,288 +0,0 @@ -import { VNode, h } from "preact"; -import { Pages } from "../pages.js"; -import { AmlRecords, AmlState } from "../types.js"; -import { InputChoiceHorizontal } from "../handlers/InputChoiceHorizontal.js"; -import { createNewForm } from "../handlers/forms.js"; -import { TranslatedString } from "@gnu-taler/taler-util"; -import { amlStateConverter as amlStateConverter } from "./CaseDetails.js"; -import { useState } from "preact/hooks"; -import { HandleAccountNotReady } from "./HandleAccountNotReady.js"; -import { useOfficer } from "../hooks/useOfficer.js"; - -const response: AmlRecords = { - records: [ - { - current_state: 0, - h_payto: "QWEQWEQWEQWEWQE", - rowid: 1, - threshold: "USD 100", - }, - { - current_state: 1, - h_payto: "ASDASDASD", - rowid: 1, - threshold: "USD 100", - }, - { - current_state: 2, - h_payto: "ZXCZXCZXCXZC", - rowid: 1, - threshold: "USD 1000", - }, - { - current_state: 0, - h_payto: "QWEQWEQWEQWEWQE", - rowid: 1, - threshold: "USD 100", - }, - { - current_state: 1, - h_payto: "ASDASDASD", - rowid: 1, - threshold: "USD 100", - }, - { - current_state: 2, - h_payto: "ZXCZXCZXCXZC", - rowid: 1, - threshold: "USD 1000", - }, - ].map((e, idx) => { - e.rowid = idx; - e.threshold = `${e.threshold}${idx}`; - return e; - }), -}; - -function doFilter( - list: typeof response.records, - filter: AmlState | undefined, -): typeof response.records { - if (filter === undefined) return list; - return list.filter((r) => r.current_state === filter); -} - -export function Cases() { - const officer = useOfficer(); - if (officer.state !== "ready") { - return <HandleAccountNotReady officer={officer} />; - } - const form = createNewForm<{ - state: AmlState; - }>(); - const initial = { state: AmlState.pending }; - const [list, setList] = useState(doFilter(response.records, initial.state)); - return ( - <div> - <div class="px-4 sm:px-6 lg:px-8"> - <div class="sm:flex sm:items-center"> - <div class="sm:flex-auto"> - <h1 class="text-base font-semibold leading-6 text-gray-900"> - Cases - </h1> - <p class="mt-2 text-sm text-gray-700"> - A list of all the account with the status - </p> - </div> - <form.Provider - initialValue={initial} - onUpdate={(v) => { - setList(doFilter(response.records, v.state)); - }} - onSubmit={(v) => {}} - > - <form.InputChoiceHorizontal - name="state" - label={"Filter" as TranslatedString} - converter={amlStateConverter} - choices={[ - { - label: "Pending" as TranslatedString, - value: AmlState.pending, - }, - { - label: "Frozen" as TranslatedString, - value: AmlState.frozen, - }, - { - label: "Normal" as TranslatedString, - value: AmlState.normal, - }, - ]} - /> - </form.Provider> - </div> - <div class="mt-8 flow-root"> - <div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> - <div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8"> - <Pagination /> - <table class="min-w-full divide-y divide-gray-300"> - <thead> - <tr> - <th - scope="col" - class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900" - > - Account Id - </th> - <th - scope="col" - class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900" - > - Status - </th> - <th - scope="col" - class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900" - > - Threshold - </th> - </tr> - </thead> - <tbody class="divide-y divide-gray-200 bg-white"> - {list.map((r) => { - return ( - <tr class="hover:bg-gray-100 "> - <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-500 "> - <div class="text-gray-900"> - <a - href={Pages.details.url({ account: r.h_payto })} - class="text-indigo-600 hover:text-indigo-900" - > - {r.h_payto} - </a> - </div> - </td> - <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-500"> - {((state: AmlState): VNode => { - switch (state) { - case AmlState.normal: { - return ( - <span class="inline-flex items-center rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20"> - Normal - </span> - ); - } - case AmlState.pending: { - return ( - <span class="inline-flex items-center rounded-md bg-yellow-50 px-2 py-1 text-xs font-medium text-yellow-700 ring-1 ring-inset ring-green-600/20"> - Pending - </span> - ); - } - case AmlState.frozen: { - return ( - <span class="inline-flex items-center rounded-md bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 ring-inset ring-green-600/20"> - Frozen - </span> - ); - } - } - })(r.current_state)} - </td> - <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-900"> - {r.threshold} - </td> - </tr> - ); - })} - </tbody> - </table> - <Pagination /> - </div> - </div> - </div> - </div> - </div> - ); -} - -function Pagination() { - return ( - <nav class="flex items-center justify-between px-4 sm:px-0"> - <div class="-mt-px flex w-0 flex-1"> - <a - href="#" - class="inline-flex items-center border-t-2 border-transparent pr-1 pt-4 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700" - > - <svg - class="mr-3 h-5 w-5 text-gray-400" - viewBox="0 0 20 20" - fill="currentColor" - aria-hidden="true" - > - <path - fill-rule="evenodd" - d="M18 10a.75.75 0 01-.75.75H4.66l2.1 1.95a.75.75 0 11-1.02 1.1l-3.5-3.25a.75.75 0 010-1.1l3.5-3.25a.75.75 0 111.02 1.1l-2.1 1.95h12.59A.75.75 0 0118 10z" - clip-rule="evenodd" - /> - </svg> - Previous - </a> - </div> - <div class="hidden md:-mt-px md:flex"> - <a - href="#" - class="inline-flex items-center border-t-2 border-transparent px-4 pt-4 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700" - > - 1 - </a> - {/* <!-- Current: "border-indigo-500 text-indigo-600", Default: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300" --> */} - <a - href="#" - class="inline-flex items-center border-t-2 border-transparent px-4 pt-4 text-sm font-medium text-gray-500" - aria-current="page" - > - 2 - </a> - <a - href="#" - class="inline-flex items-center border-t-2 border-transparent px-4 pt-4 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700" - > - 3 - </a> - <span class="inline-flex items-center border-t-2 border-transparent px-4 pt-4 text-sm font-medium text-gray-500"> - ... - </span> - <a - href="#" - class="inline-flex items-center border-t-2 border-transparent px-4 pt-4 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700" - > - 8 - </a> - <a - href="#" - class="inline-flex items-center border-t-2 border-transparent px-4 pt-4 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700" - > - 9 - </a> - <a - href="#" - class="inline-flex items-center border-t-2 border-transparent px-4 pt-4 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700" - > - 10 - </a> - </div> - <div class="-mt-px flex w-0 flex-1 justify-end"> - <a - href="#" - class="inline-flex items-center border-t-2 border-transparent pl-1 pt-4 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700" - > - Next - <svg - class="ml-3 h-5 w-5 text-gray-400" - viewBox="0 0 20 20" - fill="currentColor" - aria-hidden="true" - > - <path - fill-rule="evenodd" - d="M2 10a.75.75 0 01.75-.75h12.59l-2.1-1.95a.75.75 0 111.02-1.1l3.5 3.25a.75.75 0 010 1.1l-3.5 3.25a.75.75 0 11-1.02-1.1l2.1-1.95H2.75A.75.75 0 012 10z" - clip-rule="evenodd" - /> - </svg> - </a> - </div> - </nav> - ); -} diff --git a/packages/exchange-backoffice-ui/src/pages/CreateAccount.tsx b/packages/exchange-backoffice-ui/src/pages/CreateAccount.tsx deleted file mode 100644 index 5dcb8b21d..000000000 --- a/packages/exchange-backoffice-ui/src/pages/CreateAccount.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import { TranslatedString } from "@gnu-taler/taler-util"; -import { - notifyError, - useTranslationContext, -} from "@gnu-taler/web-util/browser"; -import { VNode, h } from "preact"; -import { createNewForm } from "../handlers/forms.js"; - -export function CreateAccount({ - onNewAccount, -}: { - onNewAccount: (password: string) => void; -}): VNode { - const { i18n } = useTranslationContext(); - const Form = createNewForm<{ - password: string; - repeat: string; - }>(); - - return ( - <div class="flex min-h-full flex-col "> - <div class="sm:mx-auto sm:w-full sm:max-w-md"> - <h2 class="mt-6 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900"> - Create account - </h2> - </div> - - <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px] "> - <div class="bg-gray-100 px-6 py-6 shadow sm:rounded-lg sm:px-12"> - <Form.Provider - computeFormState={(v) => { - return { - password: { - error: !v.password - ? i18n.str`required` - : v.password.length < 8 - ? i18n.str`should have at least 8 characters` - : !v.password.match(/[a-z]/) && v.password.match(/[A-Z]/) - ? i18n.str`should have lowercase and uppercase characters` - : !v.password.match(/\d/) - ? i18n.str`should have numbers` - : !v.password.match(/[^a-zA-Z\d]/) - ? i18n.str`should have at least one character which is not a number or letter` - : undefined, - }, - repeat: { - error: !v.repeat - ? i18n.str`required` - : v.repeat !== v.password - ? i18n.str`doesn't match` - : undefined, - }, - }; - }} - onSubmit={async (v, s) => { - console.log(v, s); - const error = s?.password?.error ?? s?.repeat?.error; - console.log(error); - if (error) { - notifyError( - "Can't create account" as TranslatedString, - error as TranslatedString, - ); - } else { - onNewAccount(v.password!); - } - }} - > - <div class="mb-4"> - <Form.InputLine - label={"Password" as TranslatedString} - name="password" - type="password" - help={ - "lower and upper case letters, number and special character" as TranslatedString - } - required - /> - </div> - <div class="mb-4"> - <Form.InputLine - label={"Repeat password" as TranslatedString} - name="repeat" - type="password" - required - /> - </div> - - <div class="mt-8"> - <button - type="submit" - class="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" - > - Create - </button> - </div> - </Form.Provider> - </div> - </div> - </div> - ); -} diff --git a/packages/exchange-backoffice-ui/src/pages/HandleAccountNotReady.tsx b/packages/exchange-backoffice-ui/src/pages/HandleAccountNotReady.tsx deleted file mode 100644 index 05fd0a019..000000000 --- a/packages/exchange-backoffice-ui/src/pages/HandleAccountNotReady.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { VNode, h } from "preact"; -import { OfficerNotReady } from "../hooks/useOfficer.js"; -import { CreateAccount } from "./CreateAccount.js"; -import { UnlockAccount } from "./UnlockAccount.js"; - -export function HandleAccountNotReady({ - officer, -}: { - officer: OfficerNotReady; -}): VNode { - if (officer.state === "not-found") { - return ( - <CreateAccount - onNewAccount={(password) => { - officer.create(password); - }} - /> - ); - } - - if (officer.state === "locked") { - return ( - <UnlockAccount - onRemoveAccount={() => { - officer.forget(); - }} - onAccountUnlocked={(pwd) => { - officer.tryUnlock(pwd); - }} - /> - ); - } - throw Error(`unexpected account state ${(officer as any).state}`); -} diff --git a/packages/exchange-backoffice-ui/src/pages/Home.tsx b/packages/exchange-backoffice-ui/src/pages/Home.tsx deleted file mode 100644 index 838032d63..000000000 --- a/packages/exchange-backoffice-ui/src/pages/Home.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { h } from "preact"; - -export function Home() { - return <div>Home</div>; -} diff --git a/packages/exchange-backoffice-ui/src/pages/NewFormEntry.tsx b/packages/exchange-backoffice-ui/src/pages/NewFormEntry.tsx deleted file mode 100644 index fdb255701..000000000 --- a/packages/exchange-backoffice-ui/src/pages/NewFormEntry.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { VNode, h } from "preact"; -import { allForms } from "./AntiMoneyLaunderingForm.js"; -import { Pages } from "../pages.js"; -import { NiceForm } from "../NiceForm.js"; -import { AmlState } from "../types.js"; -import { AbsoluteTime, Amounts } from "@gnu-taler/taler-util"; - -export function NewFormEntry({ - account, - type, -}: { - account?: string; - type?: string; -}): VNode { - if (!account) { - return <div>no account</div>; - } - if (!type) { - return <SelectForm account={account} />; - } - - const selectedForm = Number.parseInt(type ?? "0", 10); - if (Number.isNaN(selectedForm)) { - return <div>WHAT! {type}</div>; - } - const showingFrom = allForms[selectedForm].impl; - const initial = { - fullName: "loggedIn_user_fullname", - when: AbsoluteTime.now(), - state: AmlState.pending, - threshold: Amounts.parseOrThrow("USD:10"), - }; - return ( - <NiceForm - initial={initial} - form={showingFrom(initial)} - onSubmit={(v) => { - alert(JSON.stringify(v)); - }} - > - <div class="mt-6 flex items-center justify-end gap-x-6"> - <a - // type="button" - href={Pages.details.url({ account })} - class="text-sm font-semibold leading-6 text-gray-900" - > - Cancel - </a> - <button - type="submit" - class="rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" - > - Confirm - </button> - </div> - </NiceForm> - ); -} - -function SelectForm({ account }: { account: string }) { - return ( - <div> - <pre>New form for account: {account}</pre> - {allForms.map((form, idx) => { - return ( - <a - href={Pages.newFormEntry.url({ account, type: String(idx) })} - class="m-4 block rounded-md w-fit border-0 p-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-600" - > - {form.name} - </a> - ); - })} - </div> - ); -} diff --git a/packages/exchange-backoffice-ui/src/pages/Officer.tsx b/packages/exchange-backoffice-ui/src/pages/Officer.tsx deleted file mode 100644 index 5320369e4..000000000 --- a/packages/exchange-backoffice-ui/src/pages/Officer.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { Fragment, h } from "preact"; -import { useOfficer } from "../hooks/useOfficer.js"; -import { HandleAccountNotReady } from "./HandleAccountNotReady.js"; - -export function Officer() { - const officer = useOfficer(); - if (officer.state !== "ready") { - return <HandleAccountNotReady officer={officer} />; - } - - return ( - <div> - <h1 class="my-2 text-3xl font-bold tracking-tight text-gray-900 "> - Public key - </h1> - <div class="max-w-xl text-base leading-7 text-gray-700 lg:max-w-lg"> - <p class="mt-6 font-mono break-all">{officer.account.accountId}</p> - </div> - <p> - <a - href={`mailto:aml@exchange.taler.net?body=${encodeURIComponent( - `I want my AML account\n\n\nPubKey: ${officer.account.accountId}`, - )}`} - target="_blank" - rel="noreferrer" - class="m-4 block rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700" - > - Request account activation - </a> - </p> - <p> - <button - type="button" - onClick={() => { - officer.lock(); - }} - class="m-4 block rounded-md border-0 bg-gray-200 px-3 py-2 text-center text-sm text-black shadow-sm " - > - Lock account - </button> - </p> - <p> - <button - type="button" - onClick={() => { - officer.forget(); - }} - class="m-4 block rounded-md bg-red-600 px-3 py-2 text-center text-sm text-white shadow-sm hover:bg-red-500 " - > - Remove account - </button> - </p> - </div> - ); -} diff --git a/packages/exchange-backoffice-ui/src/pages/Settings.tsx b/packages/exchange-backoffice-ui/src/pages/Settings.tsx deleted file mode 100644 index ccff3b210..000000000 --- a/packages/exchange-backoffice-ui/src/pages/Settings.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { h } from "preact"; - -export function Settings() { - return <div>Settings</div>; -} diff --git a/packages/exchange-backoffice-ui/src/pages/UnlockAccount.tsx b/packages/exchange-backoffice-ui/src/pages/UnlockAccount.tsx deleted file mode 100644 index 2ebac0718..000000000 --- a/packages/exchange-backoffice-ui/src/pages/UnlockAccount.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { TranslatedString } from "@gnu-taler/taler-util"; -import { notifyError, notifyInfo } from "@gnu-taler/web-util/browser"; -import { VNode, h } from "preact"; -import { UnwrapKeyError } from "../account.js"; -import { createNewForm } from "../handlers/forms.js"; - -export function UnlockAccount({ - onAccountUnlocked, - onRemoveAccount, -}: { - onAccountUnlocked: (password: string) => void; - onRemoveAccount: () => void; -}): VNode { - const Form = createNewForm<{ - password: string; - }>(); - - return ( - <div class="flex min-h-full flex-col "> - <div class="sm:mx-auto sm:w-full sm:max-w-md"> - <h2 class="mt-6 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900"> - Account locked - </h2> - <p class="mt-6 text-lg leading-8 text-gray-600"> - Your account is normally locked anytime you reload. To unlock type - your password again. - </p> - </div> - - <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px] "> - <div class="bg-gray-100 px-6 py-6 shadow sm:rounded-lg sm:px-12"> - <Form.Provider - onSubmit={async (v) => { - try { - await onAccountUnlocked(v.password!); - - notifyInfo("Account unlocked" as TranslatedString); - } catch (e) { - if (e instanceof UnwrapKeyError) { - notifyError( - "Could not unlock account" as any, - e.message as any, - ); - } else { - throw e; - } - } - }} - > - <div class="mb-4"> - <Form.InputLine - label={"Password" as TranslatedString} - name="password" - type="password" - required - /> - </div> - - <div class="mt-8"> - <button - type="submit" - class="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" - > - Unlock - </button> - </div> - </Form.Provider> - </div> - <button - type="button" - onClick={() => { - onRemoveAccount(); - }} - class="m-4 block rounded-md bg-red-600 px-3 py-2 text-center text-sm text-white shadow-sm hover:bg-red-500 " - > - Remove account - </button> - </div> - </div> - ); -} diff --git a/packages/exchange-backoffice-ui/src/pages/Welcome.tsx b/packages/exchange-backoffice-ui/src/pages/Welcome.tsx deleted file mode 100644 index 433fbcf59..000000000 --- a/packages/exchange-backoffice-ui/src/pages/Welcome.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { h } from "preact"; - -export function Welcome({ name, asd }: { asd?: string; name?: string }) { - return ( - <div> - {asd} Hello {name} - </div> - ); -} |
