/* This file is part of GNU Taler (C) 2022 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 { buildPayto, KnownBankAccountsInfo, PaytoUriBitcoin, PaytoUriIBAN, PaytoUriTalerBank, stringifyPaytoUri, validateIban, } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { styled } from "@linaria/react"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { ErrorMessage } from "../../components/ErrorMessage.js"; import { SubTitle, SvgIcon } from "../../components/styled/index.js"; import { Button } from "../../mui/Button.js"; import { TextFieldHandler } from "../../mui/handlers.js"; import { TextField } from "../../mui/TextField.js"; import checkIcon from "../../svg/check_24px.inline.svg"; import deleteIcon from "../../svg/delete_24px.inline.svg"; import warningIcon from "../../svg/warning_24px.inline.svg"; import { State } from "./index.js"; type AccountType = "bitcoin" | "x-taler-bank" | "iban"; type ComponentFormByAccountType = { [type in AccountType]: (props: { field: TextFieldHandler }) => VNode; }; type ComponentListByAccountType = { [type in AccountType]: (props: { list: KnownBankAccountsInfo[]; onDelete: (a: KnownBankAccountsInfo) => Promise; }) => VNode; }; const formComponentByAccountType: ComponentFormByAccountType = { iban: IbanAddressAccount, bitcoin: BitcoinAddressAccount, "x-taler-bank": TalerBankAddressAccount, }; const tableComponentByAccountType: ComponentListByAccountType = { iban: IbanTable, bitcoin: BitcoinTable, "x-taler-bank": TalerBankTable, }; const AccountTable = styled.table` width: 100%; border-collapse: separate; border-spacing: 0px 10px; tbody tr:nth-child(odd) > td:not(.actions, .kyc) { background-color: lightgrey; } .actions, .kyc { width: 10px; background-color: inherit; } `; export function ReadyView({ currency, error, accountType, accountByType, alias, onAccountAdded, deleteAccount, onCancel, uri, }: State.Ready): VNode { const { i18n } = useTranslationContext(); return (
Known accounts for {currency}

To add a new account first select the account type.

{error && ( )}
{Object.entries(accountType.list).map(([key, name], idx) => (
{ if (accountType.onChange) { accountType.onChange(key); } }} > {name}
))}
--- {uri.value} ---

{Object.entries(accountByType).map(([type, list]) => { const Table = tableComponentByAccountType[type as AccountType]; return ; })} ); } function IbanTable({ list, onDelete, }: { list: KnownBankAccountsInfo[]; onDelete: (ac: KnownBankAccountsInfo) => void; }): VNode { const { i18n } = useTranslationContext(); if (list.length === 0) return ; return (

IBAN accounts

{list.map((account) => { const p = account.uri as PaytoUriIBAN; return ( ); })} ); } function TalerBankTable({ list, onDelete, }: { list: KnownBankAccountsInfo[]; onDelete: (ac: KnownBankAccountsInfo) => void; }): VNode { const { i18n } = useTranslationContext(); if (list.length === 0) return ; return (

Taler accounts

{list.map((account) => { const p = account.uri as PaytoUriTalerBank; return ( ); })} ); } function BitcoinTable({ list, onDelete, }: { list: KnownBankAccountsInfo[]; onDelete: (ac: KnownBankAccountsInfo) => void; }): VNode { const { i18n } = useTranslationContext(); if (list.length === 0) return ; return (

Bitcoin accounts

{list.map((account) => { const p = account.uri as PaytoUriBitcoin; return ( ); })} ); } function BitcoinAddressAccount({ field }: { field: TextFieldHandler }): VNode { const { i18n } = useTranslationContext(); const [value, setValue] = useState(undefined); const errors = undefinedIfEmpty({ value: !value ? i18n.str`Can't be empty` : undefined, }); return (

Bitcoin Account

{ setValue(v); if (!errors && field.onInput) { const p = buildPayto("bitcoin", v, undefined); field.onInput(stringifyPaytoUri(p)); } }} />
); } function undefinedIfEmpty(obj: T): T | undefined { return Object.keys(obj).some((k) => (obj as Record)[k] !== undefined) ? obj : undefined; } function TalerBankAddressAccount({ field, }: { field: TextFieldHandler; }): VNode { const { i18n } = useTranslationContext(); const [host, setHost] = useState(undefined); const [account, setAccount] = useState(undefined); const errors = undefinedIfEmpty({ host: !host ? i18n.str`Can't be empty` : undefined, account: !account ? i18n.str`Can't be empty` : undefined, }); return (

Taler Bank

{ setHost(v); if (!errors && field.onInput && account) { const p = buildPayto("x-taler-bank", v, account); field.onInput(stringifyPaytoUri(p)); } }} /> { setAccount(v || ""); if (!errors && field.onInput && host) { const p = buildPayto("x-taler-bank", host, v); field.onInput(stringifyPaytoUri(p)); } }} />
); } //Taken from libeufin and libeufin took it from the ISO20022 XSD schema // const bicRegex = /^[A-Z]{6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3})?$/; // const ibanRegex = /^[A-Z]{2}[0-9]{2}[a-zA-Z0-9]{1,30}$/; function IbanAddressAccount({ field }: { field: TextFieldHandler }): VNode { const { i18n } = useTranslationContext(); // const [bic, setBic] = useState(undefined); const [iban, setIban] = useState(undefined); const [name, setName] = useState(undefined); const bic = "" const errorsFN = (iban:string | undefined, name: string | undefined) => undefinedIfEmpty({ // bic: !bic // ? undefined // : !bicRegex.test(bic) // ? i18n.str`Invalid bic` // : undefined, iban: !iban ? i18n.str`Can't be empty` : validateIban(iban).type === "invalid" ? i18n.str`Invalid iban` : undefined, name: !name ? i18n.str`Can't be empty` : undefined, }); const errors = errorsFN(iban, name) function sendUpdateIfNoErrors( bic: string | undefined, iban: string, name: string, ): void { if (!field.onInput) return; if (!errorsFN(iban, name)) { const p = buildPayto("iban", iban, bic); p.params["receiver-name"] = name; field.onInput(stringifyPaytoUri(p)); } else { field.onInput("") } } return (

International Bank Account Number

{/*

{ setBic(v); sendUpdateIfNoErrors(v, iban || "", name || ""); }} />

*/}

{ setIban(v); sendUpdateIfNoErrors(bic, v, name || ""); }} />

{ setName(v); sendUpdateIfNoErrors(bic, iban || "", v); }} />

); } function CustomFieldByAccountType({ type, field, }: { type: AccountType; field: TextFieldHandler; }): VNode { // const { i18n } = useTranslationContext(); const AccountForm = formComponentByAccountType[type]; return (
); }
Alias Bank Id Int. Account Number Account name KYC
{account.alias} {p.bic} {p.iban} {p.params["receiver-name"]} {account.kyc_completed ? ( ) : ( )}
Alias Host Account KYC
{account.alias} {p.host} {p.account} {account.kyc_completed ? ( ) : ( )}
Alias Address KYC
{account.alias} {p.targetPath} {account.kyc_completed ? ( ) : ( )}