taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 56e40d8face45fb13a2c8e2b0d11c1ba47856bf3
parent e2a7155e272d9e9284dee4415efb43094fd6940a
Author: Florian Dold <florian@dold.me>
Date:   Fri, 21 Mar 2025 17:51:54 +0100

forms: cleanup, fix type error

Diffstat:
Mpackages/aml-backoffice-ui/src/pages/Cases.tsx | 21++++++++++-----------
Mpackages/aml-backoffice-ui/src/pages/decision/Information.tsx | 8+++++---
Mpackages/web-util/src/forms/FormProvider.tsx | 88+++++++++++++++++++++++++++++++------------------------------------------------
Mpackages/web-util/src/hooks/useForm.ts | 9+++------
4 files changed, 52 insertions(+), 74 deletions(-)

diff --git a/packages/aml-backoffice-ui/src/pages/Cases.tsx b/packages/aml-backoffice-ui/src/pages/Cases.tsx @@ -351,7 +351,6 @@ function JumpByIdForm({ const [account, setAccount] = useState<string>(""); return ( <form class="mt-5 grid grid-cols-1"> - <div class="flex flex-row"> <div class="w-full sm:max-w-xs"> <input @@ -384,16 +383,16 @@ function JumpByIdForm({ </a> </div> <div class="mt-2 cursor-default"> - - <InputToggle<any, string> - threeState - name="inv" - label={i18n.str`Only investigated`} - handler={{ - onChange: onTog, - value: fitered, - }} - /> + <InputToggle<any, string> + threeState + name="inv" + label={i18n.str`Only investigated`} + handler={{ + onChange: onTog, + value: fitered, + computedProperties: {}, + }} + /> </div> </form> ); diff --git a/packages/aml-backoffice-ui/src/pages/decision/Information.tsx b/packages/aml-backoffice-ui/src/pages/decision/Information.tsx @@ -8,6 +8,7 @@ import { InternationalizationAPI, onComponentUnload, TalerFormAttributes, + UIFieldHandler, UIHandlerId, useForm, useTranslationContext, @@ -76,9 +77,10 @@ function FillCustomerData({ const [expiration, setExpiration] = useState( request.attributes?.expiration ?? defaultExp, ); - const expirationHandler = { + const expirationHandler: UIFieldHandler<any> = { onChange: setExpiration, value: expiration, + computedProperties: {}, }; /** @@ -223,6 +225,6 @@ function findLatestVersionOfFormWithId( ): FormMetadata | undefined { const found = forms.filter((v) => v.id === formId); if (!found.length) return undefined; - if (found.length === 1) return found[0] - return found.sort((a,b) => b.version - a.version)[0] + if (found.length === 1) return found[0]; + return found.sort((a, b) => b.version - a.version)[0]; } diff --git a/packages/web-util/src/forms/FormProvider.tsx b/packages/web-util/src/forms/FormProvider.tsx @@ -1,59 +1,43 @@ import { TranslatedString } from "@gnu-taler/taler-util"; -import { ComponentChildren, VNode, createContext } from "preact"; -import { MutableRef } from "preact/hooks"; - -export interface FormType<T extends object> { - value: MutableRef<Partial<T>>; - initial?: Partial<T>; - readOnly?: boolean; - onUpdate?: (v: Partial<T>) => void; - // computeFormState?: (v: Partial<T>) => FormState<T>; -} - -export const FormContext = createContext<FormType<any> | undefined>(undefined); - -/** - * Map of {[field]:FieldUIOptions} - * for every field of type - * - any native (string, number, etc...) - * - absoluteTime - * - amountJson - * - * except for: - * - object => recurse into - * - array => behavior result and element field - */ -// export type FormState<T extends object | undefined> = { -// [field in keyof T]?: T[field] extends AbsoluteTime -// ? FieldUIOptions -// : T[field] extends AmountJson -// ? FieldUIOptions -// : T[field] extends Array<infer P extends object> -// ? InputArrayFieldState<P> -// : T[field] extends object | undefined -// ? FormState<T[field]> -// : FieldUIOptions; -// }; +import { ComponentChildren, VNode } from "preact"; /** - * properties only to be defined on design time + * Properties for form elements set at design type. */ export interface UIFormProps<T extends object, K extends keyof T> { - // property name of the object + /** + * Form file name. + */ name: K; - /* instruction to be shown in the field */ + /** + * instruction to be shown in the field + */ placeholder?: TranslatedString; - /* long text help to be shown on demand */ + + /** + * long text help to be shown on demand + */ tooltip?: TranslatedString; - /* short text to be shown next to the field*/ + /** + * Short text to be shown next to the field + */ help?: TranslatedString; - /* should show as disabled and readonly */ + + /** + * should show as disabled and readonly + */ disabled?: boolean; - /* should not show */ + + /** + * should not show + */ hidden?: boolean; - /* should start with focus */ + + /** + * should start with focus + */ focus?: boolean; /** @@ -61,8 +45,11 @@ export interface UIFormProps<T extends object, K extends keyof T> { */ required?: boolean; - // label if the field + /** + * Label of the field. + */ label: TranslatedString; + before?: Addon; after?: Addon; @@ -75,7 +62,6 @@ export interface UIFormProps<T extends object, K extends keyof T> { export type UIFieldHandler<T = any> = { value: T | undefined; onChange: (s: T) => void; - // state: FieldUIOptions; error?: TranslatedString; /** @@ -91,27 +77,21 @@ export interface IconAddon { type: "icon"; icon: VNode; } + export interface ButtonAddon { type: "button"; onClick: () => void; children: ComponentChildren; } + export interface TextAddon { type: "text"; text: TranslatedString; } + export type Addon = IconAddon | ButtonAddon | TextAddon; export interface StringConverter<T> { toStringUI: (v?: T) => string; fromStringUI: (v?: string) => T; } - -// export interface InputArrayFieldState<P extends object> extends FieldUIOptions { -// elements?: FormState<P>[]; -// } - -// export type FormProviderProps<T extends object> = Omit<FormType<T>, "value"> & { -// onSubmit?: (v: Partial<T>, s: FormState<T> | undefined) => void; -// children?: ComponentChildren; -// }; diff --git a/packages/web-util/src/hooks/useForm.ts b/packages/web-util/src/hooks/useForm.ts @@ -62,6 +62,7 @@ export type ErrorAndLabel = { message: TranslatedString; label: TranslatedString; }; + export type FormErrors<T> = { [k in keyof T]?: T[k] extends string ? ErrorAndLabel @@ -93,11 +94,7 @@ export type FormState<T> = { }; /** - * - * @param fields form fields - * @param initialValue initial value - * @param check validation chain - * @returns + * Hook to instantiate a form from its design. */ export function useForm<T>( design: FormDesign<T>, @@ -278,7 +275,7 @@ function constructFormHandler<T>( parentRef: result, computedProperties: { hidden, - } + }, }; // FIXME: handler should not be set but we also need to refactor