diff options
Diffstat (limited to 'packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx')
-rw-r--r-- | packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx | 118 |
1 files changed, 84 insertions, 34 deletions
diff --git a/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx b/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx index 32545c89a..a0c15c77c 100644 --- a/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx +++ b/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx @@ -1,6 +1,6 @@ /* This file is part of GNU Taler - (C) 2021-2023 Taler Systems S.A. + (C) 2021-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 @@ -18,7 +18,11 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { parsePaytoUri, PaytoUriGeneric, stringifyPaytoUri } from "@gnu-taler/taler-util"; +import { + parsePaytoUri, + PaytoUriGeneric, + stringifyPaytoUri, +} from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, h, VNode } from "preact"; import { COUNTRY_TABLE } from "../../utils/constants.js"; @@ -71,7 +75,7 @@ function checkAddressChecksum(address: string) { return true; } -function validateBitcoin( +function validateBitcoin_path1( addr: string, i18n: ReturnType<typeof useTranslationContext>["i18n"], ): string | undefined { @@ -84,7 +88,7 @@ function validateBitcoin( return i18n.str`This is not a valid bitcoin address.`; } -function validateEthereum( +function validateEthereum_path1( addr: string, i18n: ReturnType<typeof useTranslationContext>["i18n"], ): string | undefined { @@ -98,6 +102,29 @@ function validateEthereum( } /** + * validates + * bank.com/ + * bank.com + * bank.com/path + * bank.com/path/subpath/ + */ +const DOMAIN_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+(\/[a-zA-Z0-9-.]+)*\/?$/ + +function validateTalerBank_path1( + addr: string, + i18n: ReturnType<typeof useTranslationContext>["i18n"], +): string | undefined { + console.log(addr, DOMAIN_REGEX.test(addr)) + try { + const valid = DOMAIN_REGEX.test(addr); + if (valid) return undefined; + } catch (e) { + console.log(e); + } + return i18n.str`This is not a valid host.`; +} + +/** * An IBAN is validated by converting it into an integer and performing a * basic mod-97 operation (as described in ISO 7064) on it. * If the IBAN is valid, the remainder equals 1. @@ -111,7 +138,7 @@ function validateEthereum( * If the remainder is 1, the check digit test is passed and the IBAN might be valid. * */ -function validateIBAN( +function validateIBAN_path1( iban: string, i18n: ReturnType<typeof useTranslationContext>["i18n"], ): string | undefined { @@ -178,34 +205,36 @@ export function InputPaytoForm<T>({ }: Props<keyof T>): VNode { const { value: initialValueStr, onChange } = useField<T>(name); - const initialPayto = parsePaytoUri(initialValueStr ?? "") - const paths = !initialPayto ? [] : initialPayto.targetPath.split("/") + const initialPayto = parsePaytoUri(initialValueStr ?? ""); + const paths = !initialPayto ? [] : initialPayto.targetPath.split("/"); const initialPath1 = paths.length >= 1 ? paths[0] : undefined; const initialPath2 = paths.length >= 2 ? paths[1] : undefined; - const initial: Entity = initialPayto === undefined ? defaultTarget : { - target: initialPayto.targetType, - params: initialPayto.params, - path1: initialPath1, - path2: initialPath2, - } - const [value, setValue] = useState<Partial<Entity>>(initial) + const initial: Entity = + initialPayto === undefined + ? defaultTarget + : { + target: initialPayto.targetType, + params: initialPayto.params, + path1: initialPath1, + path2: initialPath2, + }; + const [value, setValue] = useState<Partial<Entity>>(initial); const { i18n } = useTranslationContext(); const errors: FormErrors<Entity> = { - target: - value.target === noTargetValue - ? i18n.str`required` - : undefined, + target: value.target === noTargetValue ? i18n.str`required` : undefined, path1: !value.path1 ? i18n.str`required` : value.target === "iban" - ? validateIBAN(value.path1, i18n) + ? validateIBAN_path1(value.path1, i18n) : value.target === "bitcoin" - ? validateBitcoin(value.path1, i18n) + ? validateBitcoin_path1(value.path1, i18n) : value.target === "ethereum" - ? validateEthereum(value.path1, i18n) - : undefined, + ? validateEthereum_path1(value.path1, i18n) + : value.target === "x-taler-bank" + ? validateTalerBank_path1(value.path1, i18n) + : undefined, path2: value.target === "x-taler-bank" ? !value.path2 @@ -222,22 +251,29 @@ export function InputPaytoForm<T>({ const hasErrors = Object.keys(errors).some( (k) => (errors as any)[k] !== undefined, ); - const str = hasErrors || !value.target ? undefined : stringifyPaytoUri({ - targetType: value.target, - targetPath: value.path2 ? `${value.path1}/${value.path2}` : (value.path1 ?? ""), - params: value.params ?? {} as any, - isKnown: false, - }) + + const path1WithSlash = value.path1 && !value.path1.endsWith("/") ? value.path1 + "/" : value.path1 + const str = + hasErrors || !value.target + ? undefined + : stringifyPaytoUri({ + targetType: value.target, + targetPath: value.path2 + ? `${path1WithSlash}${value.path2}` + : value.path1 ?? "", + params: value.params ?? ({} as any), + isKnown: false, + }); useEffect(() => { - onChange(str as any) - }, [str]) + onChange(str as any); + }, [str]); // const submit = useCallback((): void => { - // // const accounts: MerchantBackend.BankAccounts.AccountAddDetails[] = paytos; + // // const accounts: TalerMerchantApi.AccountAddDetails[] = paytos; // // const alreadyExists = // // accounts.findIndex((x) => x.payto_uri === paytoURL) !== -1; // // if (!alreadyExists) { - // const newValue: MerchantBackend.BankAccounts.AccountAddDetails = { + // const newValue: TalerMerchantApi.AccountAddDetails = { // payto_uri: paytoURL, // }; // if (value.auth) { @@ -365,7 +401,23 @@ export function InputPaytoForm<T>({ name="path1" readonly={readonly} label={i18n.str`Host`} + fromStr={(v) => { + if (v.startsWith("http")) { + try { + const url = new URL(v); + return url.host + url.pathname; + } catch { + return v; + } + } + return v; + }} tooltip={i18n.str`Bank host.`} + help={<Fragment> + <div><i18n.Translate>Without scheme and may include subpath:</i18n.Translate></div> + <div>bank.com/</div> + <div>bank.com/path/subpath/</div> + </Fragment>} /> <Input<Entity> name="path2" @@ -389,9 +441,7 @@ export function InputPaytoForm<T>({ /> </Fragment> )} - </FormProvider> </InputGroup> ); } - |