diff --git a/packages/wallet-webui/src/screens/BankAccountsScreen.tsx b/packages/wallet-webui/src/screens/BankAccountsScreen.tsx index 051179b24..923aa87d1 100644 --- a/packages/wallet-webui/src/screens/BankAccountsScreen.tsx +++ b/packages/wallet-webui/src/screens/BankAccountsScreen.tsx @@ -1,4 +1,5 @@ import { useEffect, useMemo, useRef, useState } from "preact/hooks"; +import { Paytos, PaytoType, Result } from "@gnu-taler/taler-util"; import { Button } from "../ui/Button.js"; import { Card } from "../ui/Card.js"; import { ErrorCard } from "../ui/ErrorCard.js"; @@ -47,6 +48,79 @@ function supportedMethod( return value === "iban" || value === "x-taler-bank" || value === "bitcoin"; } +interface BankAccountFields { + method: GuidedMethod; + receiverName: string; + receiverTown: string; + receiverPostalCode: string; + accountField: string; + bankHost: string; + bankAccount: string; + bitcoinAddress: string; +} + +/** + * The form fields for a saved account, so that editing uses the same guided + * form as adding; a URI that the guided methods cannot represent stays raw. + */ +function bankAccountFields( + account: BankAccountView | undefined, + guidedMethods: GuidedMethod[], + wireTypes: BankAccountWireTypeView[] | undefined, +): BankAccountFields { + const fields: BankAccountFields = { + method: account ? "advanced" : (guidedMethods[0] ?? "advanced"), + receiverName: "", + receiverTown: "", + receiverPostalCode: "", + accountField: "", + bankHost: "", + bankAccount: "", + bitcoinAddress: "", + }; + if (!account) return fields; + const parsed = Paytos.fromString(account.paytoUri); + if (Result.isError(parsed)) return fields; + const payto = parsed.value; + const holder = Paytos.getAccountHolder(payto) ?? ""; + switch (payto.targetType) { + case PaytoType.IBAN: + if (!guidedMethods.includes("iban") || !holder) return fields; + return { + ...fields, + method: "iban", + receiverName: holder, + accountField: payto.iban, + receiverTown: payto.params["receiver-town"] ?? "", + receiverPostalCode: payto.params["receiver-postal-code"] ?? "", + }; + case PaytoType.TalerBank: { + const hosts = + wireTypes?.find((entry) => entry.paymentTargetType === "x-taler-bank") + ?.talerBankHostnames ?? []; + // the bank field is a choice among these hosts when there are any + if ( + !guidedMethods.includes("x-taler-bank") || + !holder || + (hosts.length > 0 && !hosts.includes(payto.host)) + ) + return fields; + return { + ...fields, + method: "x-taler-bank", + receiverName: holder, + bankHost: payto.host, + bankAccount: payto.account, + }; + } + case PaytoType.Bitcoin: + if (!guidedMethods.includes("bitcoin")) return fields; + return { ...fields, method: "bitcoin", bitcoinAddress: payto.address }; + default: + return fields; + } +} + export function BankAccountsScreen(props: { accounts?: BankAccountView[]; wireTypes?: BankAccountWireTypeView[]; @@ -112,8 +186,20 @@ export function BankAccountsScreen(props: { setLabel(props.editing?.label ?? ""); setCurrencies(props.editing?.currencies.join(", ") ?? ""); setPaytoUri(props.editing?.paytoUri ?? ""); - setMethod(props.editing ? "advanced" : (guidedMethods[0] ?? "advanced")); - }, [guidedMethods, props.editing]); + const fields = bankAccountFields( + props.editing, + guidedMethods, + props.wireTypes, + ); + setMethod(fields.method); + setReceiverName(fields.receiverName); + setReceiverTown(fields.receiverTown); + setReceiverPostalCode(fields.receiverPostalCode); + setAccountField(fields.accountField); + setBankHost(fields.bankHost); + setBankAccount(fields.bankAccount); + setBitcoinAddress(fields.bitcoinAddress); + }, [guidedMethods, props.editing, props.wireTypes]); const wireType = props.wireTypes?.find( (entry) => entry.paymentTargetType === method, );