diff options
author | Sebastian <sebasjm@gmail.com> | 2021-11-15 11:18:58 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2021-11-15 11:18:58 -0300 |
commit | 1d4815c66c395f4fcc86c30e20f3d005e3cb9ff5 (patch) | |
tree | 99e8241a5eb5af4d752be93a460004bc0c6255aa /packages/taler-wallet-webextension/src/cta | |
parent | 9692f589c687a2ba39a705ca4238cf123f444c61 (diff) | |
download | wallet-core-1d4815c66c395f4fcc86c30e20f3d005e3cb9ff5.tar.xz |
prettier
Diffstat (limited to 'packages/taler-wallet-webextension/src/cta')
11 files changed, 1035 insertions, 771 deletions
diff --git a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx b/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx index 622e7950f..c2d360d3b 100644 --- a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx @@ -15,150 +15,156 @@ */ /** -* -* @author Sebastian Javier Marchano (sebasjm) -*/ + * + * @author Sebastian Javier Marchano (sebasjm) + */ -import { ContractTerms, PreparePayResultType } from '@gnu-taler/taler-util'; -import { createExample } from '../test-utils'; -import { PaymentRequestView as TestedComponent } from './Pay'; +import { ContractTerms, PreparePayResultType } from "@gnu-taler/taler-util"; +import { createExample } from "../test-utils"; +import { PaymentRequestView as TestedComponent } from "./Pay"; export default { - title: 'cta/pay', + title: "cta/pay", component: TestedComponent, - argTypes: { - }, + argTypes: {}, }; export const NoBalance = createExample(TestedComponent, { payStatus: { status: PreparePayResultType.InsufficientBalance, - noncePriv: '', + noncePriv: "", proposalId: "proposal1234", - contractTerms: { + contractTerms: ({ merchant: { - name: 'someone' + name: "someone", }, - summary: 'some beers', - amount: 'USD:10', - } as Partial<ContractTerms> as any, - amountRaw: 'USD:10', - } + summary: "some beers", + amount: "USD:10", + } as Partial<ContractTerms>) as any, + amountRaw: "USD:10", + }, }); export const NoEnoughBalance = createExample(TestedComponent, { payStatus: { status: PreparePayResultType.InsufficientBalance, - noncePriv: '', + noncePriv: "", proposalId: "proposal1234", - contractTerms: { + contractTerms: ({ merchant: { - name: 'someone' + name: "someone", }, - summary: 'some beers', - amount: 'USD:10', - } as Partial<ContractTerms> as any, - amountRaw: 'USD:10', + summary: "some beers", + amount: "USD:10", + } as Partial<ContractTerms>) as any, + amountRaw: "USD:10", }, balance: { - currency: 'USD', + currency: "USD", fraction: 40000000, - value: 9 - } + value: 9, + }, }); export const PaymentPossible = createExample(TestedComponent, { - uri: 'taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0', + 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', + amountEffective: "USD:10", + amountRaw: "USD:10", + noncePriv: "", + contractTerms: ({ + nonce: "123213123", merchant: { - name: 'someone' + name: "someone", }, - amount: 'USD:10', - summary: 'some beers', - } as Partial<ContractTerms> as any, - contractTermsHash: '123456', - proposalId: 'proposal1234' - } + amount: "USD:10", + summary: "some beers", + } as Partial<ContractTerms>) as any, + contractTermsHash: "123456", + proposalId: "proposal1234", + }, }); export const PaymentPossibleWithFee = createExample(TestedComponent, { - uri: 'taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0', + uri: + "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0", payStatus: { status: PreparePayResultType.PaymentPossible, - amountEffective: 'USD:10.20', - amountRaw: 'USD:10', - noncePriv: '', - contractTerms: { - nonce: '123213123', + amountEffective: "USD:10.20", + amountRaw: "USD:10", + noncePriv: "", + contractTerms: ({ + nonce: "123213123", merchant: { - name: 'someone' + name: "someone", }, - amount: 'USD:10', - summary: 'some beers', - } as Partial<ContractTerms> as any, - contractTermsHash: '123456', - proposalId: 'proposal1234' - } + amount: "USD:10", + summary: "some beers", + } as Partial<ContractTerms>) as any, + contractTermsHash: "123456", + proposalId: "proposal1234", + }, }); export const AlreadyConfirmedWithFullfilment = createExample(TestedComponent, { payStatus: { status: PreparePayResultType.AlreadyConfirmed, - amountEffective: 'USD:10', - amountRaw: 'USD:10', - contractTerms: { + amountEffective: "USD:10", + amountRaw: "USD:10", + contractTerms: ({ merchant: { - name: 'someone' + name: "someone", }, - fulfillment_message: 'congratulations! you are looking at the fulfillment message! ', - summary: 'some beers', - amount: 'USD:10', - } as Partial<ContractTerms> as any, - contractTermsHash: '123456', - proposalId: 'proposal1234', + fulfillment_message: + "congratulations! you are looking at the fulfillment message! ", + summary: "some beers", + amount: "USD:10", + } as Partial<ContractTerms>) as any, + contractTermsHash: "123456", + proposalId: "proposal1234", paid: false, - } + }, }); -export const AlreadyConfirmedWithoutFullfilment = createExample(TestedComponent, { - payStatus: { - status: PreparePayResultType.AlreadyConfirmed, - amountEffective: 'USD:10', - amountRaw: 'USD:10', - contractTerms: { - merchant: { - name: 'someone' - }, - summary: 'some beers', - amount: 'USD:10', - } as Partial<ContractTerms> as any, - contractTermsHash: '123456', - proposalId: 'proposal1234', - paid: false, - } -}); +export const AlreadyConfirmedWithoutFullfilment = createExample( + TestedComponent, + { + payStatus: { + status: PreparePayResultType.AlreadyConfirmed, + amountEffective: "USD:10", + amountRaw: "USD:10", + contractTerms: ({ + merchant: { + name: "someone", + }, + summary: "some beers", + amount: "USD:10", + } as Partial<ContractTerms>) as any, + contractTermsHash: "123456", + proposalId: "proposal1234", + paid: false, + }, + }, +); export const AlreadyPaid = createExample(TestedComponent, { payStatus: { status: PreparePayResultType.AlreadyConfirmed, - amountEffective: 'USD:10', - amountRaw: 'USD:10', - contractTerms: { + amountEffective: "USD:10", + amountRaw: "USD:10", + contractTerms: ({ merchant: { - name: 'someone' + name: "someone", }, - fulfillment_message: 'congratulations! you are looking at the fulfillment message! ', - summary: 'some beers', - amount: 'USD:10', - } as Partial<ContractTerms> as any, - contractTermsHash: '123456', - proposalId: 'proposal1234', + fulfillment_message: + "congratulations! you are looking at the fulfillment message! ", + summary: "some beers", + amount: "USD:10", + } as Partial<ContractTerms>) as any, + contractTermsHash: "123456", + proposalId: "proposal1234", paid: true, - } + }, }); diff --git a/packages/taler-wallet-webextension/src/cta/Pay.tsx b/packages/taler-wallet-webextension/src/cta/Pay.tsx index 675b14ff9..1023013d2 100644 --- a/packages/taler-wallet-webextension/src/cta/Pay.tsx +++ b/packages/taler-wallet-webextension/src/cta/Pay.tsx @@ -24,18 +24,36 @@ */ // import * as i18n from "../i18n"; -import { AmountJson, AmountLike, Amounts, ConfirmPayResult, ConfirmPayResultDone, ConfirmPayResultType, ContractTerms, getJsonI18n, i18n, PreparePayResult, PreparePayResultType } from "@gnu-taler/taler-util"; -import { Fragment, JSX, VNode } from "preact"; +import { + AmountJson, + AmountLike, + Amounts, + ConfirmPayResult, + ConfirmPayResultDone, + ConfirmPayResultType, + ContractTerms, + i18n, + PreparePayResult, + PreparePayResultType, +} from "@gnu-taler/taler-util"; +import { h, Fragment, JSX, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; import { LogoHeader } from "../components/LogoHeader"; import { Part } from "../components/Part"; import { QR } from "../components/QR"; -import { ButtonSuccess, ErrorBox, LinkSuccess, SuccessBox, WalletAction, WarningBox } from "../components/styled"; +import { + ButtonSuccess, + ErrorBox, + LinkSuccess, + SuccessBox, + WalletAction, + WarningBox, +} from "../components/styled"; import { useBalances } from "../hooks/useBalances"; import * as wxApi from "../wxApi"; interface Props { - talerPayUri?: string + talerPayUri?: string; } // export function AlreadyPaid({ payStatus }: { payStatus: PreparePayResult }) { @@ -64,7 +82,9 @@ interface Props { // </section> // } -const doPayment = async (payStatus: PreparePayResult): Promise<ConfirmPayResultDone> => { +const doPayment = async ( + payStatus: PreparePayResult, +): Promise<ConfirmPayResultDone> => { if (payStatus.status !== "payment-possible") { throw Error(`invalid state: ${payStatus.status}`); } @@ -80,18 +100,29 @@ const doPayment = async (payStatus: PreparePayResult): Promise<ConfirmPayResultD return res; }; - - export function PayPage({ talerPayUri }: Props): JSX.Element { - const [payStatus, setPayStatus] = useState<PreparePayResult | undefined>(undefined); - const [payResult, setPayResult] = useState<ConfirmPayResult | undefined>(undefined); + const [payStatus, setPayStatus] = useState<PreparePayResult | undefined>( + undefined, + ); + const [payResult, setPayResult] = useState<ConfirmPayResult | undefined>( + undefined, + ); const [payErrMsg, setPayErrMsg] = useState<string | undefined>(undefined); - const balance = useBalances() - const balanceWithoutError = balance?.hasError ? [] : (balance?.response.balances || []) + const balance = useBalances(); + const balanceWithoutError = balance?.hasError + ? [] + : balance?.response.balances || []; - const foundBalance = balanceWithoutError.find(b => payStatus && Amounts.parseOrThrow(b.available).currency === Amounts.parseOrThrow(payStatus?.amountRaw).currency) - const foundAmount = foundBalance ? Amounts.parseOrThrow(foundBalance.available) : undefined + const foundBalance = balanceWithoutError.find( + (b) => + payStatus && + Amounts.parseOrThrow(b.available).currency === + Amounts.parseOrThrow(payStatus?.amountRaw).currency, + ); + const foundAmount = foundBalance + ? Amounts.parseOrThrow(foundBalance.available) + : undefined; useEffect(() => { if (!talerPayUri) return; @@ -101,7 +132,7 @@ export function PayPage({ talerPayUri }: Props): JSX.Element { setPayStatus(p); } catch (e) { if (e instanceof Error) { - setPayErrMsg(e.message) + setPayErrMsg(e.message); } } }; @@ -109,30 +140,28 @@ export function PayPage({ talerPayUri }: Props): JSX.Element { }, [talerPayUri]); if (!talerPayUri) { - return <span>missing pay uri</span> + return <span>missing pay uri</span>; } if (!payStatus) { if (payErrMsg) { - return <WalletAction> - <LogoHeader /> - <h2> - {i18n.str`Digital cash payment`} - </h2> - <section> - <p>Could not get the payment information for this order</p> - <ErrorBox> - {payErrMsg} - </ErrorBox> - </section> - </WalletAction> + return ( + <WalletAction> + <LogoHeader /> + <h2>{i18n.str`Digital cash payment`}</h2> + <section> + <p>Could not get the payment information for this order</p> + <ErrorBox>{payErrMsg}</ErrorBox> + </section> + </WalletAction> + ); } return <span>Loading payment information ...</span>; } const onClick = async () => { try { - const res = await doPayment(payStatus) + const res = await doPayment(payStatus); setPayResult(res); } catch (e) { console.error(e); @@ -140,13 +169,18 @@ export function PayPage({ talerPayUri }: Props): JSX.Element { setPayErrMsg(e.message); } } + }; - } - - return <PaymentRequestView uri={talerPayUri} - payStatus={payStatus} payResult={payResult} - onClick={onClick} payErrMsg={payErrMsg} - balance={foundAmount} />; + return ( + <PaymentRequestView + uri={talerPayUri} + payStatus={payStatus} + payResult={payResult} + onClick={onClick} + payErrMsg={payErrMsg} + balance={foundAmount} + /> + ); } export interface PaymentRequestViewProps { @@ -157,7 +191,14 @@ export interface PaymentRequestViewProps { uri: string; balance: AmountJson | undefined; } -export function PaymentRequestView({ uri, payStatus, payResult, onClick, payErrMsg, balance }: PaymentRequestViewProps) { +export function PaymentRequestView({ + uri, + payStatus, + payResult, + onClick, + payErrMsg, + balance, +}: PaymentRequestViewProps) { let totalFees: AmountJson = Amounts.getZero(payStatus.amountRaw); const contractTerms: ContractTerms = payStatus.contractTerms; @@ -185,116 +226,174 @@ export function PaymentRequestView({ uri, payStatus, payResult, onClick, payErrM } function Alternative() { - const [showQR, setShowQR] = useState<boolean>(false) - const privateUri = payStatus.status !== PreparePayResultType.AlreadyConfirmed ? `${uri}&n=${payStatus.noncePriv}` : uri - return <section> - <LinkSuccess upperCased onClick={() => setShowQR(qr => !qr)}> - {!showQR ? i18n.str`Pay with a mobile phone` : i18n.str`Hide QR`} - </LinkSuccess> - {showQR && <div> - <QR text={privateUri} /> - Scan the QR code or <a href={privateUri}>click here</a> - </div>} - </section> + const [showQR, setShowQR] = useState<boolean>(false); + const privateUri = + payStatus.status !== PreparePayResultType.AlreadyConfirmed + ? `${uri}&n=${payStatus.noncePriv}` + : uri; + return ( + <section> + <LinkSuccess upperCased onClick={() => setShowQR((qr) => !qr)}> + {!showQR ? i18n.str`Pay with a mobile phone` : i18n.str`Hide QR`} + </LinkSuccess> + {showQR && ( + <div> + <QR text={privateUri} /> + Scan the QR code or <a href={privateUri}>click here</a> + </div> + )} + </section> + ); } function ButtonsSection() { if (payResult) { if (payResult.type === ConfirmPayResultType.Pending) { - return <section> - <div> - <p>Processing...</p> - </div> - </section> + return ( + <section> + <div> + <p>Processing...</p> + </div> + </section> + ); } - return null + return null; } if (payErrMsg) { - return <section> - <div> - <p>Payment failed: {payErrMsg}</p> - <button class="pure-button button-success" onClick={onClick} > - {i18n.str`Retry`} - </button> - </div> - </section> - } - if (payStatus.status === PreparePayResultType.PaymentPossible) { - return <Fragment> + return ( <section> - <ButtonSuccess upperCased onClick={onClick}> - {i18n.str`Pay`} {amountToString(payStatus.amountEffective)} - </ButtonSuccess> + <div> + <p>Payment failed: {payErrMsg}</p> + <button class="pure-button button-success" onClick={onClick}> + {i18n.str`Retry`} + </button> + </div> </section> - <Alternative /> - </Fragment> + ); + } + if (payStatus.status === PreparePayResultType.PaymentPossible) { + return ( + <Fragment> + <section> + <ButtonSuccess upperCased onClick={onClick}> + {i18n.str`Pay`} {amountToString(payStatus.amountEffective)} + </ButtonSuccess> + </section> + <Alternative /> + </Fragment> + ); } if (payStatus.status === PreparePayResultType.InsufficientBalance) { - return <Fragment> - <section> - {balance ? <WarningBox> - Your balance of {amountToString(balance)} is not enough to pay for this purchase - </WarningBox> : <WarningBox> - Your balance is not enough to pay for this purchase. - </WarningBox>} - </section> - <section> - <ButtonSuccess upperCased> - {i18n.str`Withdraw digital cash`} - </ButtonSuccess> - </section> - <Alternative /> - </Fragment> + return ( + <Fragment> + <section> + {balance ? ( + <WarningBox> + Your balance of {amountToString(balance)} is not enough to pay + for this purchase + </WarningBox> + ) : ( + <WarningBox> + Your balance is not enough to pay for this purchase. + </WarningBox> + )} + </section> + <section> + <ButtonSuccess upperCased> + {i18n.str`Withdraw digital cash`} + </ButtonSuccess> + </section> + <Alternative /> + </Fragment> + ); } if (payStatus.status === PreparePayResultType.AlreadyConfirmed) { - return <Fragment> - <section> - {payStatus.paid && contractTerms.fulfillment_message && <Part title="Merchant message" text={contractTerms.fulfillment_message} kind='neutral' />} - </section> - {!payStatus.paid && <Alternative />} - </Fragment> + return ( + <Fragment> + <section> + {payStatus.paid && contractTerms.fulfillment_message && ( + <Part + title="Merchant message" + text={contractTerms.fulfillment_message} + kind="neutral" + /> + )} + </section> + {!payStatus.paid && <Alternative />} + </Fragment> + ); } - return <span /> + return <span />; } - return <WalletAction> - <LogoHeader /> - - <h2> - {i18n.str`Digital cash payment`} - </h2> - {payStatus.status === PreparePayResultType.AlreadyConfirmed && - (payStatus.paid ? <SuccessBox> Already paid </SuccessBox> : <WarningBox> Already claimed </WarningBox>) - } - {payResult && payResult.type === ConfirmPayResultType.Done && ( - <SuccessBox> - <h3>Payment complete</h3> - <p>{!payResult.contractTerms.fulfillment_message ? - "You will now be sent back to the merchant you came from." : - payResult.contractTerms.fulfillment_message - }</p> - </SuccessBox> - )} - <section> - {payStatus.status !== PreparePayResultType.InsufficientBalance && Amounts.isNonZero(totalFees) && - <Part big title="Total to pay" text={amountToString(payStatus.amountEffective)} kind='negative' /> - } - <Part big title="Purchase amount" text={amountToString(payStatus.amountRaw)} kind='neutral' /> - {Amounts.isNonZero(totalFees) && <Fragment> - <Part big title="Fee" text={amountToString(totalFees)} kind='negative' /> - </Fragment> - } - <Part title="Merchant" text={contractTerms.merchant.name} kind='neutral' /> - <Part title="Purchase" text={contractTerms.summary} kind='neutral' /> - {contractTerms.order_id && <Part title="Receipt" text={`#${contractTerms.order_id}`} kind='neutral' />} - </section> - <ButtonsSection /> + return ( + <WalletAction> + <LogoHeader /> - </WalletAction> + <h2>{i18n.str`Digital cash payment`}</h2> + {payStatus.status === PreparePayResultType.AlreadyConfirmed && + (payStatus.paid ? ( + <SuccessBox> Already paid </SuccessBox> + ) : ( + <WarningBox> Already claimed </WarningBox> + ))} + {payResult && payResult.type === ConfirmPayResultType.Done && ( + <SuccessBox> + <h3>Payment complete</h3> + <p> + {!payResult.contractTerms.fulfillment_message + ? "You will now be sent back to the merchant you came from." + : payResult.contractTerms.fulfillment_message} + </p> + </SuccessBox> + )} + <section> + {payStatus.status !== PreparePayResultType.InsufficientBalance && + Amounts.isNonZero(totalFees) && ( + <Part + big + title="Total to pay" + text={amountToString(payStatus.amountEffective)} + kind="negative" + /> + )} + <Part + big + title="Purchase amount" + text={amountToString(payStatus.amountRaw)} + kind="neutral" + /> + {Amounts.isNonZero(totalFees) && ( + <Fragment> + <Part + big + title="Fee" + text={amountToString(totalFees)} + kind="negative" + /> + </Fragment> + )} + <Part + title="Merchant" + text={contractTerms.merchant.name} + kind="neutral" + /> + <Part title="Purchase" text={contractTerms.summary} kind="neutral" /> + {contractTerms.order_id && ( + <Part + title="Receipt" + text={`#${contractTerms.order_id}`} + kind="neutral" + /> + )} + </section> + <ButtonsSection /> + </WalletAction> + ); } function amountToString(text: AmountLike) { - const aj = Amounts.jsonifyAmount(text) - const amount = Amounts.stringifyValue(aj, 2) - return `${amount} ${aj.currency}` + const aj = Amounts.jsonifyAmount(text); + const amount = Amounts.stringifyValue(aj, 2); + return `${amount} ${aj.currency}`; } diff --git a/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx b/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx index 88e714cb7..a0abcea58 100644 --- a/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx @@ -15,63 +15,61 @@ */ /** -* -* @author Sebastian Javier Marchano (sebasjm) -*/ - -import { OrderShortInfo } from '@gnu-taler/taler-util'; -import { createExample } from '../test-utils'; -import { View as TestedComponent } from './Refund'; + * + * @author Sebastian Javier Marchano (sebasjm) + */ +import { OrderShortInfo } from "@gnu-taler/taler-util"; +import { createExample } from "../test-utils"; +import { View as TestedComponent } from "./Refund"; export default { - title: 'cta/refund', + title: "cta/refund", component: TestedComponent, - argTypes: { - }, + argTypes: {}, }; export const Complete = createExample(TestedComponent, { applyResult: { - amountEffectivePaid: 'USD:10', - amountRefundGone: 'USD:0', - amountRefundGranted: 'USD:2', - contractTermsHash: 'QWEASDZXC', - info: { - summary: 'tasty cold beer', - contractTermsHash: 'QWEASDZXC', - } as Partial<OrderShortInfo> as any, + amountEffectivePaid: "USD:10", + amountRefundGone: "USD:0", + amountRefundGranted: "USD:2", + contractTermsHash: "QWEASDZXC", + info: ({ + summary: "tasty cold beer", + contractTermsHash: "QWEASDZXC", + } as Partial<OrderShortInfo>) as any, pendingAtExchange: false, proposalId: "proposal123", - } + }, }); export const Partial = createExample(TestedComponent, { applyResult: { - amountEffectivePaid: 'USD:10', - amountRefundGone: 'USD:1', - amountRefundGranted: 'USD:2', - contractTermsHash: 'QWEASDZXC', - info: { - summary: 'tasty cold beer', - contractTermsHash: 'QWEASDZXC', - } as Partial<OrderShortInfo> as any, + amountEffectivePaid: "USD:10", + amountRefundGone: "USD:1", + amountRefundGranted: "USD:2", + contractTermsHash: "QWEASDZXC", + info: ({ + summary: "tasty cold beer", + contractTermsHash: "QWEASDZXC", + } as Partial<OrderShortInfo>) as any, pendingAtExchange: false, proposalId: "proposal123", - } + }, }); export const InProgress = createExample(TestedComponent, { applyResult: { - amountEffectivePaid: 'USD:10', - amountRefundGone: 'USD:1', - amountRefundGranted: 'USD:2', - contractTermsHash: 'QWEASDZXC', - info: { - summary: 'tasty cold beer', - contractTermsHash: 'QWEASDZXC', - } as Partial<OrderShortInfo> as any, + amountEffectivePaid: "USD:10", + amountRefundGone: "USD:1", + amountRefundGranted: "USD:2", + contractTermsHash: "QWEASDZXC", + info: ({ + summary: "tasty cold beer", + contractTermsHash: "QWEASDZXC", + } as Partial<OrderShortInfo>) as any, pendingAtExchange: true, proposalId: "proposal123", - } + }, }); diff --git a/packages/taler-wallet-webextension/src/cta/Refund.tsx b/packages/taler-wallet-webextension/src/cta/Refund.tsx index 943095360..aa11dca6a 100644 --- a/packages/taler-wallet-webextension/src/cta/Refund.tsx +++ b/packages/taler-wallet-webextension/src/cta/Refund.tsx @@ -22,45 +22,46 @@ import * as wxApi from "../wxApi"; import { AmountView } from "../renderHtml"; -import { - ApplyRefundResponse, - Amounts, -} from "@gnu-taler/taler-util"; +import { ApplyRefundResponse, Amounts } from "@gnu-taler/taler-util"; import { useEffect, useState } from "preact/hooks"; import { JSX } from "preact/jsx-runtime"; -import { h } from 'preact'; +import { h } from "preact"; interface Props { - talerRefundUri?: string + talerRefundUri?: string; } export interface ViewProps { applyResult: ApplyRefundResponse; } export function View({ applyResult }: ViewProps) { - return <section class="main"> - <h1>GNU Taler Wallet</h1> - <article class="fade"> - <h2>Refund Status</h2> - <p> - The product <em>{applyResult.info.summary}</em> has received a total - effective refund of{" "} - <AmountView amount={applyResult.amountRefundGranted} />. - </p> - {applyResult.pendingAtExchange ? ( - <p>Refund processing is still in progress.</p> - ) : null} - {!Amounts.isZero(applyResult.amountRefundGone) ? ( + return ( + <section class="main"> + <h1>GNU Taler Wallet</h1> + <article class="fade"> + <h2>Refund Status</h2> <p> - The refund amount of{" "} - <AmountView amount={applyResult.amountRefundGone} />{" "} - could not be applied. + The product <em>{applyResult.info.summary}</em> has received a total + effective refund of{" "} + <AmountView amount={applyResult.amountRefundGranted} />. </p> - ) : null} - </article> - </section> + {applyResult.pendingAtExchange ? ( + <p>Refund processing is still in progress.</p> + ) : null} + {!Amounts.isZero(applyResult.amountRefundGone) ? ( + <p> + The refund amount of{" "} + <AmountView amount={applyResult.amountRefundGone} /> could not be + applied. + </p> + ) : null} + </article> + </section> + ); } export function RefundPage({ talerRefundUri }: Props): JSX.Element { - const [applyResult, setApplyResult] = useState<ApplyRefundResponse | undefined>(undefined); + const [applyResult, setApplyResult] = useState< + ApplyRefundResponse | undefined + >(undefined); const [errMsg, setErrMsg] = useState<string | undefined>(undefined); useEffect(() => { diff --git a/packages/taler-wallet-webextension/src/cta/Tip.stories.tsx b/packages/taler-wallet-webextension/src/cta/Tip.stories.tsx index 389b183f0..8da599513 100644 --- a/packages/taler-wallet-webextension/src/cta/Tip.stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/Tip.stories.tsx @@ -15,45 +15,43 @@ */ /** -* -* @author Sebastian Javier Marchano (sebasjm) -*/ - -import { createExample } from '../test-utils'; -import { View as TestedComponent } from './Tip'; + * + * @author Sebastian Javier Marchano (sebasjm) + */ +import { createExample } from "../test-utils"; +import { View as TestedComponent } from "./Tip"; export default { - title: 'cta/tip', + title: "cta/tip", component: TestedComponent, - argTypes: { - }, + argTypes: {}, }; export const Accepted = createExample(TestedComponent, { prepareTipResult: { accepted: true, - merchantBaseUrl: '', - exchangeBaseUrl: '', - expirationTimestamp : { - t_ms: 0 + merchantBaseUrl: "", + exchangeBaseUrl: "", + expirationTimestamp: { + t_ms: 0, }, - tipAmountEffective: 'USD:10', - tipAmountRaw: 'USD:5', - walletTipId: 'id' - } + tipAmountEffective: "USD:10", + tipAmountRaw: "USD:5", + walletTipId: "id", + }, }); export const NotYetAccepted = createExample(TestedComponent, { prepareTipResult: { accepted: false, - merchantBaseUrl: 'http://merchant.url/', - exchangeBaseUrl: 'http://exchange.url/', - expirationTimestamp : { - t_ms: 0 + merchantBaseUrl: "http://merchant.url/", + exchangeBaseUrl: "http://exchange.url/", + expirationTimestamp: { + t_ms: 0, }, - tipAmountEffective: 'USD:10', - tipAmountRaw: 'USD:5', - walletTipId: 'id' - } + tipAmountEffective: "USD:10", + tipAmountRaw: "USD:5", + walletTipId: "id", + }, }); diff --git a/packages/taler-wallet-webextension/src/cta/Tip.tsx b/packages/taler-wallet-webextension/src/cta/Tip.tsx index dc1feaed3..0a1c1238c 100644 --- a/packages/taler-wallet-webextension/src/cta/Tip.tsx +++ b/packages/taler-wallet-webextension/src/cta/Tip.tsx @@ -25,43 +25,43 @@ import { PrepareTipResult } from "@gnu-taler/taler-util"; import { AmountView } from "../renderHtml"; import * as wxApi from "../wxApi"; import { JSX } from "preact/jsx-runtime"; -import { h } from 'preact'; +import { h } from "preact"; interface Props { - talerTipUri?: string + talerTipUri?: string; } export interface ViewProps { prepareTipResult: PrepareTipResult; onAccept: () => void; onIgnore: () => void; - } export function View({ prepareTipResult, onAccept, onIgnore }: ViewProps) { - return <section class="main"> - <h1>GNU Taler Wallet</h1> - <article class="fade"> - {prepareTipResult.accepted ? ( - <span> - Tip from <code>{prepareTipResult.merchantBaseUrl}</code> accepted. Check - your transactions list for more details. - </span> - ) : ( + return ( + <section class="main"> + <h1>GNU Taler Wallet</h1> + <article class="fade"> + {prepareTipResult.accepted ? ( + <span> + Tip from <code>{prepareTipResult.merchantBaseUrl}</code> accepted. + Check your transactions list for more details. + </span> + ) : ( <div> <p> The merchant <code>{prepareTipResult.merchantBaseUrl}</code> is - offering you a tip of{" "} + offering you a tip of{" "} <strong> <AmountView amount={prepareTipResult.tipAmountEffective} /> </strong>{" "} - via the exchange <code>{prepareTipResult.exchangeBaseUrl}</code> + via the exchange <code>{prepareTipResult.exchangeBaseUrl}</code> </p> <button onClick={onAccept}>Accept tip</button> <button onClick={onIgnore}>Ignore</button> </div> )} - </article> - </section> - + </article> + </section> + ); } export function TipPage({ talerTipUri }: Props): JSX.Element { @@ -105,7 +105,11 @@ export function TipPage({ talerTipUri }: Props): JSX.Element { return <span>Loading ...</span>; } - return <View prepareTipResult={prepareTipResult} - onAccept={doAccept} onIgnore={doIgnore} - /> + return ( + <View + prepareTipResult={prepareTipResult} + onAccept={doAccept} + onIgnore={doIgnore} + /> + ); } diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx index 5e29a3e39..90df2a27e 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx @@ -15,23 +15,22 @@ */ /** -* -* @author Sebastian Javier Marchano (sebasjm) -*/ - -import { amountFractionalBase, Amounts } from '@gnu-taler/taler-util'; -import { ExchangeRecord } from '@gnu-taler/taler-wallet-core'; -import { ExchangeWithdrawDetails } from '@gnu-taler/taler-wallet-core/src/operations/withdraw'; -import { getMaxListeners } from 'process'; -import { createExample } from '../test-utils'; -import { View as TestedComponent } from './Withdraw'; + * + * @author Sebastian Javier Marchano (sebasjm) + */ +import { amountFractionalBase, Amounts } from "@gnu-taler/taler-util"; +import { ExchangeRecord } from "@gnu-taler/taler-wallet-core"; +import { ExchangeWithdrawDetails } from "@gnu-taler/taler-wallet-core/src/operations/withdraw"; +import { getMaxListeners } from "process"; +import { createExample } from "../test-utils"; +import { View as TestedComponent } from "./Withdraw"; export default { - title: 'cta/withdraw', + title: "cta/withdraw", component: TestedComponent, argTypes: { - onSwitchExchange: { action: 'onRetry' }, + onSwitchExchange: { action: "onRetry" }, }, }; @@ -48,7 +47,7 @@ const termsHtml = `<html xmlns="http://www.w3.org/1999/xhtml" lang="en"> </div> </body> </html> -` +`; const termsPlain = ` Terms Of Service **************** @@ -432,7 +431,7 @@ Questions or comments We welcome comments, questions, concerns, or suggestions. Please send us a message on our contact page at legal@taler-systems.com. -` +`; const termsXml = `<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE document PUBLIC "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML" "http://docutils.sourceforge.net/docs/ref/docutils.dtd"> @@ -781,120 +780,131 @@ const termsXml = `<?xml version="1.0" encoding="utf-8"?> `; export const NewTerms = createExample(TestedComponent, { - knownExchanges: [{ - currency: 'USD', - exchangeBaseUrl: 'exchange.demo.taler.net', - paytoUris: ['asd'], - }, { - currency: 'USD', - exchangeBaseUrl: 'exchange.test.taler.net', - paytoUris: ['asd'], - }], - exchangeBaseUrl: 'exchange.demo.taler.net', + knownExchanges: [ + { + currency: "USD", + exchangeBaseUrl: "exchange.demo.taler.net", + paytoUris: ["asd"], + }, + { + currency: "USD", + exchangeBaseUrl: "exchange.test.taler.net", + paytoUris: ["asd"], + }, + ], + exchangeBaseUrl: "exchange.demo.taler.net", details: { - content: '', - contentType: '', - currentEtag: '', + content: "", + contentType: "", + currentEtag: "", acceptedEtag: undefined, }, withdrawalFee: { - currency: 'USD', + currency: "USD", fraction: 0, - value: 0 + value: 0, }, amount: { - currency: 'USD', + currency: "USD", value: 2, - fraction: 10000000 + fraction: 10000000, }, - onSwitchExchange: async () => { }, + onSwitchExchange: async () => {}, terms: { value: { - type: 'xml', + type: "xml", document: new DOMParser().parseFromString(termsXml, "text/xml"), }, - status: 'new' + status: "new", }, -}) +}); export const TermsReviewingPLAIN = createExample(TestedComponent, { - knownExchanges: [{ - currency: 'USD', - exchangeBaseUrl: 'exchange.demo.taler.net', - paytoUris: ['asd'], - }, { - currency: 'USD', - exchangeBaseUrl: 'exchange.test.taler.net', - paytoUris: ['asd'], - }], - exchangeBaseUrl: 'exchange.demo.taler.net', + knownExchanges: [ + { + currency: "USD", + exchangeBaseUrl: "exchange.demo.taler.net", + paytoUris: ["asd"], + }, + { + currency: "USD", + exchangeBaseUrl: "exchange.test.taler.net", + paytoUris: ["asd"], + }, + ], + exchangeBaseUrl: "exchange.demo.taler.net", details: { - content: '', - contentType: '', - currentEtag: '', + content: "", + contentType: "", + currentEtag: "", acceptedEtag: undefined, }, withdrawalFee: { - currency: 'USD', + currency: "USD", fraction: 0, - value: 0 + value: 0, }, amount: { - currency: 'USD', + currency: "USD", value: 2, - fraction: 10000000 + fraction: 10000000, }, - onSwitchExchange: async () => { }, + onSwitchExchange: async () => {}, terms: { value: { - type: 'plain', - content: termsPlain + type: "plain", + content: termsPlain, }, - status: 'new' + status: "new", }, - reviewing: true -}) + reviewing: true, +}); export const TermsReviewingHTML = createExample(TestedComponent, { - knownExchanges: [{ - currency: 'USD', - exchangeBaseUrl: 'exchange.demo.taler.net', - paytoUris: ['asd'], - }, { - currency: 'USD', - exchangeBaseUrl: 'exchange.test.taler.net', - paytoUris: ['asd'], - }], - exchangeBaseUrl: 'exchange.demo.taler.net', + knownExchanges: [ + { + currency: "USD", + exchangeBaseUrl: "exchange.demo.taler.net", + paytoUris: ["asd"], + }, + { + currency: "USD", + exchangeBaseUrl: "exchange.test.taler.net", + paytoUris: ["asd"], + }, + ], + exchangeBaseUrl: "exchange.demo.taler.net", details: { - content: '', - contentType: '', - currentEtag: '', + content: "", + contentType: "", + currentEtag: "", acceptedEtag: undefined, }, withdrawalFee: { - currency: 'USD', + currency: "USD", fraction: 0, - value: 0 + value: 0, }, amount: { - currency: 'USD', + currency: "USD", value: 2, - fraction: 10000000 + fraction: 10000000, }, - onSwitchExchange: async () => { }, + onSwitchExchange: async () => {}, terms: { value: { - type: 'html', - href: new URL(`data:text/html;base64,${Buffer.from(termsHtml).toString('base64')}`), + type: "html", + href: new URL( + `data:text/html;base64,${Buffer.from(termsHtml).toString("base64")}`, + ), }, - status: 'new' + status: "new", }, - reviewing: true -}) + reviewing: true, +}); const termsPdf = ` %PDF-1.2 @@ -909,306 +919,330 @@ endobj trailer << /Root 3 0 R >> %%EOF -` +`; export const TermsReviewingPDF = createExample(TestedComponent, { - knownExchanges: [{ - currency: 'USD', - exchangeBaseUrl: 'exchange.demo.taler.net', - paytoUris: ['asd'], - }, { - currency: 'USD', - exchangeBaseUrl: 'exchange.test.taler.net', - paytoUris: ['asd'], - }], - exchangeBaseUrl: 'exchange.demo.taler.net', + knownExchanges: [ + { + currency: "USD", + exchangeBaseUrl: "exchange.demo.taler.net", + paytoUris: ["asd"], + }, + { + currency: "USD", + exchangeBaseUrl: "exchange.test.taler.net", + paytoUris: ["asd"], + }, + ], + exchangeBaseUrl: "exchange.demo.taler.net", details: { - content: '', - contentType: '', - currentEtag: '', + content: "", + contentType: "", + currentEtag: "", acceptedEtag: undefined, }, withdrawalFee: { - currency: 'USD', + currency: "USD", fraction: 0, - value: 0 + value: 0, }, amount: { - currency: 'USD', + currency: "USD", value: 2, - fraction: 10000000 + fraction: 10000000, }, - onSwitchExchange: async () => { }, + onSwitchExchange: async () => {}, terms: { value: { - type: 'pdf', - location: new URL(`data:text/html;base64,${Buffer.from(termsPdf).toString('base64')}`), + type: "pdf", + location: new URL( + `data:text/html;base64,${Buffer.from(termsPdf).toString("base64")}`, + ), }, - status: 'new' + status: "new", }, - reviewing: true -}) - + reviewing: true, +}); export const TermsReviewingXML = createExample(TestedComponent, { - knownExchanges: [{ - currency: 'USD', - exchangeBaseUrl: 'exchange.demo.taler.net', - paytoUris: ['asd'], - }, { - currency: 'USD', - exchangeBaseUrl: 'exchange.test.taler.net', - paytoUris: ['asd'], - }], - exchangeBaseUrl: 'exchange.demo.taler.net', + knownExchanges: [ + { + currency: "USD", + exchangeBaseUrl: "exchange.demo.taler.net", + paytoUris: ["asd"], + }, + { + currency: "USD", + exchangeBaseUrl: "exchange.test.taler.net", + paytoUris: ["asd"], + }, + ], + exchangeBaseUrl: "exchange.demo.taler.net", details: { - content: '', - contentType: '', - currentEtag: '', + content: "", + contentType: "", + currentEtag: "", acceptedEtag: undefined, }, withdrawalFee: { - currency: 'USD', + currency: "USD", fraction: 0, - value: 0 + value: 0, }, amount: { - currency: 'USD', + currency: "USD", value: 2, - fraction: 10000000 + fraction: 10000000, }, - onSwitchExchange: async () => { }, + onSwitchExchange: async () => {}, terms: { value: { - type: 'xml', + type: "xml", document: new DOMParser().parseFromString(termsXml, "text/xml"), }, - status: 'new' + status: "new", }, - reviewing: true -}) + reviewing: true, +}); export const NewTermsAccepted = createExample(TestedComponent, { - knownExchanges: [{ - currency: 'USD', - exchangeBaseUrl: 'exchange.demo.taler.net', - paytoUris: ['asd'], - }, { - currency: 'USD', - exchangeBaseUrl: 'exchange.test.taler.net', - paytoUris: ['asd'], - }], - exchangeBaseUrl: 'exchange.demo.taler.net', + knownExchanges: [ + { + currency: "USD", + exchangeBaseUrl: "exchange.demo.taler.net", + paytoUris: ["asd"], + }, + { + currency: "USD", + exchangeBaseUrl: "exchange.test.taler.net", + paytoUris: ["asd"], + }, + ], + exchangeBaseUrl: "exchange.demo.taler.net", details: { - content: '', - contentType: '', - currentEtag: '', + content: "", + contentType: "", + currentEtag: "", acceptedEtag: undefined, }, withdrawalFee: { - currency: 'USD', + currency: "USD", fraction: 0, - value: 0 + value: 0, }, amount: { - currency: 'USD', + currency: "USD", value: 2, - fraction: 10000000 + fraction: 10000000, }, - onSwitchExchange: async () => { }, + onSwitchExchange: async () => {}, terms: { value: { - type: 'xml', + type: "xml", document: new DOMParser().parseFromString(termsXml, "text/xml"), }, - status: 'new' + status: "new", }, - reviewed: true -}) + reviewed: true, +}); export const TermsShowAgainXML = createExample(TestedComponent, { - knownExchanges: [{ - currency: 'USD', - exchangeBaseUrl: 'exchange.demo.taler.net', - paytoUris: ['asd'], - }, { - currency: 'USD', - exchangeBaseUrl: 'exchange.test.taler.net', - paytoUris: ['asd'], - }], - exchangeBaseUrl: 'exchange.demo.taler.net', + knownExchanges: [ + { + currency: "USD", + exchangeBaseUrl: "exchange.demo.taler.net", + paytoUris: ["asd"], + }, + { + currency: "USD", + exchangeBaseUrl: "exchange.test.taler.net", + paytoUris: ["asd"], + }, + ], + exchangeBaseUrl: "exchange.demo.taler.net", details: { - content: '', - contentType: '', - currentEtag: '', + content: "", + contentType: "", + currentEtag: "", acceptedEtag: undefined, }, withdrawalFee: { - currency: 'USD', + currency: "USD", fraction: 0, - value: 0 + value: 0, }, amount: { - currency: 'USD', + currency: "USD", value: 2, - fraction: 10000000 + fraction: 10000000, }, - onSwitchExchange: async () => { }, + onSwitchExchange: async () => {}, terms: { value: { - type: 'xml', + type: "xml", document: new DOMParser().parseFromString(termsXml, "text/xml"), }, - status: 'new' + status: "new", }, reviewed: true, reviewing: true, -}) +}); export const TermsChanged = createExample(TestedComponent, { - knownExchanges: [{ - currency: 'USD', - exchangeBaseUrl: 'exchange.demo.taler.net', - paytoUris: ['asd'], - }, { - currency: 'USD', - exchangeBaseUrl: 'exchange.test.taler.net', - paytoUris: ['asd'], - }], - exchangeBaseUrl: 'exchange.demo.taler.net', + knownExchanges: [ + { + currency: "USD", + exchangeBaseUrl: "exchange.demo.taler.net", + paytoUris: ["asd"], + }, + { + currency: "USD", + exchangeBaseUrl: "exchange.test.taler.net", + paytoUris: ["asd"], + }, + ], + exchangeBaseUrl: "exchange.demo.taler.net", details: { - content: '', - contentType: '', - currentEtag: '', + content: "", + contentType: "", + currentEtag: "", acceptedEtag: undefined, }, withdrawalFee: { - currency: 'USD', + currency: "USD", fraction: 0, - value: 0 + value: 0, }, amount: { - currency: 'USD', + currency: "USD", value: 2, - fraction: 10000000 + fraction: 10000000, }, - onSwitchExchange: async () => { }, + onSwitchExchange: async () => {}, terms: { value: { - type: 'xml', + type: "xml", document: new DOMParser().parseFromString(termsXml, "text/xml"), }, - status: 'changed' + status: "changed", }, -}) +}); export const TermsNotFound = createExample(TestedComponent, { - knownExchanges: [{ - currency: 'USD', - exchangeBaseUrl: 'exchange.demo.taler.net', - paytoUris: ['asd'], - }, { - currency: 'USD', - exchangeBaseUrl: 'exchange.test.taler.net', - paytoUris: ['asd'], - }], - exchangeBaseUrl: 'exchange.demo.taler.net', + knownExchanges: [ + { + currency: "USD", + exchangeBaseUrl: "exchange.demo.taler.net", + paytoUris: ["asd"], + }, + { + currency: "USD", + exchangeBaseUrl: "exchange.test.taler.net", + paytoUris: ["asd"], + }, + ], + exchangeBaseUrl: "exchange.demo.taler.net", details: { - content: '', - contentType: '', - currentEtag: '', + content: "", + contentType: "", + currentEtag: "", acceptedEtag: undefined, }, withdrawalFee: { - currency: 'USD', + currency: "USD", fraction: 0, - value: 0 + value: 0, }, amount: { - currency: 'USD', + currency: "USD", value: 2, - fraction: 10000000 + fraction: 10000000, }, - onSwitchExchange: async () => { }, + onSwitchExchange: async () => {}, terms: { - status: 'notfound' + status: "notfound", }, -}) +}); export const TermsAlreadyAccepted = createExample(TestedComponent, { - knownExchanges: [{ - currency: 'USD', - exchangeBaseUrl: 'exchange.demo.taler.net', - paytoUris: ['asd'], - }, { - currency: 'USD', - exchangeBaseUrl: 'exchange.test.taler.net', - paytoUris: ['asd'], - }], - exchangeBaseUrl: 'exchange.demo.taler.net', + knownExchanges: [ + { + currency: "USD", + exchangeBaseUrl: "exchange.demo.taler.net", + paytoUris: ["asd"], + }, + { + currency: "USD", + exchangeBaseUrl: "exchange.test.taler.net", + paytoUris: ["asd"], + }, + ], + exchangeBaseUrl: "exchange.demo.taler.net", details: { - content: '', - contentType: '', - currentEtag: '', + content: "", + contentType: "", + currentEtag: "", acceptedEtag: undefined, }, withdrawalFee: { - currency: 'USD', + currency: "USD", fraction: amountFractionalBase * 0.5, - value: 0 + value: 0, }, amount: { - currency: 'USD', + currency: "USD", value: 2, - fraction: 10000000 + fraction: 10000000, }, - onSwitchExchange: async () => { }, + onSwitchExchange: async () => {}, terms: { - status: 'accepted' + status: "accepted", }, -}) - +}); export const WithoutFee = createExample(TestedComponent, { - knownExchanges: [{ - currency: 'USD', - exchangeBaseUrl: 'exchange.demo.taler.net', - paytoUris: ['asd'], - }, { - currency: 'USD', - exchangeBaseUrl: 'exchange.test.taler.net', - paytoUris: ['asd'], - }], - exchangeBaseUrl: 'exchange.demo.taler.net', + knownExchanges: [ + { + currency: "USD", + exchangeBaseUrl: "exchange.demo.taler.net", + paytoUris: ["asd"], + }, + { + currency: "USD", + exchangeBaseUrl: "exchange.test.taler.net", + paytoUris: ["asd"], + }, + ], + exchangeBaseUrl: "exchange.demo.taler.net", details: { - content: '', - contentType: '', - currentEtag: '', + content: "", + contentType: "", + currentEtag: "", acceptedEtag: undefined, }, withdrawalFee: { - currency: 'USD', + currency: "USD", fraction: 0, value: 0, }, amount: { - currency: 'USD', + currency: "USD", value: 2, - fraction: 10000000 + fraction: 10000000, }, - onSwitchExchange: async () => { }, + onSwitchExchange: async () => {}, terms: { value: { - type: 'xml', + type: "xml", document: new DOMParser().parseFromString(termsXml, "text/xml"), }, - status: 'accepted', - } -})
\ No newline at end of file + status: "accepted", + }, +}); diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx index 6ef72cbe6..603dafcde 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx +++ b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx @@ -21,21 +21,39 @@ * @author Florian Dold */ -import { AmountJson, Amounts, ExchangeListItem, GetExchangeTosResult, i18n, WithdrawUriInfoResponse } from '@gnu-taler/taler-util'; -import { ExchangeWithdrawDetails } from '@gnu-taler/taler-wallet-core/src/operations/withdraw'; +import { + AmountJson, + Amounts, + ExchangeListItem, + GetExchangeTosResult, + i18n, + WithdrawUriInfoResponse, +} from "@gnu-taler/taler-util"; +import { VNode, h } from "preact"; import { useState } from "preact/hooks"; -import { Fragment } from 'preact/jsx-runtime'; -import { CheckboxOutlined } from '../components/CheckboxOutlined'; -import { ExchangeXmlTos } from '../components/ExchangeToS'; -import { LogoHeader } from '../components/LogoHeader'; -import { Part } from '../components/Part'; -import { SelectList } from '../components/SelectList'; -import { ButtonSuccess, ButtonWarning, LinkSuccess, LinkWarning, TermsOfService, WalletAction, WarningText } from '../components/styled'; -import { useAsyncAsHook } from '../hooks/useAsyncAsHook'; +import { Fragment } from "preact/jsx-runtime"; +import { CheckboxOutlined } from "../components/CheckboxOutlined"; +import { ExchangeXmlTos } from "../components/ExchangeToS"; +import { LogoHeader } from "../components/LogoHeader"; +import { Part } from "../components/Part"; +import { SelectList } from "../components/SelectList"; +import { + ButtonSuccess, + ButtonWarning, + LinkSuccess, + TermsOfService, + WalletAction, + WarningText, +} from "../components/styled"; +import { useAsyncAsHook } from "../hooks/useAsyncAsHook"; import { - acceptWithdrawal, getExchangeWithdrawalInfo, getWithdrawalDetailsForUri, setExchangeTosAccepted, listExchanges, getExchangeTos + acceptWithdrawal, + getExchangeTos, + getExchangeWithdrawalInfo, + getWithdrawalDetailsForUri, + listExchanges, + setExchangeTosAccepted, } from "../wxApi"; -import { wxMain } from '../wxBackend.js'; interface Props { talerWithdrawUri?: string; @@ -58,145 +76,193 @@ export interface ViewProps { status: TermsStatus; }; knownExchanges: ExchangeListItem[]; +} -}; - -type TermsStatus = 'new' | 'accepted' | 'changed' | 'notfound'; +type TermsStatus = "new" | "accepted" | "changed" | "notfound"; -type TermsDocument = TermsDocumentXml | TermsDocumentHtml | TermsDocumentPlain | TermsDocumentJson | TermsDocumentPdf; +type TermsDocument = + | TermsDocumentXml + | TermsDocumentHtml + | TermsDocumentPlain + | TermsDocumentJson + | TermsDocumentPdf; interface TermsDocumentXml { - type: 'xml', - document: Document, + type: "xml"; + document: Document; } interface TermsDocumentHtml { - type: 'html', - href: URL, + type: "html"; + href: URL; } interface TermsDocumentPlain { - type: 'plain', - content: string, + type: "plain"; + content: string; } interface TermsDocumentJson { - type: 'json', - data: any, + type: "json"; + data: any; } interface TermsDocumentPdf { - type: 'pdf', - location: URL, + type: "pdf"; + location: URL; } function amountToString(text: AmountJson) { - const aj = Amounts.jsonifyAmount(text) - const amount = Amounts.stringifyValue(aj) - return `${amount} ${aj.currency}` + const aj = Amounts.jsonifyAmount(text); + const amount = Amounts.stringifyValue(aj); + return `${amount} ${aj.currency}`; } -export function View({ details, withdrawalFee, exchangeBaseUrl, knownExchanges, amount, onWithdraw, onSwitchExchange, terms, reviewing, onReview, onAccept, reviewed, confirmed }: ViewProps) { - const needsReview = terms.status === 'changed' || terms.status === 'new' - - const [switchingExchange, setSwitchingExchange] = useState<string | undefined>(undefined) - const exchanges = knownExchanges.reduce((prev, ex) => ({ ...prev, [ex.exchangeBaseUrl]: ex.exchangeBaseUrl }), {}) +export function View({ + details, + withdrawalFee, + exchangeBaseUrl, + knownExchanges, + amount, + onWithdraw, + onSwitchExchange, + terms, + reviewing, + onReview, + onAccept, + reviewed, + confirmed, +}: ViewProps) { + const needsReview = terms.status === "changed" || terms.status === "new"; + + const [switchingExchange, setSwitchingExchange] = useState< + string | undefined + >(undefined); + const exchanges = knownExchanges.reduce( + (prev, ex) => ({ ...prev, [ex.exchangeBaseUrl]: ex.exchangeBaseUrl }), + {}, + ); return ( <WalletAction> <LogoHeader /> - <h2> - {i18n.str`Digital cash withdrawal`} - </h2> + <h2>{i18n.str`Digital cash withdrawal`}</h2> <section> - <Part title="Total to withdraw" text={amountToString(Amounts.sub(amount, withdrawalFee).amount)} kind='positive' /> - <Part title="Chosen amount" text={amountToString(amount)} kind='neutral' /> - {Amounts.isNonZero(withdrawalFee) && - <Part title="Exchange fee" text={amountToString(withdrawalFee)} kind='negative' /> - } - <Part title="Exchange" text={exchangeBaseUrl} kind='neutral' big /> + <Part + title="Total to withdraw" + text={amountToString(Amounts.sub(amount, withdrawalFee).amount)} + kind="positive" + /> + <Part + title="Chosen amount" + text={amountToString(amount)} + kind="neutral" + /> + {Amounts.isNonZero(withdrawalFee) && ( + <Part + title="Exchange fee" + text={amountToString(withdrawalFee)} + kind="negative" + /> + )} + <Part title="Exchange" text={exchangeBaseUrl} kind="neutral" big /> </section> - {!reviewing && + {!reviewing && ( <section> - {switchingExchange !== undefined ? <Fragment> - <div> - <SelectList label="Known exchanges" list={exchanges} name="" onChange={onSwitchExchange} /> - </div> - <LinkSuccess upperCased onClick={() => onSwitchExchange(switchingExchange)}> - {i18n.str`Confirm exchange selection`} - </LinkSuccess> - </Fragment> - : <LinkSuccess upperCased onClick={() => setSwitchingExchange("")}> + {switchingExchange !== undefined ? ( + <Fragment> + <div> + <SelectList + label="Known exchanges" + list={exchanges} + name="" + onChange={onSwitchExchange} + /> + </div> + <LinkSuccess + upperCased + onClick={() => onSwitchExchange(switchingExchange)} + > + {i18n.str`Confirm exchange selection`} + </LinkSuccess> + </Fragment> + ) : ( + <LinkSuccess upperCased onClick={() => setSwitchingExchange("")}> {i18n.str`Switch exchange`} - </LinkSuccess>} - + </LinkSuccess> + )} </section> - } - {!reviewing && reviewed && + )} + {!reviewing && reviewed && ( <section> - <LinkSuccess - upperCased - onClick={() => onReview(true)} - > + <LinkSuccess upperCased onClick={() => onReview(true)}> {i18n.str`Show terms of service`} </LinkSuccess> </section> - } - {terms.status === 'notfound' && + )} + {terms.status === "notfound" && ( <section> <WarningText> {i18n.str`Exchange doesn't have terms of service`} </WarningText> </section> - } - {reviewing && + )} + {reviewing && ( <section> - {terms.status !== 'accepted' && terms.value && terms.value.type === 'xml' && - <TermsOfService> - <ExchangeXmlTos doc={terms.value.document} /> - </TermsOfService> - } - {terms.status !== 'accepted' && terms.value && terms.value.type === 'plain' && - <div style={{ textAlign: 'left' }}> - <pre>{terms.value.content}</pre> - </div> - } - {terms.status !== 'accepted' && terms.value && terms.value.type === 'html' && - <iframe src={terms.value.href.toString()} /> - } - {terms.status !== 'accepted' && terms.value && terms.value.type === 'pdf' && - <a href={terms.value.location.toString()} download="tos.pdf" >Download Terms of Service</a> - } - </section>} - {reviewing && reviewed && + {terms.status !== "accepted" && + terms.value && + terms.value.type === "xml" && ( + <TermsOfService> + <ExchangeXmlTos doc={terms.value.document} /> + </TermsOfService> + )} + {terms.status !== "accepted" && + terms.value && + terms.value.type === "plain" && ( + <div style={{ textAlign: "left" }}> + <pre>{terms.value.content}</pre> + </div> + )} + {terms.status !== "accepted" && + terms.value && + terms.value.type === "html" && ( + <iframe src={terms.value.href.toString()} /> + )} + {terms.status !== "accepted" && + terms.value && + terms.value.type === "pdf" && ( + <a href={terms.value.location.toString()} download="tos.pdf"> + Download Terms of Service + </a> + )} + </section> + )} + {reviewing && reviewed && ( <section> - <LinkSuccess - upperCased - onClick={() => onReview(false)} - > + <LinkSuccess upperCased onClick={() => onReview(false)}> {i18n.str`Hide terms of service`} </LinkSuccess> </section> - } - {(reviewing || reviewed) && + )} + {(reviewing || reviewed) && ( <section> <CheckboxOutlined name="terms" enabled={reviewed} label={i18n.str`I accept the exchange terms of service`} onToggle={() => { - onAccept(!reviewed) - onReview(false) + onAccept(!reviewed); + onReview(false); }} /> </section> - } + )} {/** * Main action section */} <section> - {terms.status === 'new' && !reviewed && !reviewing && + {terms.status === "new" && !reviewed && !reviewing && ( <ButtonSuccess upperCased disabled={!exchangeBaseUrl} @@ -204,8 +270,8 @@ export function View({ details, withdrawalFee, exchangeBaseUrl, knownExchanges, > {i18n.str`Review exchange terms of service`} </ButtonSuccess> - } - {terms.status === 'changed' && !reviewed && !reviewing && + )} + {terms.status === "changed" && !reviewed && !reviewing && ( <ButtonWarning upperCased disabled={!exchangeBaseUrl} @@ -213,8 +279,8 @@ export function View({ details, withdrawalFee, exchangeBaseUrl, knownExchanges, > {i18n.str`Review new version of terms of service`} </ButtonWarning> - } - {(terms.status === 'accepted' || (needsReview && reviewed)) && + )} + {(terms.status === "accepted" || (needsReview && reviewed)) && ( <ButtonSuccess upperCased disabled={!exchangeBaseUrl || confirmed} @@ -222,8 +288,8 @@ export function View({ details, withdrawalFee, exchangeBaseUrl, knownExchanges, > {i18n.str`Confirm withdrawal`} </ButtonSuccess> - } - {terms.status === 'notfound' && + )} + {terms.status === "notfound" && ( <ButtonWarning upperCased disabled={!exchangeBaseUrl} @@ -231,60 +297,88 @@ export function View({ details, withdrawalFee, exchangeBaseUrl, knownExchanges, > {i18n.str`Withdraw anyway`} </ButtonWarning> - } + )} </section> </WalletAction> - ) + ); } -export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriInfo: WithdrawUriInfoResponse }) { - const [customExchange, setCustomExchange] = useState<string | undefined>(undefined) - const [errorAccepting, setErrorAccepting] = useState<string | undefined>(undefined) - - const [reviewing, setReviewing] = useState<boolean>(false) - const [reviewed, setReviewed] = useState<boolean>(false) - const [confirmed, setConfirmed] = useState<boolean>(false) - - const knownExchangesHook = useAsyncAsHook(() => listExchanges()) - - const knownExchanges = !knownExchangesHook || knownExchangesHook.hasError ? [] : knownExchangesHook.response.exchanges - const withdrawAmount = Amounts.parseOrThrow(uriInfo.amount) - const thisCurrencyExchanges = knownExchanges.filter(ex => ex.currency === withdrawAmount.currency) - - const exchange = customExchange || uriInfo.defaultExchangeBaseUrl || thisCurrencyExchanges[0]?.exchangeBaseUrl +export function WithdrawPageWithParsedURI({ + uri, + uriInfo, +}: { + uri: string; + uriInfo: WithdrawUriInfoResponse; +}) { + const [customExchange, setCustomExchange] = useState<string | undefined>( + undefined, + ); + const [errorAccepting, setErrorAccepting] = useState<string | undefined>( + undefined, + ); + + const [reviewing, setReviewing] = useState<boolean>(false); + const [reviewed, setReviewed] = useState<boolean>(false); + const [confirmed, setConfirmed] = useState<boolean>(false); + + const knownExchangesHook = useAsyncAsHook(() => listExchanges()); + + const knownExchanges = + !knownExchangesHook || knownExchangesHook.hasError + ? [] + : knownExchangesHook.response.exchanges; + const withdrawAmount = Amounts.parseOrThrow(uriInfo.amount); + const thisCurrencyExchanges = knownExchanges.filter( + (ex) => ex.currency === withdrawAmount.currency, + ); + + const exchange = + customExchange || + uriInfo.defaultExchangeBaseUrl || + thisCurrencyExchanges[0]?.exchangeBaseUrl; const detailsHook = useAsyncAsHook(async () => { - if (!exchange) throw Error('no default exchange') - const tos = await getExchangeTos(exchange, ['text/xml']) + if (!exchange) throw Error("no default exchange"); + const tos = await getExchangeTos(exchange, ["text/xml"]); const info = await getExchangeWithdrawalInfo({ exchangeBaseUrl: exchange, amount: withdrawAmount, - tosAcceptedFormat: ['text/xml'] - }) - return { tos, info } - }) + tosAcceptedFormat: ["text/xml"], + }); + return { tos, info }; + }); if (!detailsHook) { - return <span><i18n.Translate>Getting withdrawal details.</i18n.Translate></span>; + return ( + <span> + <i18n.Translate>Getting withdrawal details.</i18n.Translate> + </span> + ); } if (detailsHook.hasError) { - return <span><i18n.Translate>Problems getting details: {detailsHook.message}</i18n.Translate></span>; + return ( + <span> + <i18n.Translate> + Problems getting details: {detailsHook.message} + </i18n.Translate> + </span> + ); } - const details = detailsHook.response + const details = detailsHook.response; const onAccept = async (): Promise<void> => { try { - await setExchangeTosAccepted(exchange, details.tos.currentEtag) - setReviewed(true) + await setExchangeTosAccepted(exchange, details.tos.currentEtag); + setReviewed(true); } catch (e) { if (e instanceof Error) { - setErrorAccepting(e.message) + setErrorAccepting(e.message); } } - } + }; const onWithdraw = async (): Promise<void> => { - setConfirmed(true) + setConfirmed(true); console.log("accepting exchange", exchange); try { const res = await acceptWithdrawal(uri, exchange); @@ -293,91 +387,121 @@ export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriIn document.location.href = res.confirmTransferUrl; } } catch (e) { - setConfirmed(false) + setConfirmed(false); } }; - const termsContent: TermsDocument | undefined = parseTermsOfServiceContent(details.tos.contentType, details.tos.content); - - const status: TermsStatus = !termsContent ? 'notfound' : ( - !details.tos.acceptedEtag ? 'new' : ( - details.tos.acceptedEtag !== details.tos.currentEtag ? 'changed' : 'accepted' - )) - - - return <View onWithdraw={onWithdraw} - details={details.tos} amount={withdrawAmount} - exchangeBaseUrl={exchange} - withdrawalFee={details.info.withdrawFee} //FIXME - terms={{ - status, value: termsContent - }} - onSwitchExchange={setCustomExchange} - knownExchanges={knownExchanges} - confirmed={confirmed} - reviewed={reviewed} onAccept={onAccept} - reviewing={reviewing} onReview={setReviewing} - /> + const termsContent: TermsDocument | undefined = parseTermsOfServiceContent( + details.tos.contentType, + details.tos.content, + ); + + const status: TermsStatus = !termsContent + ? "notfound" + : !details.tos.acceptedEtag + ? "new" + : details.tos.acceptedEtag !== details.tos.currentEtag + ? "changed" + : "accepted"; + + return ( + <View + onWithdraw={onWithdraw} + details={details.tos} + amount={withdrawAmount} + exchangeBaseUrl={exchange} + withdrawalFee={details.info.withdrawFee} //FIXME + terms={{ + status, + value: termsContent, + }} + onSwitchExchange={setCustomExchange} + knownExchanges={knownExchanges} + confirmed={confirmed} + reviewed={reviewed} + onAccept={onAccept} + reviewing={reviewing} + onReview={setReviewing} + /> + ); } -export function WithdrawPage({ talerWithdrawUri }: Props): JSX.Element { - const uriInfoHook = useAsyncAsHook(() => !talerWithdrawUri ? Promise.reject(undefined) : - getWithdrawalDetailsForUri({ talerWithdrawUri }) - ) +export function WithdrawPage({ talerWithdrawUri }: Props): VNode { + const uriInfoHook = useAsyncAsHook(() => + !talerWithdrawUri + ? Promise.reject(undefined) + : getWithdrawalDetailsForUri({ talerWithdrawUri }), + ); if (!talerWithdrawUri) { - return <span><i18n.Translate>missing withdraw uri</i18n.Translate></span>; + return ( + <span> + <i18n.Translate>missing withdraw uri</i18n.Translate> + </span> + ); } if (!uriInfoHook) { - return <span><i18n.Translate>Loading...</i18n.Translate></span>; + return ( + <span> + <i18n.Translate>Loading...</i18n.Translate> + </span> + ); } if (uriInfoHook.hasError) { - return <span><i18n.Translate>This URI is not valid anymore: {uriInfoHook.message}</i18n.Translate></span>; + return ( + <span> + <i18n.Translate> + This URI is not valid anymore: {uriInfoHook.message} + </i18n.Translate> + </span> + ); } - return <WithdrawPageWithParsedURI uri={talerWithdrawUri} uriInfo={uriInfoHook.response} /> + return ( + <WithdrawPageWithParsedURI + uri={talerWithdrawUri} + uriInfo={uriInfoHook.response} + /> + ); } -function parseTermsOfServiceContent(type: string, text: string): TermsDocument | undefined { - if (type === 'text/xml') { +function parseTermsOfServiceContent( + type: string, + text: string, +): TermsDocument | undefined { + if (type === "text/xml") { try { - const document = new DOMParser().parseFromString(text, "text/xml") - return { type: 'xml', document } + const document = new DOMParser().parseFromString(text, "text/xml"); + return { type: "xml", document }; } catch (e) { - console.log(e) - debugger; + console.log(e); } - } else if (type === 'text/html') { + } else if (type === "text/html") { try { - const href = new URL(text) - return { type: 'html', href } + const href = new URL(text); + return { type: "html", href }; } catch (e) { - console.log(e) - debugger; + console.log(e); } - } else if (type === 'text/json') { + } else if (type === "text/json") { try { - const data = JSON.parse(text) - return { type: 'json', data } + const data = JSON.parse(text); + return { type: "json", data }; } catch (e) { - console.log(e) - debugger; + console.log(e); } - } else if (type === 'text/pdf') { + } else if (type === "text/pdf") { try { - const location = new URL(text) - return { type: 'pdf', location } + const location = new URL(text); + return { type: "pdf", location }; } catch (e) { - console.log(e) - debugger; + console.log(e); } - } else if (type === 'text/plain') { + } else if (type === "text/plain") { try { - const content = text - return { type: 'plain', content } + const content = text; + return { type: "plain", content }; } catch (e) { - console.log(e) - debugger; + console.log(e); } } - return undefined + return undefined; } - diff --git a/packages/taler-wallet-webextension/src/cta/payback.tsx b/packages/taler-wallet-webextension/src/cta/payback.tsx index 1e27fd912..60cb8c513 100644 --- a/packages/taler-wallet-webextension/src/cta/payback.tsx +++ b/packages/taler-wallet-webextension/src/cta/payback.tsx @@ -15,7 +15,7 @@ */ import { JSX } from "preact/jsx-runtime"; -import { h } from 'preact'; +import { h } from "preact"; /** * View and edit auditors. diff --git a/packages/taler-wallet-webextension/src/cta/reset-required.tsx b/packages/taler-wallet-webextension/src/cta/reset-required.tsx index e66c0db57..3949318c4 100644 --- a/packages/taler-wallet-webextension/src/cta/reset-required.tsx +++ b/packages/taler-wallet-webextension/src/cta/reset-required.tsx @@ -63,7 +63,7 @@ class ResetNotification extends Component<any, State> { type="checkbox" checked={this.state.checked} onChange={() => { - this.setState(prev => ({ checked: prev.checked })) + this.setState((prev) => ({ checked: prev.checked })); }} />{" "} <label htmlFor="check"> diff --git a/packages/taler-wallet-webextension/src/cta/return-coins.tsx b/packages/taler-wallet-webextension/src/cta/return-coins.tsx index 43d73b5fe..548202cab 100644 --- a/packages/taler-wallet-webextension/src/cta/return-coins.tsx +++ b/packages/taler-wallet-webextension/src/cta/return-coins.tsx @@ -15,7 +15,7 @@ */ import { JSX } from "preact/jsx-runtime"; -import { h } from 'preact'; +import { h } from "preact"; /** * Return coins to own bank account. * |