/* 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 { KnownBankAccountsInfo, PaytoUriBitcoin, PaytoUriIBAN, PaytoUriTalerBank, } from "@gnu-taler/taler-util"; import { styled } from "@linaria/react"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { ErrorMessage } from "../../components/ErrorMessage.js"; import { LoadingError } from "../../components/LoadingError.js"; import { SelectList } from "../../components/SelectList.js"; import { Input, LightText, SubTitle, SvgIcon, WarningText, } from "../../components/styled/index.js"; import { useTranslationContext } from "../../context/translation.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.svg"; import warningIcon from "../../svg/warning_24px.svg"; import deleteIcon from "../../svg/delete_24px.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 LoadingUriView({ error }: State.LoadingUriError): VNode { const { i18n } = useTranslationContext(); return ( Could not load} error={error} /> ); } 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 && ( Unable add this account} description={error} /> )}

Select account type} list={accountType.list} name="accountType" value={accountType.value} onChange={accountType.onChange} />

{accountType.value === "" ? undefined : (

)}
{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 ( { setValue(v); if (!errors) { field.onInput(`payto://bitcoin/${v}`); } }} /> {value !== undefined && errors?.value && ( {errors?.value}} /> )} ); } function undefinedIfEmpty(obj: T): T | undefined { return Object.keys(obj).some((k) => (obj as any)[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 ( { setHost(v); if (!errors) { field.onInput(`payto://x-taler-bank/${v}/${account}`); } }} />{" "} {host !== undefined && errors?.host && ( {errors?.host}} /> )} { setAccount(v || ""); if (!errors) { field.onInput(`payto://x-taler-bank/${host}/${v}`); } }} />{" "} {account !== undefined && errors?.account && ( {errors?.account}} /> )} ); } function IbanAddressAccount({ field }: { field: TextFieldHandler }): VNode { const { i18n } = useTranslationContext(); const [number, setNumber] = useState(undefined); const [name, setName] = useState(undefined); const errors = undefinedIfEmpty({ number: !number ? i18n.str`Can't be empty` : undefined, name: !name ? i18n.str`Can't be empty` : undefined, }); return ( { setNumber(v); if (!errors) { field.onInput(`payto://iban/${v}?receiver-name=${name}`); } }} /> {number !== undefined && errors?.number && ( {errors?.number}} /> )} { setName(v); if (!errors) { field.onInput(`payto://iban/${number}?receiver-name=${v}`); } }} /> {name !== undefined && errors?.name && ( {errors?.name}} /> )} ); } function CustomFieldByAccountType({ type, field, }: { type: AccountType; field: TextFieldHandler; }): VNode { const { i18n } = useTranslationContext(); const AccountForm = formComponentByAccountType[type]; return (
We can not validate the account so make sure the value is correct.
); }
Alias Int. Account Number Account name KYC
{account.alias} {p.targetPath} {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 ? ( ) : ( )}