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:
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