summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/cta/Pay.tsx
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2021-08-19 00:34:47 -0300
committerSebastian <sebasjm@gmail.com>2021-08-19 00:35:21 -0300
commit97a05ff659af274dcfcd9c76bf19100bbd51ce0e (patch)
tree9cce837ec9a5ec06279dc48eac75e1993ede983f /packages/taler-wallet-webextension/src/cta/Pay.tsx
parentb015f76e7268cb5caff14a0ed88cb5e8fa53dc2e (diff)
downloadwallet-core-97a05ff659af274dcfcd9c76bf19100bbd51ce0e.tar.gz
wallet-core-97a05ff659af274dcfcd9c76bf19100bbd51ce0e.tar.bz2
wallet-core-97a05ff659af274dcfcd9c76bf19100bbd51ce0e.zip
new wallet history and view refactoring
Diffstat (limited to 'packages/taler-wallet-webextension/src/cta/Pay.tsx')
-rw-r--r--packages/taler-wallet-webextension/src/cta/Pay.tsx253
1 files changed, 253 insertions, 0 deletions
diff --git a/packages/taler-wallet-webextension/src/cta/Pay.tsx b/packages/taler-wallet-webextension/src/cta/Pay.tsx
new file mode 100644
index 000000000..a5849bb28
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/cta/Pay.tsx
@@ -0,0 +1,253 @@
+/*
+ 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 <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * 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 { ConfirmPayResultDone, 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 AlreadyPaid({ payStatus }: { payStatus: PreparePayResult }) {
+ const fulfillmentUrl = payStatus.contractTerms.fulfillment_url;
+ let message;
+ if (fulfillmentUrl) {
+ message = (
+ <span>
+ You have already paid for this article. Click{" "}
+ <a href={fulfillmentUrl} target="_bank" rel="external">here</a> to view it again.
+ </span>
+ );
+ } else {
+ message = <span>
+ You have already paid for this article:{" "}
+ <em>
+ {payStatus.contractTerms.fulfillment_message ?? "no message given"}
+ </em>
+ </span>;
+ }
+ return <section class="main">
+ <h1>GNU Taler Wallet</h1>
+ <article class="fade">
+ {message}
+ </article>
+ </section>
+}
+
+const doPayment = async (payStatus: PreparePayResult): Promise<ConfirmPayResultDone> => {
+ if (payStatus.status !== "payment-possible") {
+ throw Error(`invalid state: ${payStatus.status}`);
+ }
+ const proposalId = payStatus.proposalId;
+ 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;
+ }
+ return res;
+};
+
+
+
+export function PayPage({ talerPayUri }: Props): JSX.Element {
+ const [payStatus, setPayStatus] = useState<PreparePayResult | undefined>(undefined);
+ const [payResult, setPayResult] = useState<ConfirmPayResult | undefined>(undefined);
+ const [payErrMsg, setPayErrMsg] = useState<string | undefined>("");
+
+ useEffect(() => {
+ if (!talerPayUri) return;
+ const doFetch = async (): Promise<void> => {
+ const p = await wxApi.preparePay(talerPayUri);
+ setPayStatus(p);
+ };
+ doFetch();
+ }, [talerPayUri]);
+
+ if (!talerPayUri) {
+ return <span>missing pay uri</span>
+ }
+
+ if (!payStatus) {
+ return <span>Loading payment information ...</span>;
+ }
+
+ 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 (
+ <div>
+ <p>Payment succeeded.</p>
+ <p>{msg}</p>
+ </div>
+ );
+ } else {
+ return <span>Redirecting ...</span>;
+ }
+ }
+
+ const onClick = async () => {
+ try {
+ const res = await doPayment(payStatus)
+ setPayResult(res);
+ } catch (e) {
+ console.error(e);
+ setPayErrMsg(e.message);
+ }
+
+ }
+
+ return <PaymentRequestView payStatus={payStatus} onClick={onClick} payErrMsg={payErrMsg} />;
+}
+
+export interface PaymentRequestViewProps {
+ payStatus: PreparePayResult;
+ onClick: () => void;
+ payErrMsg?: string;
+
+}
+export function PaymentRequestView({ payStatus, onClick, payErrMsg }: PaymentRequestViewProps) {
+ let totalFees: AmountJson | undefined = undefined;
+ let insufficientBalance = false;
+ const [loading, setLoading] = useState(false);
+ const contractTerms: ContractTerms = payStatus.contractTerms;
+
+ if (
+ payStatus.status === PreparePayResultType.AlreadyConfirmed
+ ) {
+ return <AlreadyPaid payStatus={payStatus} />
+ }
+
+ if (!contractTerms) {
+ return (
+ <span>
+ Error: did not get contract terms from merchant or wallet backend.
+ </span>
+ );
+ }
+
+ 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;
+ }
+
+ let merchantName: VNode;
+ if (contractTerms.merchant && contractTerms.merchant.name) {
+ merchantName = <strong>{contractTerms.merchant.name}</strong>;
+ } else {
+ merchantName = <strong>(pub: {contractTerms.merchant_pub})</strong>;
+ }
+
+ const amount = (
+ <strong>{renderAmount(Amounts.parseOrThrow(contractTerms.amount))}</strong>
+ );
+
+ return <section class="main">
+ <h1>GNU Taler Wallet</h1>
+ <article class="fade">
+ <div>
+ <p>
+ <i18n.Translate>
+ The merchant <span>{merchantName}</span> offers you to purchase:
+ </i18n.Translate>
+ <div style={{ textAlign: "center" }}>
+ <strong>{contractTerms.summary}</strong>
+ </div>
+ {totalFees ? (
+ <i18n.Translate>
+ The total price is <span>{amount} </span>
+ (plus <span>{renderAmount(totalFees)}</span> fees).
+ </i18n.Translate>
+ ) : (
+ <i18n.Translate>
+ The total price is <span>{amount}</span>.
+ </i18n.Translate>
+ )}
+ </p>
+
+ {insufficientBalance ? (
+ <div>
+ <p style={{ color: "red", fontWeight: "bold" }}>
+ Unable to pay: Your balance is insufficient.
+ </p>
+ </div>
+ ) : null}
+
+ {payErrMsg ? (
+ <div>
+ <p>Payment failed: {payErrMsg}</p>
+ <button
+ class="pure-button button-success"
+ onClick={onClick}
+ >
+ {i18n.str`Retry`}
+ </button>
+ </div>
+ ) : (
+ <div>
+ <ProgressButton
+ isLoading={loading}
+ disabled={insufficientBalance}
+ onClick={onClick}
+ >
+ {i18n.str`Confirm payment`}
+ </ProgressButton>
+ </div>
+ )}
+ </div>
+ </article>
+ </section>
+
+
+} \ No newline at end of file