/* 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 */ import { AmountJson, TalerBankConversionApi, TranslatedString } from "@gnu-taler/taler-util"; import { useState } from "preact/hooks"; export type UIField = { value: string | undefined; onUpdate: (s: string) => void; error: TranslatedString | undefined; } type FormHandler = { [k in keyof T]?: T[k] extends string ? UIField : T[k] extends AmountJson ? UIField : FormHandler; } export type FormValues = { [k in keyof T]: T[k] extends string ? (string | undefined) : T[k] extends AmountJson ? (string | undefined) : FormValues; } export type RecursivePartial = { [k in keyof T]?: T[k] extends string ? (string) : T[k] extends AmountJson ? (AmountJson) : RecursivePartial; } export type FormErrors = { [k in keyof T]?: T[k] extends string ? (TranslatedString) : T[k] extends AmountJson ? (TranslatedString) : FormErrors; } export type FormStatus = { status: "ok", result: T, errors: undefined, } | { status: "fail", result: RecursivePartial, errors: FormErrors, } function constructFormHandler(form: FormValues, updateForm: (d: FormValues) => void, errors: FormErrors | undefined): FormHandler { const keys = (Object.keys(form) as Array) const handler = keys.reduce((prev, fieldName) => { const currentValue: any = form[fieldName]; const currentError: any = errors ? errors[fieldName] : undefined; function updater(newValue: any) { updateForm({ ...form, [fieldName]: newValue }) } if (typeof currentValue === "object") { const group = constructFormHandler(currentValue, updater, currentError) // @ts-expect-error asdasd prev[fieldName] = group return prev; } const field: UIField = { error: currentError, value: currentValue, onUpdate: updater } // @ts-expect-error asdasd prev[fieldName] = field return prev }, {} as FormHandler) return handler; } export function useFormState(defaultValue: FormValues, check: (f: FormValues) => FormStatus): [FormHandler, FormStatus] { const [form, updateForm] = useState>(defaultValue) const status = check(form) const handler = constructFormHandler(form, updateForm, status.errors) return [handler, status] }