/*
This file is part of GNU Taler
(C) 2022-2024 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,
TranslatedString,
assertUnreachable,
parseWithdrawUri
} from "@gnu-taler/taler-util";
import {
Attention,
LocalNotificationBanner,
notifyError,
useLocalNotification,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
import { forwardRef } from "preact/compat";
import { useState } from "preact/hooks";
import { useBankCoreApiContext } from "../context/config.js";
import { useBackendState } from "../hooks/backend.js";
import { useBankState } from "../hooks/bank-state.js";
import { usePreferences } from "../hooks/preferences.js";
import { RouteDefinition } from "../route.js";
import { undefinedIfEmpty } from "../utils.js";
import { OperationState } from "./OperationState/index.js";
import { InputAmount, doAutoFocus } from "./PaytoWireTransferForm.js";
const RefAmount = forwardRef(InputAmount);
function OldWithdrawalForm({
onOperationCreated,
limit,
routeCancel,
focus,
routeOperationDetails,
}: {
limit: AmountJson;
focus?: boolean;
routeOperationDetails: RouteDefinition<{ wopid: string }>,
onOperationCreated: (wopid: string) => void;
routeCancel: RouteDefinition;
}): VNode {
const { i18n } = useTranslationContext();
const [settings] = usePreferences();
// const walletInegrationApi = useTalerWalletIntegrationAPI()
// const { navigateTo } = useNavigationContext();
const [bankState, updateBankState] = useBankState();
const { api } = useBankCoreApiContext();
const { state: credentials } = useBackendState();
const creds = credentials.status !== "loggedIn" ? undefined : credentials;
const [amountStr, setAmountStr] = useState(
`${settings.maxWithdrawalAmount}`,
);
const [notification, notify, handleError] = useLocalNotification();
if (bankState.currentWithdrawalOperationId) {
// FIXME: doing the preventDefault is not optimal
// const suri = stringifyWithdrawUri({
// bankIntegrationApiBaseUrl: api.getIntegrationAPI().baseUrl,
// withdrawalOperationId: bankState.currentWithdrawalOperationId,
// });
// const uri = parseWithdrawUri(suri)!
const url = routeOperationDetails.url({
wopid: bankState.currentWithdrawalOperationId,
});
return (
{
updateBankState("currentWithdrawalOperationId", undefined);
}}>
Complete the operation in
{" "}
{
// e.preventDefault()
// walletInegrationApi.publishTalerAction(uri, () => {
// navigateTo(url)
// })
// }}
>
this page
);
}
const trimmedAmountStr = amountStr?.trim();
const parsedAmount = trimmedAmountStr
? Amounts.parse(`${limit.currency}:${trimmedAmountStr}`)
: undefined;
const errors = undefinedIfEmpty({
amount:
trimmedAmountStr == null
? i18n.str`Required`
: !parsedAmount
? i18n.str`Invalid`
: Amounts.cmp(limit, parsedAmount) === -1
? i18n.str`Balance is not enough`
: undefined,
});
async function doStart() {
if (!parsedAmount || !creds) return;
await handleError(async () => {
const resp = await api.createWithdrawal(creds, {
amount: Amounts.stringify(parsedAmount),
});
if (resp.type === "ok") {
const uri = parseWithdrawUri(resp.body.taler_withdraw_uri);
if (!uri) {
return notifyError(
i18n.str`Server responded with an invalid withdraw URI`,
i18n.str`Withdraw URI: ${resp.body.taler_withdraw_uri}`,
);
} else {
updateBankState(
"currentWithdrawalOperationId",
uri.withdrawalOperationId,
);
onOperationCreated(uri.withdrawalOperationId);
}
} else {
switch (resp.case) {
case HttpStatusCode.Conflict: {
notify({
type: "error",
title: i18n.str`The operation was rejected due to insufficient funds`,
description: resp.detail.hint as TranslatedString,
debug: resp.detail,
});
break;
}
case HttpStatusCode.Unauthorized: {
notify({
type: "error",
title: i18n.str`The operation was rejected due to insufficient funds`,
description: resp.detail.hint as TranslatedString,
debug: resp.detail,
});
break;
}
case HttpStatusCode.NotFound: {
notify({
type: "error",
title: i18n.str`Account not found`,
description: resp.detail.hint as TranslatedString,
debug: resp.detail,
});
break;
}
default:
assertUnreachable(resp);
}
}
});
}
return (
);
}
export function WalletWithdrawForm({
focus,
limit,
routeCancel,
onAuthorizationRequired,
onOperationCreated,
onOperationAborted,
routeOperationDetails,
}: {
limit: AmountJson;
focus?: boolean;
routeOperationDetails: RouteDefinition<{ wopid: string }>,
onAuthorizationRequired: () => void;
onOperationCreated: (wopid: string) => void;
onOperationAborted: () => void;
routeCancel: RouteDefinition;
}): VNode {
const { i18n } = useTranslationContext();
const [settings, updateSettings] = usePreferences();
return (
Prepare your Taler wallet
After using your wallet you will need to confirm or cancel the
operation on this site.
{settings.showInstallWallet && (
{
updateSettings("showInstallWallet", false);
}}
>
If you don't have one yet you can follow the instruction in
{" "}
this page
)}
{!settings.fastWithdrawal ? (
) : (
)}