2022-10-28 18:39:06 +02:00
|
|
|
/*
|
|
|
|
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 <http://www.gnu.org/licenses/>
|
|
|
|
*/
|
|
|
|
|
|
|
|
import {
|
2023-01-17 20:01:04 +01:00
|
|
|
buildPayto,
|
2022-10-28 18:39:06 +02:00
|
|
|
KnownBankAccountsInfo,
|
|
|
|
PaytoUriBitcoin,
|
|
|
|
PaytoUriIBAN,
|
|
|
|
PaytoUriTalerBank,
|
2023-01-17 20:01:04 +01:00
|
|
|
stringifyPaytoUri,
|
2023-04-07 22:31:01 +02:00
|
|
|
validateIban,
|
2022-10-28 18:39:06 +02:00
|
|
|
} from "@gnu-taler/taler-util";
|
|
|
|
import { styled } from "@linaria/react";
|
|
|
|
import { Fragment, h, VNode } from "preact";
|
|
|
|
import { useState } from "preact/hooks";
|
2023-01-09 12:38:48 +01:00
|
|
|
import { ErrorMessage } from "../../components/ErrorMessage.js";
|
2022-10-28 18:39:06 +02:00
|
|
|
import { SelectList } from "../../components/SelectList.js";
|
2023-04-07 22:31:01 +02:00
|
|
|
import { Input, SubTitle, SvgIcon } from "../../components/styled/index.js";
|
2023-05-05 13:47:00 +02:00
|
|
|
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
2022-10-28 18:39:06 +02:00
|
|
|
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 deleteIcon from "../../svg/delete_24px.svg";
|
2023-01-09 12:38:48 +01:00
|
|
|
import warningIcon from "../../svg/warning_24px.svg";
|
2022-10-28 18:39:06 +02:00
|
|
|
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<void>;
|
|
|
|
}) => 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 (
|
|
|
|
<Fragment>
|
|
|
|
<section>
|
|
|
|
<SubTitle>
|
|
|
|
<i18n.Translate>Known accounts for {currency}</i18n.Translate>
|
|
|
|
</SubTitle>
|
|
|
|
<p>
|
|
|
|
<i18n.Translate>
|
|
|
|
To add a new account first select the account type.
|
|
|
|
</i18n.Translate>
|
|
|
|
</p>
|
|
|
|
|
|
|
|
{error && (
|
|
|
|
<ErrorMessage
|
2023-01-09 12:38:48 +01:00
|
|
|
title={i18n.str`Unable add this account`}
|
2022-10-28 18:39:06 +02:00
|
|
|
description={error}
|
|
|
|
/>
|
|
|
|
)}
|
2023-04-07 22:31:01 +02:00
|
|
|
<div style={{ width: "100%", display: "flex" }}>
|
|
|
|
{Object.entries(accountType.list).map(([key, name], idx) => (
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
marginLeft: 8,
|
|
|
|
padding: 8,
|
|
|
|
borderTopLeftRadius: 5,
|
|
|
|
borderTopRightRadius: 5,
|
|
|
|
backgroundColor:
|
|
|
|
accountType.value === key ? "#0042b2" : "unset",
|
|
|
|
color: accountType.value === key ? "white" : "unset",
|
|
|
|
}}
|
|
|
|
onClick={(e) => {
|
|
|
|
if (accountType.onChange) {
|
|
|
|
accountType.onChange(key);
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{name}
|
|
|
|
</div>
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
<div style={{ border: "1px solid gray", padding: 8, borderRadius: 5 }}>
|
|
|
|
<p>
|
|
|
|
<CustomFieldByAccountType
|
|
|
|
type={accountType.value as AccountType}
|
|
|
|
field={uri}
|
2022-10-28 18:39:06 +02:00
|
|
|
/>
|
2023-04-07 22:31:01 +02:00
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<p>
|
|
|
|
<TextField
|
|
|
|
label="Alias"
|
|
|
|
variant="filled"
|
|
|
|
placeholder="Easy to remember description"
|
|
|
|
fullWidth
|
|
|
|
disabled={accountType.value === ""}
|
|
|
|
value={alias.value}
|
|
|
|
onChange={alias.onInput}
|
|
|
|
/>
|
2022-10-28 18:39:06 +02:00
|
|
|
</p>
|
|
|
|
</section>
|
|
|
|
<section>
|
|
|
|
<Button
|
|
|
|
variant="contained"
|
|
|
|
color="secondary"
|
|
|
|
onClick={onCancel.onClick}
|
|
|
|
>
|
|
|
|
<i18n.Translate>Cancel</i18n.Translate>
|
|
|
|
</Button>
|
|
|
|
<Button
|
|
|
|
variant="contained"
|
|
|
|
onClick={onAccountAdded.onClick}
|
|
|
|
disabled={!onAccountAdded.onClick}
|
|
|
|
>
|
|
|
|
<i18n.Translate>Add</i18n.Translate>
|
|
|
|
</Button>
|
|
|
|
</section>
|
|
|
|
<section>
|
|
|
|
{Object.entries(accountByType).map(([type, list]) => {
|
|
|
|
const Table = tableComponentByAccountType[type as AccountType];
|
|
|
|
return <Table key={type} list={list} onDelete={deleteAccount} />;
|
|
|
|
})}
|
|
|
|
</section>
|
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function IbanTable({
|
|
|
|
list,
|
|
|
|
onDelete,
|
|
|
|
}: {
|
|
|
|
list: KnownBankAccountsInfo[];
|
|
|
|
onDelete: (ac: KnownBankAccountsInfo) => void;
|
|
|
|
}): VNode {
|
|
|
|
const { i18n } = useTranslationContext();
|
|
|
|
if (list.length === 0) return <Fragment />;
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<h1>
|
|
|
|
<i18n.Translate>IBAN accounts</i18n.Translate>
|
|
|
|
</h1>
|
|
|
|
<AccountTable>
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th>
|
|
|
|
<i18n.Translate>Alias</i18n.Translate>
|
|
|
|
</th>
|
2022-11-07 23:29:47 +01:00
|
|
|
<th>
|
|
|
|
<i18n.Translate>Bank Id</i18n.Translate>
|
|
|
|
</th>
|
2022-10-28 18:39:06 +02:00
|
|
|
<th>
|
|
|
|
<i18n.Translate>Int. Account Number</i18n.Translate>
|
|
|
|
</th>
|
2022-10-30 01:10:46 +02:00
|
|
|
<th>
|
|
|
|
<i18n.Translate>Account name</i18n.Translate>
|
|
|
|
</th>
|
2022-10-28 18:39:06 +02:00
|
|
|
<th class="kyc">
|
|
|
|
<i18n.Translate>KYC</i18n.Translate>
|
|
|
|
</th>
|
|
|
|
<th class="actions"></th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
|
|
|
{list.map((account) => {
|
|
|
|
const p = account.uri as PaytoUriIBAN;
|
|
|
|
return (
|
|
|
|
<tr key={account.alias}>
|
|
|
|
<td>{account.alias}</td>
|
2022-11-07 23:29:47 +01:00
|
|
|
<td>{p.bic}</td>
|
|
|
|
<td>{p.iban}</td>
|
2022-10-30 01:10:46 +02:00
|
|
|
<td>{p.params["receiver-name"]}</td>
|
2022-10-28 18:39:06 +02:00
|
|
|
<td class="kyc">
|
|
|
|
{account.kyc_completed ? (
|
|
|
|
<SvgIcon
|
|
|
|
title={i18n.str`KYC done`}
|
|
|
|
dangerouslySetInnerHTML={{ __html: checkIcon }}
|
|
|
|
color="green"
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
<SvgIcon
|
|
|
|
title={i18n.str`KYC missing`}
|
|
|
|
dangerouslySetInnerHTML={{ __html: warningIcon }}
|
|
|
|
color="orange"
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</td>
|
|
|
|
<td class="actions">
|
|
|
|
<Button
|
|
|
|
variant="outlined"
|
|
|
|
startIcon={deleteIcon}
|
|
|
|
size="small"
|
|
|
|
onClick={async () => onDelete(account)}
|
|
|
|
color="error"
|
|
|
|
>
|
|
|
|
Forget
|
|
|
|
</Button>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
);
|
|
|
|
})}
|
|
|
|
</tbody>
|
|
|
|
</AccountTable>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function TalerBankTable({
|
|
|
|
list,
|
|
|
|
onDelete,
|
|
|
|
}: {
|
|
|
|
list: KnownBankAccountsInfo[];
|
|
|
|
onDelete: (ac: KnownBankAccountsInfo) => void;
|
|
|
|
}): VNode {
|
|
|
|
const { i18n } = useTranslationContext();
|
|
|
|
if (list.length === 0) return <Fragment />;
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<h1>
|
|
|
|
<i18n.Translate>Taler accounts</i18n.Translate>
|
|
|
|
</h1>
|
|
|
|
<AccountTable>
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th>
|
|
|
|
<i18n.Translate>Alias</i18n.Translate>
|
|
|
|
</th>
|
|
|
|
<th>
|
|
|
|
<i18n.Translate>Host</i18n.Translate>
|
|
|
|
</th>
|
|
|
|
<th>
|
|
|
|
<i18n.Translate>Account</i18n.Translate>
|
|
|
|
</th>
|
|
|
|
<th class="kyc">
|
|
|
|
<i18n.Translate>KYC</i18n.Translate>
|
|
|
|
</th>
|
|
|
|
<th class="actions"></th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
|
|
|
{list.map((account) => {
|
|
|
|
const p = account.uri as PaytoUriTalerBank;
|
|
|
|
return (
|
|
|
|
<tr key={account.alias}>
|
|
|
|
<td>{account.alias}</td>
|
|
|
|
<td>{p.host}</td>
|
|
|
|
<td>{p.account}</td>
|
|
|
|
<td class="kyc">
|
|
|
|
{account.kyc_completed ? (
|
|
|
|
<SvgIcon
|
|
|
|
title={i18n.str`KYC done`}
|
|
|
|
dangerouslySetInnerHTML={{ __html: checkIcon }}
|
|
|
|
color="green"
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
<SvgIcon
|
|
|
|
title={i18n.str`KYC missing`}
|
|
|
|
dangerouslySetInnerHTML={{ __html: warningIcon }}
|
|
|
|
color="orange"
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</td>
|
|
|
|
<td class="actions">
|
|
|
|
<Button
|
|
|
|
variant="outlined"
|
|
|
|
startIcon={deleteIcon}
|
|
|
|
size="small"
|
|
|
|
onClick={async () => onDelete(account)}
|
|
|
|
color="error"
|
|
|
|
>
|
|
|
|
Forget
|
|
|
|
</Button>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
);
|
|
|
|
})}
|
|
|
|
</tbody>
|
|
|
|
</AccountTable>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function BitcoinTable({
|
|
|
|
list,
|
|
|
|
onDelete,
|
|
|
|
}: {
|
|
|
|
list: KnownBankAccountsInfo[];
|
|
|
|
onDelete: (ac: KnownBankAccountsInfo) => void;
|
|
|
|
}): VNode {
|
|
|
|
const { i18n } = useTranslationContext();
|
|
|
|
if (list.length === 0) return <Fragment />;
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<h2>
|
|
|
|
<i18n.Translate>Bitcoin accounts</i18n.Translate>
|
|
|
|
</h2>
|
|
|
|
<AccountTable>
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th>
|
|
|
|
<i18n.Translate>Alias</i18n.Translate>
|
|
|
|
</th>
|
|
|
|
<th>
|
|
|
|
<i18n.Translate>Address</i18n.Translate>
|
|
|
|
</th>
|
|
|
|
<th class="kyc">
|
|
|
|
<i18n.Translate>KYC</i18n.Translate>
|
|
|
|
</th>
|
|
|
|
<th class="actions"></th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
|
|
|
{list.map((account) => {
|
|
|
|
const p = account.uri as PaytoUriBitcoin;
|
|
|
|
return (
|
|
|
|
<tr key={account.alias}>
|
|
|
|
<td>{account.alias}</td>
|
|
|
|
<td>{p.targetPath}</td>
|
|
|
|
<td class="kyc">
|
|
|
|
{account.kyc_completed ? (
|
|
|
|
<SvgIcon
|
|
|
|
title={i18n.str`KYC done`}
|
|
|
|
dangerouslySetInnerHTML={{ __html: checkIcon }}
|
|
|
|
color="green"
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
<SvgIcon
|
|
|
|
title={i18n.str`KYC missing`}
|
|
|
|
dangerouslySetInnerHTML={{ __html: warningIcon }}
|
|
|
|
color="orange"
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</td>
|
|
|
|
<td class="actions">
|
|
|
|
<Button
|
|
|
|
variant="outlined"
|
|
|
|
startIcon={deleteIcon}
|
|
|
|
size="small"
|
|
|
|
onClick={async () => onDelete(account)}
|
|
|
|
color="error"
|
|
|
|
>
|
|
|
|
Forget
|
|
|
|
</Button>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
);
|
|
|
|
})}
|
|
|
|
</tbody>
|
|
|
|
</AccountTable>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function BitcoinAddressAccount({ field }: { field: TextFieldHandler }): VNode {
|
|
|
|
const { i18n } = useTranslationContext();
|
|
|
|
const [value, setValue] = useState<string | undefined>(undefined);
|
|
|
|
const errors = undefinedIfEmpty({
|
|
|
|
value: !value ? i18n.str`Can't be empty` : undefined,
|
|
|
|
});
|
|
|
|
return (
|
|
|
|
<Fragment>
|
2023-04-07 22:31:01 +02:00
|
|
|
<h3>
|
|
|
|
<i18n.Translate>Bitcoin Account</i18n.Translate>
|
|
|
|
</h3>
|
2022-10-28 18:39:06 +02:00
|
|
|
<TextField
|
|
|
|
label="Bitcoin address"
|
|
|
|
variant="standard"
|
|
|
|
fullWidth
|
|
|
|
value={value}
|
2022-11-07 23:29:47 +01:00
|
|
|
error={value !== undefined ? errors?.value : undefined}
|
2022-11-07 18:38:42 +01:00
|
|
|
disabled={!field.onInput}
|
2022-10-28 18:39:06 +02:00
|
|
|
onChange={(v) => {
|
|
|
|
setValue(v);
|
2022-11-07 18:38:42 +01:00
|
|
|
if (!errors && field.onInput) {
|
2023-01-17 20:01:04 +01:00
|
|
|
const p = buildPayto("bitcoin", v, undefined);
|
|
|
|
field.onInput(stringifyPaytoUri(p));
|
2022-10-28 18:39:06 +02:00
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function undefinedIfEmpty<T extends object>(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<string | undefined>(undefined);
|
|
|
|
const [account, setAccount] = useState<string | undefined>(undefined);
|
|
|
|
const errors = undefinedIfEmpty({
|
|
|
|
host: !host ? i18n.str`Can't be empty` : undefined,
|
|
|
|
account: !account ? i18n.str`Can't be empty` : undefined,
|
|
|
|
});
|
|
|
|
return (
|
|
|
|
<Fragment>
|
2023-04-07 22:31:01 +02:00
|
|
|
<h3>
|
|
|
|
<i18n.Translate>Taler Bank</i18n.Translate>
|
|
|
|
</h3>
|
2022-10-28 18:39:06 +02:00
|
|
|
<TextField
|
|
|
|
label="Bank host"
|
|
|
|
variant="standard"
|
|
|
|
fullWidth
|
|
|
|
value={host}
|
2022-11-07 23:29:47 +01:00
|
|
|
error={host !== undefined ? errors?.host : undefined}
|
2022-11-07 18:38:42 +01:00
|
|
|
disabled={!field.onInput}
|
2022-10-28 18:39:06 +02:00
|
|
|
onChange={(v) => {
|
|
|
|
setHost(v);
|
2023-01-17 20:01:04 +01:00
|
|
|
if (!errors && field.onInput && account) {
|
|
|
|
const p = buildPayto("x-taler-bank", v, account);
|
|
|
|
field.onInput(stringifyPaytoUri(p));
|
2022-10-28 18:39:06 +02:00
|
|
|
}
|
|
|
|
}}
|
2022-11-07 23:29:47 +01:00
|
|
|
/>
|
2022-10-28 18:39:06 +02:00
|
|
|
<TextField
|
|
|
|
label="Bank account"
|
|
|
|
variant="standard"
|
|
|
|
fullWidth
|
2022-11-07 18:38:42 +01:00
|
|
|
disabled={!field.onInput}
|
2022-10-28 18:39:06 +02:00
|
|
|
value={account}
|
2022-11-07 23:29:47 +01:00
|
|
|
error={account !== undefined ? errors?.account : undefined}
|
2022-10-28 18:39:06 +02:00
|
|
|
onChange={(v) => {
|
|
|
|
setAccount(v || "");
|
2023-01-17 20:01:04 +01:00
|
|
|
if (!errors && field.onInput && host) {
|
|
|
|
const p = buildPayto("x-taler-bank", host, v);
|
|
|
|
field.onInput(stringifyPaytoUri(p));
|
2022-10-28 18:39:06 +02:00
|
|
|
}
|
|
|
|
}}
|
2022-11-07 23:29:47 +01:00
|
|
|
/>
|
2022-10-28 18:39:06 +02:00
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-11-07 23:29:47 +01:00
|
|
|
//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}$/;
|
|
|
|
|
2022-10-28 18:39:06 +02:00
|
|
|
function IbanAddressAccount({ field }: { field: TextFieldHandler }): VNode {
|
|
|
|
const { i18n } = useTranslationContext();
|
2022-11-07 23:29:47 +01:00
|
|
|
const [bic, setBic] = useState<string | undefined>(undefined);
|
|
|
|
const [iban, setIban] = useState<string | undefined>(undefined);
|
2022-10-30 01:10:46 +02:00
|
|
|
const [name, setName] = useState<string | undefined>(undefined);
|
2022-10-28 18:39:06 +02:00
|
|
|
const errors = undefinedIfEmpty({
|
2022-11-07 23:29:47 +01:00
|
|
|
bic: !bic
|
|
|
|
? undefined
|
|
|
|
: !bicRegex.test(bic)
|
|
|
|
? i18n.str`Invalid bic`
|
|
|
|
: undefined,
|
|
|
|
iban: !iban
|
|
|
|
? i18n.str`Can't be empty`
|
2023-04-07 22:31:01 +02:00
|
|
|
: validateIban(iban).type === "invalid"
|
2022-11-07 23:29:47 +01:00
|
|
|
? i18n.str`Invalid iban`
|
|
|
|
: undefined,
|
2022-10-30 01:10:46 +02:00
|
|
|
name: !name ? i18n.str`Can't be empty` : undefined,
|
2022-10-28 18:39:06 +02:00
|
|
|
});
|
2022-11-07 23:29:47 +01:00
|
|
|
|
|
|
|
function sendUpdateIfNoErrors(
|
|
|
|
bic: string | undefined,
|
|
|
|
iban: string,
|
|
|
|
name: string,
|
|
|
|
): void {
|
|
|
|
if (!errors && field.onInput) {
|
2023-01-17 20:01:04 +01:00
|
|
|
const p = buildPayto("iban", iban, bic);
|
|
|
|
p.params["receiver-name"] = name;
|
|
|
|
field.onInput(stringifyPaytoUri(p));
|
2022-11-07 23:29:47 +01:00
|
|
|
}
|
|
|
|
}
|
2022-10-28 18:39:06 +02:00
|
|
|
return (
|
|
|
|
<Fragment>
|
2023-04-07 22:31:01 +02:00
|
|
|
<h3>
|
|
|
|
<i18n.Translate>International Bank Account Number</i18n.Translate>
|
|
|
|
</h3>
|
|
|
|
{/* <p>
|
2022-11-07 23:29:47 +01:00
|
|
|
<TextField
|
|
|
|
label="BIC"
|
|
|
|
variant="filled"
|
|
|
|
placeholder="BANKID"
|
|
|
|
fullWidth
|
|
|
|
value={bic}
|
|
|
|
error={bic !== undefined ? errors?.bic : undefined}
|
|
|
|
disabled={!field.onInput}
|
|
|
|
onChange={(v) => {
|
|
|
|
setBic(v);
|
|
|
|
sendUpdateIfNoErrors(v, iban || "", name || "");
|
|
|
|
}}
|
|
|
|
/>
|
2023-04-07 22:31:01 +02:00
|
|
|
</p> */}
|
2022-11-07 23:29:47 +01:00
|
|
|
<p>
|
|
|
|
<TextField
|
|
|
|
label="IBAN"
|
|
|
|
variant="filled"
|
|
|
|
placeholder="XX123456"
|
|
|
|
fullWidth
|
|
|
|
required
|
|
|
|
value={iban}
|
|
|
|
error={iban !== undefined ? errors?.iban : undefined}
|
|
|
|
disabled={!field.onInput}
|
|
|
|
onChange={(v) => {
|
|
|
|
setIban(v);
|
|
|
|
sendUpdateIfNoErrors(bic, v, name || "");
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
<TextField
|
2023-04-07 22:31:01 +02:00
|
|
|
label="Account name"
|
2022-11-07 23:29:47 +01:00
|
|
|
variant="filled"
|
|
|
|
placeholder="Name of the target bank account owner"
|
|
|
|
fullWidth
|
|
|
|
required
|
|
|
|
value={name}
|
|
|
|
error={name !== undefined ? errors?.name : undefined}
|
|
|
|
disabled={!field.onInput}
|
|
|
|
onChange={(v) => {
|
|
|
|
setName(v);
|
|
|
|
sendUpdateIfNoErrors(bic, iban || "", v);
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</p>
|
2022-10-28 18:39:06 +02:00
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function CustomFieldByAccountType({
|
|
|
|
type,
|
|
|
|
field,
|
|
|
|
}: {
|
|
|
|
type: AccountType;
|
|
|
|
field: TextFieldHandler;
|
|
|
|
}): VNode {
|
|
|
|
const { i18n } = useTranslationContext();
|
|
|
|
|
|
|
|
const AccountForm = formComponentByAccountType[type];
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<AccountForm field={field} />
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|