aboutsummaryrefslogtreecommitdiff
path: root/packages/exchange-backoffice-ui/src/pages
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-06-05 10:04:09 -0300
committerSebastian <sebasjm@gmail.com>2023-06-05 10:04:09 -0300
commitc680f5aa71b08e978444df07f93c381f9d47ab82 (patch)
tree81903fac003bb1e202cf69551e06ba41a6e960a5 /packages/exchange-backoffice-ui/src/pages
parentdf53866e6b148ea5fd2ab57e906a4aa36b535ed3 (diff)
rename aml
Diffstat (limited to 'packages/exchange-backoffice-ui/src/pages')
-rw-r--r--packages/exchange-backoffice-ui/src/pages/AntiMoneyLaunderingForm.tsx90
-rw-r--r--packages/exchange-backoffice-ui/src/pages/CaseDetails.tsx447
-rw-r--r--packages/exchange-backoffice-ui/src/pages/Cases.tsx288
-rw-r--r--packages/exchange-backoffice-ui/src/pages/CreateAccount.tsx102
-rw-r--r--packages/exchange-backoffice-ui/src/pages/HandleAccountNotReady.tsx34
-rw-r--r--packages/exchange-backoffice-ui/src/pages/Home.tsx5
-rw-r--r--packages/exchange-backoffice-ui/src/pages/NewFormEntry.tsx76
-rw-r--r--packages/exchange-backoffice-ui/src/pages/Officer.tsx55
-rw-r--r--packages/exchange-backoffice-ui/src/pages/Settings.tsx5
-rw-r--r--packages/exchange-backoffice-ui/src/pages/UnlockAccount.tsx81
-rw-r--r--packages/exchange-backoffice-ui/src/pages/Welcome.tsx9
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>
- );
-}