/* This file is part of TALER (C) 2015 GNUnet e.V. 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. 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 TALER; see the file COPYING. If not, see */ /** * Page shown to the user to confirm entering * a contract. */ /** * Imports. */ // import * as i18n from "../i18n"; import { renderAmount, ProgressButton } from "../renderHtml"; import * as wxApi from "../wxApi"; import { useState, useEffect } from "preact/hooks"; import { getJsonI18n, i18n } from "@gnu-taler/taler-util"; import { PreparePayResult, ConfirmPayResult, AmountJson, PreparePayResultType, Amounts, ContractTerms, ConfirmPayResultType, } from "@gnu-taler/taler-util"; import { JSX, VNode } from "preact"; interface Props { talerPayUri?: string } export function PayPage({ talerPayUri }: Props): JSX.Element { const [payStatus, setPayStatus] = useState(undefined); const [payResult, setPayResult] = useState(undefined); const [payErrMsg, setPayErrMsg] = useState(""); const [numTries, setNumTries] = useState(0); const [loading, setLoading] = useState(false); let totalFees: AmountJson | undefined = undefined; useEffect(() => { if (!talerPayUri) return; const doFetch = async (): Promise => { const p = await wxApi.preparePay(talerPayUri); setPayStatus(p); }; doFetch(); }, [numTries, talerPayUri]); if (!talerPayUri) { return missing pay uri } if (!payStatus) { return Loading payment information ...; } let insufficientBalance = false; if (payStatus.status == PreparePayResultType.InsufficientBalance) { insufficientBalance = true; } if (payStatus.status === PreparePayResultType.PaymentPossible) { const amountRaw = Amounts.parseOrThrow(payStatus.amountRaw); const amountEffective: AmountJson = Amounts.parseOrThrow( payStatus.amountEffective, ); totalFees = Amounts.sub(amountEffective, amountRaw).amount; } if ( payStatus.status === PreparePayResultType.AlreadyConfirmed && numTries === 0 ) { const fulfillmentUrl = payStatus.contractTerms.fulfillment_url; if (fulfillmentUrl) { return ( You have already paid for this article. Click{" "} here to view it again. ); } else { You have already paid for this article:{" "} {payStatus.contractTerms.fulfillment_message ?? "no message given"} ; } } const contractTerms: ContractTerms = payStatus.contractTerms; if (!contractTerms) { return ( Error: did not get contract terms from merchant or wallet backend. ); } let merchantName: VNode; if (contractTerms.merchant && contractTerms.merchant.name) { merchantName = {contractTerms.merchant.name}; } else { merchantName = (pub: {contractTerms.merchant_pub}); } const amount = ( {renderAmount(Amounts.parseOrThrow(contractTerms.amount))} ); const doPayment = async (): Promise => { if (payStatus.status !== "payment-possible") { throw Error(`invalid state: ${payStatus.status}`); } const proposalId = payStatus.proposalId; setNumTries(numTries + 1); try { setLoading(true); const res = await wxApi.confirmPay(proposalId, undefined); if (res.type !== ConfirmPayResultType.Done) { throw Error("payment pending"); } const fu = res.contractTerms.fulfillment_url; if (fu) { document.location.href = fu; } setPayResult(res); } catch (e) { console.error(e); setPayErrMsg(e.message); } }; if (payResult && payResult.type === ConfirmPayResultType.Done) { if (payResult.contractTerms.fulfillment_message) { const obj = { fulfillment_message: payResult.contractTerms.fulfillment_message, fulfillment_message_i18n: payResult.contractTerms.fulfillment_message_i18n, }; const msg = getJsonI18n(obj, "fulfillment_message"); return (

Payment succeeded.

{msg}

); } else { return Redirecting ...; } } return (

The merchant {merchantName} offers you to purchase:

{contractTerms.summary}
{totalFees ? ( The total price is {amount} (plus {renderAmount(totalFees)} fees). ) : ( The total price is {amount}. )}

{insufficientBalance ? (

Unable to pay: Your balance is insufficient.

) : null} {payErrMsg ? (

Payment failed: {payErrMsg}

) : (
doPayment()} > {i18n.str`Confirm payment`}
)}
); }