/*
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, PreparePayResult } from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { useState } from "preact/hooks";
import { alertFromError, useAlertContext } from "../../context/alert.js";
import { useBackendContext } from "../../context/backend.js";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
import { AmountFieldHandler, TextFieldHandler } from "../../mui/handlers.js";
import { RecursiveState } from "../../utils/index.js";
import { Props, State } from "./index.js";
export function useComponentState({
talerTemplateUri,
cancel,
goToWalletManualWithdraw,
onSuccess,
}: Props): RecursiveState {
const api = useBackendContext();
const { i18n } = useTranslationContext();
const { safely } = useAlertContext();
// const url = talerTemplateUri ? new URL(talerTemplateUri) : undefined;
// const parsedAmount = !amountParam ? undefined : Amounts.parse(amountParam);
// const currency = parsedAmount ? parsedAmount.currency : amountParam;
// const initialAmount =
// parsedAmount ?? (currency ? Amounts.zeroOfCurrency(currency) : undefined);
const [newOrder, setNewOrder] = useState("");
const hook = useAsyncAsHook(async () => {
if (!talerTemplateUri) throw Error("ERROR_NO-URI-FOR-PAYMENT-TEMPLATE");
const templateP = await api.wallet.call(
WalletApiOperation.CheckPayForTemplate, { talerPayTemplateUri: talerTemplateUri },
);
const requireMoreInfo = !templateP.templateDetails.template_contract.amount || !templateP.templateDetails.template_contract.summary;
let payStatus: PreparePayResult | undefined = undefined;
if (!requireMoreInfo) {
payStatus = await api.wallet.call(WalletApiOperation.PreparePayForTemplate, { talerPayTemplateUri: talerTemplateUri });
}
const balance = await api.wallet.call(WalletApiOperation.GetBalances, {});
return { payStatus, balance, uri: talerTemplateUri, templateP };
}, []);
if (!hook) {
return {
status: "loading",
error: undefined,
};
}
if (hook.hasError) {
return {
status: "error",
error: alertFromError(
i18n,
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,
};
}
return () => {
const cfg = hook.response.templateP.templateDetails.template_contract;
const def = hook.response.templateP.templateDetails.editable_defaults;
const fixedAmount = cfg.amount !== undefined ? Amounts.parseOrThrow(cfg.amount) : undefined;
const fixedSummary = cfg.summary !== undefined ? cfg.summary : undefined;
const defaultAmount = def?.amount !== undefined ? Amounts.parseOrThrow(def.amount) : undefined;
const defaultSummary = def?.summary !== undefined ? def.summary : undefined;
const zero = fixedAmount ? Amounts.zeroOfAmount(fixedAmount) :
cfg.currency !== undefined ? Amounts.zeroOfCurrency(cfg.currency) :
defaultAmount !== undefined ? Amounts.zeroOfAmount(defaultAmount) :
def?.currency !== undefined ? Amounts.zeroOfCurrency(def.currency) :
Amounts.zeroOfCurrency(hook.response.templateP.supportedCurrencies[0]);
const [amount, setAmount] = useState(defaultAmount ?? zero);
const [summary, setSummary] = useState(defaultSummary ?? "");
async function createOrder() {
try {
const templateParams: Record = {};
if (amount && !fixedAmount) {
templateParams["amount"] = Amounts.stringify(amount);
}
if (summary && !fixedSummary) {
templateParams["summary"] = summary;
}
const payStatus = await api.wallet.call(
WalletApiOperation.PreparePayForTemplate,
{
talerPayTemplateUri: talerTemplateUri,
templateParams,
},
);
setNewOrder(payStatus.talerUri!);
} catch (e) {
console.error(e);
}
}
const errors = undefinedIfEmpty({
amount: fixedAmount !== undefined ? undefined : amount && Amounts.isZero(amount) ? i18n.str`required` : undefined,
summary: fixedSummary !== undefined ? undefined : summary !== undefined && !summary ? i18n.str`required` : undefined,
});
return {
status: "fill-template",
error: undefined,
minAge: cfg.minimum_age ?? 0,
amount:
fixedAmount === undefined
? ({
onInput: (a) => {
setAmount(a);
},
value: amount,
error: errors?.amount,
} as AmountFieldHandler)
: undefined,
summary:
fixedSummary === 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(obj: T): T | undefined {
return Object.keys(obj).some(
(k) => (obj as Record)[k] !== undefined,
)
? obj
: undefined;
}