/*
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 {
Amounts,
HttpStatusCode,
Logger,
TranslatedString,
WithdrawUriResult,
parsePaytoUri,
parseWithdrawUri,
stringifyWithdrawUri,
} from "@gnu-taler/taler-util";
import { ErrorType, RequestError, notify, notifyError, notifyInfo, useTranslationContext } from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { Loading } from "../components/Loading.js";
import { useAccessAPI, useWithdrawalDetails } from "../hooks/access.js";
import { useSettings } from "../hooks/settings.js";
import { handleNotOkResult } from "./HomePage.js";
import { QrCodeSection, QrCodeSectionSimpler } from "./QrCodeSection.js";
import { WithdrawalConfirmationQuestion } from "./WithdrawalConfirmationQuestion.js";
import { useEffect, useState } from "preact/hooks";
import { buildRequestErrorMessage } from "../utils.js";
import { getInitialBackendBaseURL } from "../hooks/backend.js";
const logger = new Logger("WithdrawalQRCode");
interface Props {
withdrawUri: WithdrawUriResult;
onClose: () => void;
}
/**
* Offer the QR code (and a clickable taler://-link) to
* permit the passing of exchange and reserve details to
* the bank. Poll the backend until such operation is done.
*/
export function WithdrawalQRCode({
withdrawUri,
onClose,
}: Props): VNode {
const [settings, updateSettings] = useSettings();
const { i18n } = useTranslationContext();
const result = useWithdrawalDetails(withdrawUri.withdrawalOperationId);
if (!result.ok) {
if (result.loading) {
return ;
}
if (
result.type === ErrorType.CLIENT &&
result.status === HttpStatusCode.NotFound
) {
onClose()
return
{i18n.str`Operation aborted`}
}
if (data.confirmation_done) {
return {
notifyInfo(i18n.str`Operation canceled`);
onClose()
}}
/>
);
}
if (!data.selected_reserve_pub) {
return
the exchange is selcted but no reserve pub
}
const account = !data.selected_exchange_account ? undefined : parsePaytoUri(data.selected_exchange_account)
if (!account) {
return
the exchange is selcted but no account
}
return (
{
notifyInfo(i18n.str`Operation canceled`);
onClose()
}}
/>
);
}
export function WithdrawalOperationState({
currency,
currentOperation,
onClose,
}: {currency:string, currentOperation: string, onClose: () => void}): VNode {
const { i18n } = useTranslationContext();
const [settings, updateSettings] = useSettings()
const { createWithdrawal } = useAccessAPI();
const amount = settings.maxWithdrawalAmount
async function doSilentStart() {
//FIXME: if amount is not enough use balance
const parsedAmount = Amounts.parseOrThrow(`${currency}:${amount}`)
try {
const result = await createWithdrawal({
amount: Amounts.stringify(parsedAmount),
});
const uri = parseWithdrawUri(result.data.taler_withdraw_uri);
if (!uri) {
return notifyError(
i18n.str`Server responded with an invalid withdraw URI`,
i18n.str`Withdraw URI: ${result.data.taler_withdraw_uri}`);
} else {
updateSettings("currentWithdrawalOperationId", uri.withdrawalOperationId)
}
} catch (error) {
if (error instanceof RequestError) {
notify(
buildRequestErrorMessage(i18n, error.cause, {
onClientError: (status) =>
status === HttpStatusCode.Forbidden
? i18n.str`The operation was rejected due to insufficient funds`
: undefined,
}),
);
} else {
notifyError(
i18n.str`Operation failed, please report`,
(error instanceof Error
? error.message
: JSON.stringify(error)) as TranslatedString
)
}
}
}
useEffect(() => {
doSilentStart()
}, [settings.fastWithdrawal, amount])
const result = useWithdrawalDetails(currentOperation);
if (!result.ok) {
if (result.loading) {
return ;
}
if (
result.type === ErrorType.CLIENT &&
result.status === HttpStatusCode.NotFound
) {
onClose()
return operation not found
;
}
// onLoadNotOk();
return handleNotOkResult(i18n)(result);
}
const { data } = result;
const baseUrl = getInitialBackendBaseURL()
const uri = stringifyWithdrawUri({
bankIntegrationApiBaseUrl: `${baseUrl}/integration-api`,
withdrawalOperationId: currentOperation,
});
const parsedUri = parseWithdrawUri(uri);
if (data.aborted) {
return
the operation was aborted, you can create another one
}
if (data.confirmation_done) {
return
the wire transfer is made, you coin should arrive shortly
}
if (!parsedUri) {
return
the operation is not valid, create another one
}
if (!data.selection_done) {
return (
{
notifyInfo(i18n.str`Operation canceled`);
onClose()
}}
/>
);
}
if (!data.selected_reserve_pub) {
return
the exchange is selcted but no reserve pub
}
const account = !data.selected_exchange_account ? undefined : parsePaytoUri(data.selected_exchange_account)
if (!account) {
return
the exchange is selected but no account
}
return
the operation is wating for the question to be answered
;
}