From 315b167bee240e625beea731df6472a971b46cb2 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 17 Sep 2021 15:48:33 -0300 Subject: issue #5860 --- packages/taler-wallet-webextension/package.json | 1 + .../src/components/QR.tsx | 37 ++++++ .../src/components/styled/index.tsx | 8 +- .../src/cta/Pay.stories.tsx | 7 ++ packages/taler-wallet-webextension/src/cta/Pay.tsx | 136 +++++++++++---------- .../taler-wallet-webextension/src/cta/Withdraw.tsx | 133 ++++++++++---------- 6 files changed, 186 insertions(+), 136 deletions(-) create mode 100644 packages/taler-wallet-webextension/src/components/QR.tsx (limited to 'packages/taler-wallet-webextension') diff --git a/packages/taler-wallet-webextension/package.json b/packages/taler-wallet-webextension/package.json index 028a5c660..4023e4ebd 100644 --- a/packages/taler-wallet-webextension/package.json +++ b/packages/taler-wallet-webextension/package.json @@ -22,6 +22,7 @@ "history": "4.10.1", "preact": "^10.5.13", "preact-router": "^3.2.1", + "qrcode-generator": "^1.4.4", "tslib": "^2.1.0" }, "devDependencies": { diff --git a/packages/taler-wallet-webextension/src/components/QR.tsx b/packages/taler-wallet-webextension/src/components/QR.tsx new file mode 100644 index 000000000..8e3f69295 --- /dev/null +++ b/packages/taler-wallet-webextension/src/components/QR.tsx @@ -0,0 +1,37 @@ +/* + This file is part of GNU Taler + (C) 2021 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 { h, VNode } from "preact"; + import { useEffect, useRef } from "preact/hooks"; + import qrcode from "qrcode-generator"; + + export function QR({ text }: { text: string; }):VNode { + const divRef = useRef(null); + useEffect(() => { + if (!divRef.current) return + const qr = qrcode(0, 'L'); + qr.addData(text); + qr.make(); + divRef.current.innerHTML = qr.createSvgTag({ + scalable: true, + }); + }); + + return
+
+
; + } + \ No newline at end of file diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx b/packages/taler-wallet-webextension/src/components/styled/index.tsx index f7945569e..a46f38ee9 100644 --- a/packages/taler-wallet-webextension/src/components/styled/index.tsx +++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx @@ -29,10 +29,11 @@ export const PaymentStatus = styled.div<{ color: string }>` export const WalletAction = styled.section` display: flex; + text-align: center; flex-direction: column; justify-content: space-between; align-items: center; - max-width: 50%; + /* max-width: 50%; */ margin: auto; height: 100%; @@ -42,6 +43,10 @@ export const WalletAction = styled.section` } section { margin-bottom: 2em; + & button { + margin-right: 8px; + margin-left: 8px; + } } ` export const WalletActionOld = styled.section` @@ -628,6 +633,7 @@ export const TermsOfService = styled.div` display: flex; flex-direction: column; text-align: left; + max-width: 500px; & > header { text-align: center; diff --git a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx b/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx index 38e3d0f35..9a997687f 100644 --- a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx @@ -33,6 +33,7 @@ export default { export const InsufficientBalance = createExample(TestedComponent, { payStatus: { status: PreparePayResultType.InsufficientBalance, + noncePriv: '', proposalId: "proposal1234", contractTerms: { merchant: { @@ -45,15 +46,19 @@ export const InsufficientBalance = createExample(TestedComponent, { }); export const PaymentPossible = createExample(TestedComponent, { + uri: 'taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0', payStatus: { status: PreparePayResultType.PaymentPossible, amountEffective: 'USD:10', amountRaw: 'USD:10', + noncePriv: '', contractTerms: { + nonce: '123213123', merchant: { name: 'someone' }, amount: 'USD:10', + summary: 'some beers', } as Partial as any, contractTermsHash: '123456', proposalId: 'proposal1234' @@ -65,6 +70,7 @@ export const AlreadyConfirmedWithFullfilment = createExample(TestedComponent, { status: PreparePayResultType.AlreadyConfirmed, amountEffective: 'USD:10', amountRaw: 'USD:10', + noncePriv: '', contractTerms: { merchant: { name: 'someone' @@ -82,6 +88,7 @@ export const AlreadyConfirmedWithoutFullfilment = createExample(TestedComponent, payStatus: { status: PreparePayResultType.AlreadyConfirmed, amountEffective: 'USD:10', + noncePriv: '', amountRaw: 'USD:10', contractTerms: { merchant: { diff --git a/packages/taler-wallet-webextension/src/cta/Pay.tsx b/packages/taler-wallet-webextension/src/cta/Pay.tsx index 758bc4b54..e85cd60a1 100644 --- a/packages/taler-wallet-webextension/src/cta/Pay.tsx +++ b/packages/taler-wallet-webextension/src/cta/Pay.tsx @@ -29,7 +29,7 @@ import * as wxApi from "../wxApi"; import { useState, useEffect } from "preact/hooks"; -import { ConfirmPayResultDone, getJsonI18n, i18n } from "@gnu-taler/taler-util"; +import { AmountLike, ConfirmPayResultDone, getJsonI18n, i18n } from "@gnu-taler/taler-util"; import { PreparePayResult, ConfirmPayResult, @@ -39,7 +39,11 @@ import { ContractTerms, ConfirmPayResultType, } from "@gnu-taler/taler-util"; -import { JSX, VNode, h } from "preact"; +import { JSX, VNode, h, Fragment } from "preact"; +import { ButtonSuccess, LinkSuccess, WalletAction } from "../components/styled"; +import { LogoHeader } from "../components/LogoHeader"; +import { Part } from "../components/Part"; +import { QR } from "../components/QR"; interface Props { talerPayUri?: string @@ -143,17 +147,17 @@ export function PayPage({ talerPayUri }: Props): JSX.Element { } - return ; + return ; } export interface PaymentRequestViewProps { payStatus: PreparePayResult; onClick: () => void; payErrMsg?: string; - + uri: string; } -export function PaymentRequestView({ payStatus, onClick, payErrMsg }: PaymentRequestViewProps) { - let totalFees: AmountJson | undefined = undefined; +export function PaymentRequestView({ uri, payStatus, onClick, payErrMsg }: PaymentRequestViewProps) { + let totalFees: AmountJson = Amounts.getZero(payStatus.amountRaw); let insufficientBalance = false; const [loading, setLoading] = useState(false); const contractTerms: ContractTerms = payStatus.contractTerms; @@ -174,6 +178,7 @@ export function PaymentRequestView({ payStatus, onClick, payErrMsg }: PaymentReq if (payStatus.status == PreparePayResultType.InsufficientBalance) { insufficientBalance = true; + return
no te alcanza
} if (payStatus.status === PreparePayResultType.PaymentPossible) { @@ -191,65 +196,62 @@ export function PaymentRequestView({ payStatus, onClick, payErrMsg }: PaymentReq merchantName = (pub: {contractTerms.merchant_pub}); } - const amount = ( - {renderAmount(Amounts.parseOrThrow(contractTerms.amount))} - ); - - return
-

GNU Taler Wallet

-
-
-

- - 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}

- -
- ) : ( -
- - {i18n.str`Confirm payment`} - -
- )} -
-
-
- + const [showQR, setShowQR] = useState(false) + const privateUri = `${uri}&n=${payStatus.noncePriv}` + return + +

+ {i18n.str`Digital cash payment`} +

+
+ + + {Amounts.isNonZero(totalFees) && } + + + {contractTerms.order_id && } +
+ {showQR &&
+ + or click here to pay with a installed wallet +
} +
+ {payErrMsg ? ( +
+

Payment failed: {payErrMsg}

+ +
+ ) : ( + + + setShowQR(qr => !qr)} + > + {!showQR ? i18n.str`Complete with mobile wallet` : i18n.str`Hide QR`} + + onReview(true)} + > + {i18n.str`Confirm payment`} + + + )} + +
+
+} -} \ No newline at end of file +function amountToString(text: AmountLike) { + const aj = Amounts.jsonifyAmount(text) + const amount = Amounts.stringifyValue(aj) + return `${amount} ${aj.currency}` +} diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx index ac25bcd15..304313a9e 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx +++ b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx @@ -80,20 +80,18 @@ export function View({ details, amount, onWithdraw, terms, reviewing, onReview, const needsReview = terms.status === 'changed' || terms.status === 'new' return ( - +

{i18n.str`Digital cash withdrawal`}

-
- - - {Amounts.isNonZero(details.withdrawFee) && - - } - -
+ + + {Amounts.isNonZero(details.withdrawFee) && + + } +
{!reviewing &&
@@ -132,63 +130,50 @@ export function View({ details, amount, onWithdraw, terms, reviewing, onReview, } {(reviewing || accepted) &&
-
- { - onAccept(!accepted) - onReview(false) - }} - /> -
+ { + onAccept(!accepted) + onReview(false) + }} + />
}
{terms.status === 'new' && !accepted && -
- onReview(true)} - > - {i18n.str`Review exchange terms of service`} - -
+ onReview(true)} + > + {i18n.str`Review exchange terms of service`} + } {terms.status === 'changed' && !accepted && -
- onReview(true)} - > - {i18n.str`Review new version of terms of service`} - -
+ onReview(true)} + > + {i18n.str`Review new version of terms of service`} + } {(terms.status === 'accepted' || (needsReview && accepted)) && -
- - {i18n.str`Confirm withdrawal`} - -
+ + {i18n.str`Confirm withdrawal`} + } {terms.status === 'notfound' && -
- - {i18n.str`Exchange doesn't have terms of service`} - -
+ + {i18n.str`Exchange doesn't have terms of service`} + }
@@ -231,12 +216,16 @@ export function WithdrawPage({ talerWithdrawUri, ...rest }: Props): JSX.Element useEffect(() => { async function fetchData() { if (!uriInfo || !uriInfo.defaultExchangeBaseUrl) return - const res = await getExchangeWithdrawalInfo({ - exchangeBaseUrl: uriInfo.defaultExchangeBaseUrl, - amount: Amounts.parseOrThrow(uriInfo.amount), - tosAcceptedFormat: ['text/json', 'text/xml', 'text/pdf'] - }) - setDetails(res) + try { + const res = await getExchangeWithdrawalInfo({ + exchangeBaseUrl: uriInfo.defaultExchangeBaseUrl, + amount: Amounts.parseOrThrow(uriInfo.amount), + tosAcceptedFormat: ['text/json', 'text/xml', 'text/pdf'] + }) + setDetails(res) + } catch (e) { + setError(true) + } } fetchData() }, [uriInfo]) @@ -249,8 +238,12 @@ export function WithdrawPage({ talerWithdrawUri, ...rest }: Props): JSX.Element if (!details) { throw Error("can't accept, no exchange selected"); } - await setExchangeTosAccepted(details.exchangeDetails.exchangeBaseUrl, details.tosRequested?.tosEtag) - setAccepted(true) + try { + await setExchangeTosAccepted(details.exchangeDetails.exchangeBaseUrl, details.tosRequested?.tosEtag) + setAccepted(true) + } catch (e) { + setError(true) + } } const onWithdraw = async (): Promise => { @@ -259,10 +252,14 @@ export function WithdrawPage({ talerWithdrawUri, ...rest }: Props): JSX.Element } setConfirmed(true) console.log("accepting exchange", details.exchangeInfo.baseUrl); - const res = await acceptWithdrawal(talerWithdrawUri, details.exchangeInfo.baseUrl); - console.log("accept withdrawal response", res); - if (res.confirmTransferUrl) { - document.location.href = res.confirmTransferUrl; + try { + const res = await acceptWithdrawal(talerWithdrawUri, details.exchangeInfo.baseUrl); + console.log("accept withdrawal response", res); + if (res.confirmTransferUrl) { + document.location.href = res.confirmTransferUrl; + } + } catch (e) { + setConfirmed(false) } }; @@ -288,7 +285,7 @@ export function WithdrawPage({ talerWithdrawUri, ...rest }: Props): JSX.Element } catch (e) { console.log(e) debugger; - } + } } } -- cgit v1.2.3