summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/wallet/Pay.tsx
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2021-08-13 18:04:05 -0300
committerSebastian <sebasjm@gmail.com>2021-08-13 18:04:30 -0300
commite9bb85a212dbd9b86875e89a0aca5d805e2ad61b (patch)
tree7fb2f9f28fc382d7348cd45cb730b302217099c7 /packages/taler-wallet-webextension/src/wallet/Pay.tsx
parenteb553be84163946e4ffa5b2a4dfaa2029aebc534 (diff)
downloadwallet-core-e9bb85a212dbd9b86875e89a0aca5d805e2ad61b.tar.gz
wallet-core-e9bb85a212dbd9b86875e89a0aca5d805e2ad61b.tar.bz2
wallet-core-e9bb85a212dbd9b86875e89a0aca5d805e2ad61b.zip
new wallet UI and more tests
Diffstat (limited to 'packages/taler-wallet-webextension/src/wallet/Pay.tsx')
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Pay.tsx287
1 files changed, 158 insertions, 129 deletions
diff --git a/packages/taler-wallet-webextension/src/wallet/Pay.tsx b/packages/taler-wallet-webextension/src/wallet/Pay.tsx
index bd06656c7..a5849bb28 100644
--- a/packages/taler-wallet-webextension/src/wallet/Pay.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Pay.tsx
@@ -29,7 +29,7 @@ import * as wxApi from "../wxApi";
import { useState, useEffect } from "preact/hooks";
-import { getJsonI18n, i18n } from "@gnu-taler/taler-util";
+import { ConfirmPayResultDone, getJsonI18n, i18n } from "@gnu-taler/taler-util";
import {
PreparePayResult,
ConfirmPayResult,
@@ -45,13 +45,54 @@ 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>("");
- const [numTries, setNumTries] = useState(0);
- const [loading, setLoading] = useState(false);
- let totalFees: AmountJson | undefined = undefined;
useEffect(() => {
if (!talerPayUri) return;
@@ -60,53 +101,67 @@ export function PayPage({ talerPayUri }: Props): JSX.Element {
setPayStatus(p);
};
doFetch();
- }, [numTries, talerPayUri]);
+ }, [talerPayUri]);
if (!talerPayUri) {
return <span>missing pay uri</span>
}
-
+
if (!payStatus) {
return <span>Loading payment information ...</span>;
}
- 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) {
+ 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 (
- <span>
- You have already paid for this article. Click{" "}
- <a href={fulfillmentUrl} target="_bank" rel="external">here</a> to view it again.
- </span>
+ <div>
+ <p>Payment succeeded.</p>
+ <p>{msg}</p>
+ </div>
);
} else {
- <span>
- You have already paid for this article:{" "}
- <em>
- {payStatus.contractTerms.fulfillment_message ?? "no message given"}
- </em>
- </span>;
+ 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>
@@ -115,6 +170,18 @@ export function PayPage({ talerPayUri }: Props): JSX.Element {
);
}
+ 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>;
@@ -126,99 +193,61 @@ export function PayPage({ talerPayUri }: Props): JSX.Element {
<strong>{renderAmount(Amounts.parseOrThrow(contractTerms.amount))}</strong>
);
- const doPayment = async (): Promise<void> => {
- 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 (
- <div>
- <p>Payment succeeded.</p>
- <p>{msg}</p>
- </div>
- );
- } else {
- return <span>Redirecting ...</span>;
- }
- }
-
- return (
- <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 ? (
+ return <section class="main">
+ <h1>GNU Taler Wallet</h1>
+ <article class="fade">
+ <div>
+ <p>
<i18n.Translate>
- The total price is <span>{amount} </span>
- (plus <span>{renderAmount(totalFees)}</span> fees).
- </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>
) : (
- <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={() => doPayment()}
- >
- {i18n.str`Retry`}
- </button>
- </div>
- ) : (
- <div>
- <ProgressButton
- isLoading={loading}
- disabled={insufficientBalance}
- onClick={() => doPayment()}
- >
- {i18n.str`Confirm payment`}
- </ProgressButton>
- </div>
- )}
- </div>
- );
-}
-
+ <div>
+ <ProgressButton
+ isLoading={loading}
+ disabled={insufficientBalance}
+ onClick={onClick}
+ >
+ {i18n.str`Confirm payment`}
+ </ProgressButton>
+ </div>
+ )}
+ </div>
+ </article>
+ </section>
+
+
+} \ No newline at end of file