wallet-core/packages/taler-wallet-webextension/src/cta/PaymentTemplate/state.ts
2023-05-05 08:52:58 -03:00

170 lines
4.9 KiB
TypeScript

/*
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 { Amounts } from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useState } from "preact/hooks";
import { alertFromError, useAlertContext } from "../../context/alert.js";
import { useBackendContext } from "../../context/backend.js";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
import { AmountFieldHandler, TextFieldHandler } from "../../mui/handlers.js";
import { Props, State } from "./index.js";
export function useComponentState({
talerTemplateUri,
cancel,
goToWalletManualWithdraw,
onSuccess,
}: Props): State {
const api = useBackendContext();
const { i18n } = useTranslationContext();
const { safely } = useAlertContext();
const url = talerTemplateUri ? new URL(talerTemplateUri) : undefined;
const amountParam = !url
? undefined
: url.searchParams.get("amount") ?? undefined;
const summaryParam = !url
? undefined
: url.searchParams.get("summary") ?? undefined;
const parsedAmount = !amountParam ? undefined : Amounts.parse(amountParam);
const currency = parsedAmount ? parsedAmount.currency : amountParam;
const initialAmount =
parsedAmount ?? (currency ? Amounts.zeroOfCurrency(currency) : undefined);
const [amount, setAmount] = useState(initialAmount);
const [summary, setSummary] = useState(summaryParam);
const [newOrder, setNewOrder] = useState("");
const hook = useAsyncAsHook(async () => {
if (!talerTemplateUri) throw Error("ERROR_NO-URI-FOR-PAYMENT-TEMPLATE");
let payStatus;
if (!amountParam && !summaryParam) {
payStatus = await api.wallet.call(
WalletApiOperation.PreparePayForTemplate,
{
talerPayTemplateUri: talerTemplateUri,
templateParams: {},
},
);
}
const balance = await api.wallet.call(WalletApiOperation.GetBalances, {});
return { payStatus, balance, uri: talerTemplateUri };
}, []);
if (!hook) {
return {
status: "loading",
error: undefined,
};
}
if (hook.hasError) {
return {
status: "error",
error: alertFromError(
i18n.str`Could not load the status of the order template`,
hook,
),
};
}
if (hook.response.payStatus) {
return {
status: "order-ready",
error: undefined,
cancel,
goToWalletManualWithdraw,
onSuccess,
talerPayUri: hook.response.payStatus.talerUri!,
};
}
if (newOrder) {
return {
status: "order-ready",
error: undefined,
cancel,
goToWalletManualWithdraw,
onSuccess,
talerPayUri: newOrder,
};
}
async function createOrder() {
try {
const templateParams: Record<string, string> = {};
if (amount) {
templateParams["amount"] = Amounts.stringify(amount);
}
if (summary) {
templateParams["summary"] = summary;
}
const payStatus = await api.wallet.call(
WalletApiOperation.PreparePayForTemplate,
{
talerPayTemplateUri: talerTemplateUri,
templateParams,
},
);
setNewOrder(payStatus.talerUri!);
} catch (e) {}
}
const errors = undefinedIfEmpty({
amount: amount && Amounts.isZero(amount) ? i18n.str`required` : undefined,
summary: !summary ? i18n.str`required` : undefined,
});
return {
status: "fill-template",
error: undefined,
currency: currency!, //currency is always not null
amount:
amount !== undefined
? ({
onInput: (a) => {
setAmount(a);
},
value: amount,
error: errors?.amount,
} as AmountFieldHandler)
: undefined,
summary:
summary !== undefined
? ({
onInput: (t) => {
setSummary(t);
},
value: summary,
error: errors?.summary,
} as TextFieldHandler)
: undefined,
onCreate: {
onClick: errors
? undefined
: safely("create order for pay template", createOrder),
},
};
}
function undefinedIfEmpty<T extends object>(obj: T): T | undefined {
return Object.keys(obj).some((k) => (obj as any)[k] !== undefined)
? obj
: undefined;
}