import { ComponentChildren, VNode, h } from "preact"; import { ShowInputErrorLabel } from "../../components/ShowInputErrorLabel.js"; import { PartialButDefined, RecursivePartial, WithIntermediate, undefinedIfEmpty, validateIBAN } from "../../utils.js"; import { useEffect, useRef, useState } from "preact/hooks"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { buildPayto, parsePaytoUri } from "@gnu-taler/taler-util"; const IBAN_REGEX = /^[A-Z][A-Z0-9]*$/; const EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; const REGEX_JUST_NUMBERS_REGEX = /^\+[0-9 ]*$/; /** * Create valid account object to update or create * Take template as initial values for the form * Purpose indicate if all field al read only (show), part of them (update) * or none (create) * @param param0 * @returns */ export function AccountForm({ template, purpose, onChange, focus, children, }: { focus?: boolean, children: ComponentChildren, template: SandboxBackend.Circuit.CircuitAccountData | undefined; onChange: (a: SandboxBackend.Circuit.CircuitAccountData | undefined) => void; purpose: "create" | "update" | "show"; }): VNode { const initial = initializeFromTemplate(template); const [form, setForm] = useState(initial); const [errors, setErrors] = useState< RecursivePartial | undefined >(undefined); const { i18n } = useTranslationContext(); const ref = useRef(null); useEffect(() => { if (focus) ref.current?.focus(); }, [focus]); function updateForm(newForm: typeof initial): void { const parsed = !newForm.cashout_address ? undefined : buildPayto("iban", newForm.cashout_address, undefined);; const errors = undefinedIfEmpty>({ cashout_address: !newForm.cashout_address ? i18n.str`required` : !parsed ? i18n.str`does not follow the pattern` : !parsed.isKnown || parsed.targetType !== "iban" ? i18n.str`only "IBAN" target are supported` : !IBAN_REGEX.test(parsed.iban) ? i18n.str`IBAN should have just uppercased letters and numbers` : validateIBAN(parsed.iban, i18n), contact_data: undefinedIfEmpty({ email: !newForm.contact_data?.email ? i18n.str`required` : !EMAIL_REGEX.test(newForm.contact_data.email) ? i18n.str`it should be an email` : undefined, phone: !newForm.contact_data?.phone ? i18n.str`required` : !newForm.contact_data.phone.startsWith("+") ? i18n.str`should start with +` : !REGEX_JUST_NUMBERS_REGEX.test(newForm.contact_data.phone) ? i18n.str`phone number can't have other than numbers` : undefined, }), // iban: !newForm.iban // ? undefined //optional field // : !IBAN_REGEX.test(newForm.iban) // ? i18n.str`IBAN should have just uppercased letters and numbers` // : validateIBAN(newForm.iban, i18n), name: !newForm.name ? i18n.str`required` : undefined, username: !newForm.username ? i18n.str`required` : undefined, }); setErrors(errors); setForm(newForm); onChange(errors === undefined ? (newForm as any) : undefined); } return (
{ e.preventDefault() }} >
{ form.username = e.currentTarget.value; updateForm(structuredClone(form)); }} // placeholder="" autocomplete="off" />

account identification in the bank

{ form.name = e.currentTarget.value; updateForm(structuredClone(form)); }} // placeholder="" autocomplete="off" />

name of the person owner the account

{purpose !== "create" && (

international bank account number

)}
{ form.contact_data.email = e.currentTarget.value; updateForm(structuredClone(form)); }} autocomplete="off" />
{ form.contact_data.phone = e.currentTarget.value; updateForm(structuredClone(form)); }} // placeholder="" autocomplete="off" />
{ form.cashout_address = e.currentTarget.value; updateForm(structuredClone(form)); }} autocomplete="off" />

account number where the money is going to be sent when doing cashouts

{children}
); } function initializeFromTemplate( account: SandboxBackend.Circuit.CircuitAccountData | undefined, ): WithIntermediate { const emptyAccount = { cashout_address: undefined, iban: undefined, name: undefined, username: undefined, contact_data: undefined, }; const emptyContact = { email: undefined, phone: undefined, }; const initial: PartialButDefined = structuredClone(account) ?? emptyAccount; if (typeof initial.contact_data === "undefined") { initial.contact_data = emptyContact; } initial.contact_data.email; return initial as any; }