aboutsummaryrefslogtreecommitdiff
path: root/packages/aml-backoffice-ui/src/hooks/form.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/aml-backoffice-ui/src/hooks/form.ts')
-rw-r--r--packages/aml-backoffice-ui/src/hooks/form.ts89
1 files changed, 68 insertions, 21 deletions
diff --git a/packages/aml-backoffice-ui/src/hooks/form.ts b/packages/aml-backoffice-ui/src/hooks/form.ts
index edeae6085..752444bd2 100644
--- a/packages/aml-backoffice-ui/src/hooks/form.ts
+++ b/packages/aml-backoffice-ui/src/hooks/form.ts
@@ -15,12 +15,14 @@
*/
import {
+ AbsoluteTime,
AmountJson,
TalerExchangeApi,
TranslatedString,
} from "@gnu-taler/taler-util";
import { UIFieldHandler } from "@gnu-taler/web-util/browser";
import { useState } from "preact/hooks";
+import { UIFormFieldConfig, UIHandlerId } from "../context/ui-forms.js";
// export type UIField = {
// value: string | undefined;
@@ -57,6 +59,8 @@ export type FormErrors<T> = {
? TranslatedString
: T[k] extends AmountJson
? TranslatedString
+ : T[k] extends AbsoluteTime
+ ? TranslatedString
: T[k] extends TalerExchangeApi.AmlState
? TranslatedString
: FormErrors<T[k]>;
@@ -75,31 +79,22 @@ export type FormStatus<T> =
};
function constructFormHandler<T>(
+ shape: Array<UIHandlerId>,
form: RecursivePartial<FormValues<T>>,
updateForm: (d: RecursivePartial<FormValues<T>>) => void,
errors: FormErrors<T> | undefined,
): FormHandler<T> {
- const keys = Object.keys(form) as Array<keyof T>;
- const handler = keys.reduce((prev, fieldName) => {
- const currentValue: unknown = form[fieldName];
- const currentError: unknown =
- errors !== undefined ? errors[fieldName] : undefined;
+ const handler = shape.reduce((handleForm, fieldId) => {
+
+ const path = fieldId.split(".")
+
function updater(newValue: unknown) {
- updateForm({ ...form, [fieldName]: newValue });
- }
- /**
- * There is no clear way to know if this object is a custom field
- * or a group of fields
- */
- if (typeof currentValue === "object") {
- // @ts-expect-error FIXME better typing
- const group = constructFormHandler(currentValue, updater, currentError);
- // @ts-expect-error FIXME better typing
- prev[fieldName] = group;
- return prev;
+ updateForm(setValueDeeper(form, path, newValue));
}
+ const currentValue: unknown = getValueDeeper(form, path)
+ const currentError: unknown = errors === undefined ? undefined : getValueDeeper(errors, path)
const field: UIFieldHandler = {
// @ts-expect-error FIXME better typing
error: currentError,
@@ -108,14 +103,37 @@ function constructFormHandler<T>(
onChange: updater,
state: {},
};
- // @ts-expect-error FIXME better typing
- prev[fieldName] = field;
- return prev;
+
+ return setValueDeeper(handleForm, path, field)
+
+ /**
+ * There is no clear way to know if this object is a custom field
+ * or a group of fields
+ */
+ // if (typeof currentValue === "object") {
+ // // @ts-expect-error FIXME better typing
+ // const group = constructFormHandler(currentValue, updater, currentError);
+ // // @ts-expect-error FIXME better typing
+ // prev[fieldName] = group;
+ // return prev;
+ // }
+
+ // const field: UIFieldHandler = {
+ // // @ts-expect-error FIXME better typing
+ // error: currentError,
+ // // @ts-expect-error FIXME better typing
+ // value: currentValue,
+ // onChange: updater,
+ // state: {},
+ // };
+ // handleForm[fieldName] = field;
+ // return handleForm;
}, {} as FormHandler<T>);
return handler;
}
+
/**
* FIXME: Consider sending this to web-utils
*
@@ -125,6 +143,7 @@ function constructFormHandler<T>(
* @returns
*/
export function useFormState<T>(
+ shape: Array<UIHandlerId>,
defaultValue: RecursivePartial<FormValues<T>>,
check: (f: RecursivePartial<FormValues<T>>) => FormStatus<T>,
): [FormHandler<T>, FormStatus<T>] {
@@ -132,7 +151,35 @@ export function useFormState<T>(
useState<RecursivePartial<FormValues<T>>>(defaultValue);
const status = check(form);
- const handler = constructFormHandler(form, updateForm, status.errors);
+ const handler = constructFormHandler(shape, form, updateForm, status.errors);
return [handler, status];
}
+
+
+function getValueDeeper(
+ object: Record<string, any>,
+ 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) };
+}