/* 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 { AmountJson, Amounts, PaymentInsufficientBalanceDetails, PreparePayResult, PreparePayResultType, TranslatedString, parsePayUri, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; import { useBackendContext } from "../context/backend.js"; import { Button } from "../mui/Button.js"; import { ButtonHandler } from "../mui/handlers.js"; import { assertUnreachable } from "../utils/index.js"; import { Amount } from "./Amount.js"; import { Part } from "./Part.js"; import { QR } from "./QR.js"; import { LinkSuccess, WarningBox } from "./styled/index.js"; interface Props { payStatus: PreparePayResult; payHandler: ButtonHandler | undefined; uri: string; amount: AmountJson; goToWalletManualWithdraw: (currency: string) => Promise; } export function PaymentButtons({ payStatus, uri, payHandler, amount, goToWalletManualWithdraw, }: Props): VNode { const { i18n } = useTranslationContext(); if (payStatus.status === PreparePayResultType.PaymentPossible) { return (
); } if (payStatus.status === PreparePayResultType.InsufficientBalance) { const reason = getReason(payStatus.balanceDetails); let BalanceMessage = ""; switch (reason) { case "age-acceptable": { BalanceMessage = i18n.str`Balance is not enough because you have ${Amounts.stringifyValue( payStatus.balanceDetails.balanceAgeAcceptable, )} ${amount.currency} to pay for this contract which is restricted.`; break; } case "available": { BalanceMessage = i18n.str`Balance is not enough because you have ${Amounts.stringifyValue( payStatus.balanceDetails.balanceAvailable, )} ${amount.currency} available.`; break; } case "merchant-acceptable": { BalanceMessage = i18n.str`Balance is not enough because merchant will just accept ${Amounts.stringifyValue( payStatus.balanceDetails.balanceReceiverAcceptable, )} ${amount.currency } . To know more you can check which exchange and auditors the merchant trust.`; break; } case "merchant-depositable": { BalanceMessage = i18n.str`Balance is not enough because merchant will just accept ${Amounts.stringifyValue( payStatus.balanceDetails.balanceReceiverDepositable, )} ${amount.currency } . To know more you can check which wire methods the merchant accepts.`; break; } case "material": { BalanceMessage = i18n.str`Balance is not enough because you have ${Amounts.stringifyValue( payStatus.balanceDetails.balanceMaterial, )} ${amount.currency } to spend right know. There are some coins that need to be refreshed.`; break; } case "fee-gap": { BalanceMessage = i18n.str`Balance looks like it should be enough, but doesn't cover all fees requested by the merchant and payment processor. Please ensure there is at least ${Amounts.stringifyValue( Amounts.stringify( Amounts.sub( amount, payStatus.balanceDetails.maxEffectiveSpendAmount, ).amount, ), )} ${amount.currency } more balance in your wallet or ask your merchant to cover more of the fees.`; break; } default: assertUnreachable(reason); } return (
{BalanceMessage}
); } if (payStatus.status === PreparePayResultType.AlreadyConfirmed) { return (
{payStatus.paid && payStatus.contractTerms.fulfillment_message && ( )}
); } assertUnreachable(payStatus); } function PayWithMobile({ uri }: { uri: string }): VNode { const { i18n } = useTranslationContext(); const api = useBackendContext(); const payUri = parsePayUri(uri); const [showQR, setShowQR] = useState(undefined); async function sharePrivatePaymentURI() { if (!payUri) { return; } if (!showQR) { const result = await api.wallet.call(WalletApiOperation.SharePayment, { merchantBaseUrl: payUri.merchantBaseUrl, orderId: payUri.orderId, }); setShowQR(result.privatePayUri); } else { setShowQR(undefined); } } if (!payUri) { return } return (
{!showQR ? i18n.str`Pay with a mobile phone` : i18n.str`Hide QR`} {showQR && (
Scan the QR code or   click here
)}
); } type NoEnoughBalanceReason = | "available" | "material" | "age-acceptable" | "merchant-acceptable" | "merchant-depositable" | "fee-gap"; function getReason( info: PaymentInsufficientBalanceDetails, ): NoEnoughBalanceReason { if (Amounts.cmp(info.amountRequested, info.balanceAvailable) > 0) { return "available"; } if (Amounts.cmp(info.amountRequested, info.balanceMaterial) > 0) { return "material"; } if (Amounts.cmp(info.amountRequested, info.balanceAgeAcceptable) > 0) { return "age-acceptable"; } if (Amounts.cmp(info.amountRequested, info.balanceReceiverAcceptable) > 0) { return "merchant-acceptable"; } if (Amounts.cmp(info.amountRequested, info.balanceReceiverDepositable) > 0) { return "merchant-depositable"; } return "fee-gap"; }