From fa4c7039f4ebeb6ad3cf19237ad7b138519ac142 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 2 May 2024 09:57:49 -0300 Subject: removing compiled form ts --- packages/aml-backoffice-ui/src/App.tsx | 5 +- packages/aml-backoffice-ui/src/forms.ts | 24 --- packages/aml-backoffice-ui/src/forms/index.ts | 4 +- packages/aml-backoffice-ui/src/forms/simplest.ts | 4 +- packages/aml-backoffice-ui/src/hooks/form.ts | 12 +- .../aml-backoffice-ui/src/pages/CaseDetails.tsx | 5 +- .../aml-backoffice-ui/src/pages/CaseUpdate.tsx | 169 +++++++++++++++++++-- 7 files changed, 174 insertions(+), 49 deletions(-) delete mode 100644 packages/aml-backoffice-ui/src/forms.ts (limited to 'packages/aml-backoffice-ui/src') diff --git a/packages/aml-backoffice-ui/src/App.tsx b/packages/aml-backoffice-ui/src/App.tsx index 9ccf21755..ae8b574b6 100644 --- a/packages/aml-backoffice-ui/src/App.tsx +++ b/packages/aml-backoffice-ui/src/App.tsx @@ -29,15 +29,18 @@ import { UiSettingsProvider } from "./context/ui-settings.js"; import { strings } from "./i18n/strings.js"; import "./scss/main.css"; import { UiSettings, fetchUiSettings } from "./context/ui-settings.js"; +import { UiForms, fetchUiForms } from "./context/ui-forms.js"; const WITH_LOCAL_STORAGE_CACHE = false; export function App(): VNode { const [settings, setSettings] = useState(); + const [forms, setForms] = useState(); useEffect(() => { fetchUiSettings(setSettings); + fetchUiForms(setForms); }, []); - if (!settings) return ; + if (!settings || !forms) return ; const baseUrl = getInitialBackendBaseURL(settings.backendBaseURL); return ( diff --git a/packages/aml-backoffice-ui/src/forms.ts b/packages/aml-backoffice-ui/src/forms.ts deleted file mode 100644 index 3ecec2bb0..000000000 --- a/packages/aml-backoffice-ui/src/forms.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022-2024 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see - */ - -export * from "./forms/index.js"; - -/** - * this file is here to have a flat dist folder - * - * this file is being build in a bundle separated - * from the main one. - */ diff --git a/packages/aml-backoffice-ui/src/forms/index.ts b/packages/aml-backoffice-ui/src/forms/index.ts index b32978c29..abeebfc6a 100644 --- a/packages/aml-backoffice-ui/src/forms/index.ts +++ b/packages/aml-backoffice-ui/src/forms/index.ts @@ -129,10 +129,10 @@ const languages = (i18n: InternationalizationAPI) => [ ]; -const forms: (i18n: InternationalizationAPI) => Array = (i18n) => [ +export const preloadedForms: (i18n: InternationalizationAPI) => Array = (i18n) => [ { label: i18n.str`Simple comment`, - id: "simple_comment", + id: "__simple_comment", version: 1, config: simplest(i18n), // }, { diff --git a/packages/aml-backoffice-ui/src/forms/simplest.ts b/packages/aml-backoffice-ui/src/forms/simplest.ts index d32c759cb..c7ba95462 100644 --- a/packages/aml-backoffice-ui/src/forms/simplest.ts +++ b/packages/aml-backoffice-ui/src/forms/simplest.ts @@ -17,7 +17,7 @@ import type { InternationalizationAPI } from "@gnu-taler/web-util/browser"; -import { BaseForm, DoubleColumnForm, DoubleColumnFormSection, UIHandlerId } from "../context/ui-forms.js"; +import { DoubleColumnForm, DoubleColumnFormSection, UIHandlerId } from "../context/ui-forms.js"; export const v1 = (i18n: InternationalizationAPI): DoubleColumnForm => ({ type: "double-column" as const, @@ -84,7 +84,7 @@ export function resolutionSection( type: "amount", properties: { id: ".threshold" as UIHandlerId, - currency: "USD", + currency: "NETZBON", name: "threshold", label: i18n.str`New threshold`, }, diff --git a/packages/aml-backoffice-ui/src/hooks/form.ts b/packages/aml-backoffice-ui/src/hooks/form.ts index e14e29819..edeae6085 100644 --- a/packages/aml-backoffice-ui/src/hooks/form.ts +++ b/packages/aml-backoffice-ui/src/hooks/form.ts @@ -19,8 +19,8 @@ import { TalerExchangeApi, TranslatedString, } from "@gnu-taler/taler-util"; +import { UIFieldHandler } from "@gnu-taler/web-util/browser"; import { useState } from "preact/hooks"; -import { UIField } from "@gnu-taler/web-util/browser"; // export type UIField = { // value: string | undefined; @@ -28,13 +28,13 @@ import { UIField } from "@gnu-taler/web-util/browser"; // error: TranslatedString | undefined; // }; -type FormHandler = { +export type FormHandler = { [k in keyof T]?: T[k] extends string - ? UIField + ? UIFieldHandler : T[k] extends AmountJson - ? UIField + ? UIFieldHandler : T[k] extends TalerExchangeApi.AmlState - ? UIField + ? UIFieldHandler : FormHandler; }; @@ -100,7 +100,7 @@ function constructFormHandler( return prev; } - const field: UIField = { + const field: UIFieldHandler = { // @ts-expect-error FIXME better typing error: currentError, // @ts-expect-error FIXME better typing diff --git a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx index 1ad8c9453..62c54d222 100644 --- a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx +++ b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx @@ -34,18 +34,17 @@ import { import { DefaultForm, ErrorLoading, - FlexibleForm, InternationalizationAPI, Loading, - useTranslationContext, + useTranslationContext } from "@gnu-taler/web-util/browser"; import { format } from "date-fns"; import { VNode, h } from "preact"; import { useState } from "preact/hooks"; import { privatePages } from "../Routing.js"; +import { FormMetadata, useUiFormsContext } from "../context/ui-forms.js"; import { useCaseDetails } from "../hooks/useCaseDetails.js"; import { ShowConsolidated } from "./ShowConsolidated.js"; -import { FormMetadata, useUiFormsContext } from "../context/ui-forms.js"; export type AmlEvent = | AmlFormEvent diff --git a/packages/aml-backoffice-ui/src/pages/CaseUpdate.tsx b/packages/aml-backoffice-ui/src/pages/CaseUpdate.tsx index 64bfb90f1..f04d404d0 100644 --- a/packages/aml-backoffice-ui/src/pages/CaseUpdate.tsx +++ b/packages/aml-backoffice-ui/src/pages/CaseUpdate.tsx @@ -20,12 +20,14 @@ import { HttpStatusCode, TalerExchangeApi, TalerProtocolTimestamp, - assertUnreachable, + assertUnreachable } from "@gnu-taler/taler-util"; import { Button, + InternationalizationAPI, LocalNotificationBanner, RenderAllFieldsByUiConfig, + UIFieldHandler, UIFormField, useExchangeApiContext, useLocalNotificationHandler, @@ -33,12 +35,40 @@ import { } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { privatePages } from "../Routing.js"; -import { UIFormFieldConfig, useUiFormsContext } from "../context/ui-forms.js"; -import { useFormState } from "../hooks/form.js"; +import { + FormMetadata, + UIFormFieldConfig, + useUiFormsContext, +} from "../context/ui-forms.js"; +import { preloadedForms } from "../forms/index.js"; +import { FormHandler, useFormState } from "../hooks/form.js"; import { useOfficer } from "../hooks/officer.js"; import { Justification } from "./CaseDetails.js"; import { HandleAccountNotReady } from "./HandleAccountNotReady.js"; +function searchForm( + i18n: InternationalizationAPI, + forms: FormMetadata[], + formId: string, +): FormMetadata | undefined { + { + const found = forms.find((v) => v.id === formId); + if (found) return found; + } + { + const pf = preloadedForms(i18n); + const found = pf.find((v) => v.id === formId); + if (found) return found; + } + return undefined; +} + +type FormType = { + when: AbsoluteTime; + state: TalerExchangeApi.AmlState; + threshold: AmountJson; +}; + export function CaseUpdate({ account, type: formId, @@ -52,11 +82,10 @@ export function CaseUpdate({ lib: { exchange: api }, } = useExchangeApiContext(); - // const [notification, notify, handleError] = useLocalNotification(); const [notification, withErrorHandler] = useLocalNotificationHandler(); const { config } = useExchangeApiContext(); const { forms } = useUiFormsContext(); - const initial = { + const initial: FormType = { when: AbsoluteTime.now(), state: TalerExchangeApi.AmlState.pending, threshold: Amounts.zeroOfCurrency(config.currency), @@ -65,19 +94,31 @@ export function CaseUpdate({ if (officer.state !== "ready") { return ; } - const theForm = forms.find((v) => v.id === formId); + const theForm = searchForm(i18n, forms, formId); if (!theForm) { return
form with id {formId} not found
; } - const [form, state] = useFormState(initial, (st) => { + let defaultValue = initial + theForm.config.design.forEach((section) => { + section.fields.forEach((field) => { + if ("id" in field.properties) { + const path = field.properties.id.split("."); + defaultValue = setValueDeeper(defaultValue, path, undefined); + } + }); + }); + + + const [form, state] = useFormState(defaultValue, (st) => { return { status: "ok", result: st as any, errors: undefined, }; }); - + + console.log("FORM", form) const validatedForm = state.status === "fail" ? undefined : state.result; const submitHandler = @@ -125,8 +166,73 @@ export function CaseUpdate({ }, ); - function convertUiField(_f: UIFormFieldConfig[]): UIFormField[] { - return []; + function convertUiField( + fieldConfig: UIFormFieldConfig[], + form: FormHandler, + ): UIFormField[] { + return fieldConfig.map((config) => { + switch (config.type) { + case "absoluteTime": { + return undefined!; + } + case "amount": { + return { + type: "amount", + properties: { + ...(config.properties as any), + handler: getValueDeeper(form, config.properties.id.split(".")), + }, + } as UIFormField; + } + case "array": { + return undefined!; + } + case "caption": { + return undefined!; + } + case "choiceHorizontal": { + return { + type: "choiceHorizontal", + properties: { + handler: getValueDeeper(form, config.properties.id.split(".")), + choices: config.properties.choices, + }, + } as UIFormField; + } + case "choiceStacked": + case "file": + case "group": + case "integer": + case "selectMultiple": + case "selectOne": { + return undefined!; + } + case "text": { + return { + type: "text", + properties: { + ...(config.properties as any), + handler: getValueDeeper(form, config.properties.id.split(".")), + }, + } as UIFormField; + } + case "textArea": { + return { + type: "text", + properties: { + ...(config.properties as any), + handler: getValueDeeper(form, config.properties.id.split(".")), + }, + } as UIFormField; + } + case "toggle": { + return undefined!; + } + default: { + assertUnreachable(config); + } + } + }); } return ( @@ -155,7 +261,7 @@ export function CaseUpdate({
@@ -185,7 +291,10 @@ export function CaseUpdate({ } export function SelectForm({ account }: { account: string }) { + const { i18n } = useTranslationContext(); const { forms } = useUiFormsContext(); + const pf = preloadedForms(i18n); + return (
New form for account: {account.substring(0, 16)}...
@@ -200,6 +309,44 @@ export function SelectForm({ account }: { account: string }) { ); })} + {pf.map((form) => { + return ( + + {form.label} + + ); + })}
); } + +function getValueDeeper( + object: Record, + names: string[], +): UIFieldHandler { + if (names.length === 0) return object as UIFieldHandler; + const [head, ...rest] = names; + if (!head) { + return getValueDeeper(object, rest); + } + if (object === undefined) { + throw Error("handler not found"); + } + return getValueDeeper(object[head], rest); +} + +function setValueDeeper(object: any, names: string[], value: any): any { + if (names.length === 0) return value; + const [head, ...rest] = names; + if (!head) { + return setValueDeeper(object, rest, value); + } + if (object === undefined) { + return { [head]: setValueDeeper({}, rest, value) }; + } + return { ...object, [head]: setValueDeeper(object[head] ?? {}, rest, value) }; +} -- cgit v1.2.3