aboutsummaryrefslogtreecommitdiff
path: root/packages/aml-backoffice-ui/src/handlers/FormProvider.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/aml-backoffice-ui/src/handlers/FormProvider.tsx')
-rw-r--r--packages/aml-backoffice-ui/src/handlers/FormProvider.tsx99
1 files changed, 99 insertions, 0 deletions
diff --git a/packages/aml-backoffice-ui/src/handlers/FormProvider.tsx b/packages/aml-backoffice-ui/src/handlers/FormProvider.tsx
new file mode 100644
index 000000000..a195c2051
--- /dev/null
+++ b/packages/aml-backoffice-ui/src/handlers/FormProvider.tsx
@@ -0,0 +1,99 @@
+import {
+ AbsoluteTime,
+ AmountJson,
+ TranslatedString,
+} from "@gnu-taler/taler-util";
+import { ComponentChildren, VNode, createContext, h } from "preact";
+import {
+ MutableRef,
+ StateUpdater,
+ useEffect,
+ useRef,
+ useState,
+} from "preact/hooks";
+
+export interface FormType<T> {
+ value: MutableRef<Partial<T>>;
+ initialValue?: Partial<T>;
+ onUpdate?: StateUpdater<T>;
+ computeFormState?: (v: T) => FormState<T>;
+}
+
+//@ts-ignore
+export const FormContext = createContext<FormType<any>>({});
+
+export type FormState<T> = {
+ [field in keyof T]?: T[field] extends AbsoluteTime
+ ? Partial<InputFieldState>
+ : T[field] extends AmountJson
+ ? Partial<InputFieldState>
+ : T[field] extends Array<infer P>
+ ? Partial<InputArrayFieldState<P>>
+ : T[field] extends object
+ ? FormState<T[field]>
+ : Partial<InputFieldState>;
+};
+
+export interface InputFieldState {
+ /* should show the error */
+ error?: TranslatedString;
+ /* should not allow to edit */
+ readonly: boolean;
+ /* should show as disable */
+ disabled: boolean;
+ /* should not show */
+ hidden: boolean;
+}
+
+export interface InputArrayFieldState<T> extends InputFieldState {
+ elements: FormState<T>[];
+}
+
+export function FormProvider<T>({
+ children,
+ initialValue,
+ onUpdate: notify,
+ onSubmit,
+ computeFormState,
+}: {
+ initialValue?: Partial<T>;
+ onUpdate?: (v: Partial<T>) => void;
+ onSubmit?: (v: Partial<T>, s: FormState<T> | undefined) => void;
+ computeFormState?: (v: Partial<T>) => FormState<T>;
+ children: ComponentChildren;
+}): VNode {
+ // const value = useRef(initialValue ?? {});
+ // useEffect(() => {
+ // return function onUnload() {
+ // value.current = initialValue ?? {};
+ // };
+ // });
+ // const onUpdate = notify
+ const [state, setState] = useState<Partial<T>>(initialValue ?? {});
+ const value = { current: state };
+ // console.log("RENDER", initialValue, value);
+ const onUpdate = (v: typeof state) => {
+ // console.log("updated");
+ setState(v);
+ if (notify) notify(v);
+ };
+ return (
+ <FormContext.Provider
+ value={{ initialValue, value, onUpdate, computeFormState }}
+ >
+ <form
+ onSubmit={(e) => {
+ e.preventDefault();
+ //@ts-ignore
+ if (onSubmit)
+ onSubmit(
+ value.current,
+ !computeFormState ? undefined : computeFormState(value.current),
+ );
+ }}
+ >
+ {children}
+ </form>
+ </FormContext.Provider>
+ );
+}