/*
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 {
AmountJson,
Amounts,
HttpStatusCode,
Logger,
TranslatedString,
buildPayto,
parsePaytoUri,
stringifyPaytoUri
} from "@gnu-taler/taler-util";
import {
RequestError,
notify,
notifyError,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { h, VNode, Fragment, Ref } from "preact";
import { useEffect, useRef, useState } from "preact/hooks";
import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js";
import { useAccessAPI } from "../hooks/access.js";
import {
buildRequestErrorMessage,
undefinedIfEmpty,
validateIBAN,
} from "../utils.js";
const logger = new Logger("PaytoWireTransferForm");
export function PaytoWireTransferForm({
focus,
onSuccess,
onCancel,
limit,
}: {
focus?: boolean;
onSuccess: () => void;
onCancel: (() => void) | undefined;
limit: AmountJson;
}): VNode {
const [isRawPayto, setIsRawPayto] = useState(false);
const [iban, setIban] = useState(undefined);
const [subject, setSubject] = useState(undefined);
const [amount, setAmount] = useState(undefined);
const [rawPaytoInput, rawPaytoInputSetter] = useState(
undefined,
);
const { i18n } = useTranslationContext();
const ibanRegex = "^[A-Z][A-Z][0-9]+$";
const ref = useRef(null);
useEffect(() => {
if (focus) ref.current?.focus();
}, [focus, isRawPayto]);
const trimmedAmountStr = amount?.trim();
const parsedAmount = Amounts.parse(`${limit.currency}:${trimmedAmountStr}`);
const IBAN_REGEX = /^[A-Z][A-Z0-9]*$/;
const errorsWire = undefinedIfEmpty({
iban: !iban
? i18n.str`Missing IBAN`
: !IBAN_REGEX.test(iban)
? i18n.str`IBAN should have just uppercased letters and numbers`
: validateIBAN(iban, i18n),
subject: !subject ? i18n.str`Missing subject` : undefined,
amount: !trimmedAmountStr
? i18n.str`Missing amount`
: !parsedAmount
? i18n.str`Amount is not valid`
: Amounts.isZero(parsedAmount)
? i18n.str`Should be greater than 0`
: Amounts.cmp(limit, parsedAmount) === -1
? i18n.str`balance is not enough`
: undefined,
});
const { createTransaction } = useAccessAPI();
const parsed = !rawPaytoInput ? undefined : parsePaytoUri(rawPaytoInput);
const errorsPayto = undefinedIfEmpty({
rawPaytoInput: !rawPaytoInput
? i18n.str`required`
: !parsed
? i18n.str`does not follow the pattern`
: !parsed.params.amount
? i18n.str`use the "amount" parameter to specify the amount to be transferred`
: Amounts.parse(parsed.params.amount) === undefined
? i18n.str`the amount is not valid`
: !parsed.params.message
? i18n.str`use the "message" parameter to specify a reference text for the transfer`
: !parsed.isKnown || parsed.targetType !== "iban"
? i18n.str`only "IBAN" target are supported`
: !IBAN_REGEX.test(parsed.iban)
? i18n.str`IBAN should have just uppercased letters and numbers`
: validateIBAN(parsed.iban, i18n),
});
async function doSend() {
let paytoUri: string | undefined;
if (rawPaytoInput) {
paytoUri = rawPaytoInput
} else {
if (!iban || !subject) return;
const ibanPayto = buildPayto("iban", iban, undefined);
ibanPayto.params.message = encodeURIComponent(subject);
paytoUri = stringifyPaytoUri(ibanPayto);
}
try {
await createTransaction({
paytoUri,
amount: `${limit.currency}:${amount}`,
});
onSuccess();
setAmount(undefined);
setIban(undefined);
setSubject(undefined);
rawPaytoInputSetter(undefined)
} catch (error) {
if (error instanceof RequestError) {
notify(
buildRequestErrorMessage(i18n, error.cause, {
onClientError: (status) =>
status === HttpStatusCode.BadRequest
? i18n.str`The request was invalid or the payto://-URI used unacceptable features.`
: undefined,
}),
);
} else {
notifyError(
i18n.str`Operation failed, please report`,
(error instanceof Error
? error.message
: JSON.stringify(error)) as TranslatedString
)
}
}
}
return (