170 lines
4.9 KiB
TypeScript
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;
|
|
}
|