diff options
author | Sebastian <sebasjm@gmail.com> | 2022-01-10 16:04:53 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2022-01-10 16:07:27 -0300 |
commit | fb22009ec4799a624f00c228fbd7435b44c1cbac (patch) | |
tree | b1f8427e845bb3687b8a64deb3545eff2290ec67 /packages/taler-wallet-webextension/src/cta | |
parent | 83b9d32b7812e63640a60b5b42a27c96d8053bce (diff) | |
download | wallet-core-fb22009ec4799a624f00c228fbd7435b44c1cbac.tar.xz |
deposit design from belen, feature missing: kyc
Diffstat (limited to 'packages/taler-wallet-webextension/src/cta')
3 files changed, 421 insertions, 27 deletions
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit.stories.tsx b/packages/taler-wallet-webextension/src/cta/Deposit.stories.tsx new file mode 100644 index 000000000..df5947bb1 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/Deposit.stories.tsx @@ -0,0 +1,168 @@ +/* + 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 <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { ContractTerms, PreparePayResultType } from "@gnu-taler/taler-util"; +import { createExample } from "../test-utils"; +import { PaymentRequestView as TestedComponent } from "./Deposit"; + +export default { + title: "cta/deposit", + component: TestedComponent, + argTypes: {}, +}; + +export const NoBalance = createExample(TestedComponent, { + payStatus: { + status: PreparePayResultType.InsufficientBalance, + noncePriv: "", + proposalId: "proposal1234", + contractTerms: { + merchant: { + name: "someone", + }, + summary: "some beers", + amount: "USD:10", + } as Partial<ContractTerms> as any, + amountRaw: "USD:10", + }, +}); + +export const NoEnoughBalance = createExample(TestedComponent, { + payStatus: { + status: PreparePayResultType.InsufficientBalance, + noncePriv: "", + proposalId: "proposal1234", + contractTerms: { + merchant: { + name: "someone", + }, + summary: "some beers", + amount: "USD:10", + } as Partial<ContractTerms> as any, + amountRaw: "USD:10", + }, + balance: { + currency: "USD", + fraction: 40000000, + value: 9, + }, +}); + +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<ContractTerms> as any, + contractTermsHash: "123456", + proposalId: "proposal1234", + }, +}); + +export const PaymentPossibleWithFee = createExample(TestedComponent, { + 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", + merchant: { + name: "someone", + }, + 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: { + merchant: { + 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", + 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: { + merchant: { + 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", + paid: true, + }, +}); diff --git a/packages/taler-wallet-webextension/src/cta/Deposit.tsx b/packages/taler-wallet-webextension/src/cta/Deposit.tsx new file mode 100644 index 000000000..3696b0c2d --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/Deposit.tsx @@ -0,0 +1,251 @@ +/* + 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 { + AmountJson, + Amounts, + amountToPretty, + ConfirmPayResult, + ConfirmPayResultDone, + ConfirmPayResultType, + ContractTerms, + i18n, + NotificationType, + PreparePayResult, + PreparePayResultType, +} from "@gnu-taler/taler-util"; +import { OperationFailedError } from "@gnu-taler/taler-wallet-core"; +import { Fragment, h, VNode } from "preact"; +import { useEffect, useState } from "preact/hooks"; +import { ErrorTalerOperation } from "../components/ErrorTalerOperation"; +import { LogoHeader } from "../components/LogoHeader"; +import { Part } from "../components/Part"; +import { + ErrorBox, + SuccessBox, + WalletAction, + WarningBox, +} from "../components/styled"; +import { useAsyncAsHook } from "../hooks/useAsyncAsHook"; +import * as wxApi from "../wxApi"; + +interface Props { + talerPayUri?: string; + goBack: () => void; +} + +export function DepositPage({ talerPayUri, goBack }: Props): VNode { + const [payStatus, setPayStatus] = useState<PreparePayResult | undefined>( + undefined, + ); + const [payResult, setPayResult] = useState<ConfirmPayResult | undefined>( + undefined, + ); + const [payErrMsg, setPayErrMsg] = useState< + OperationFailedError | string | undefined + >(undefined); + + const balance = useAsyncAsHook(wxApi.getBalance, [ + NotificationType.CoinWithdrawn, + ]); + 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; + // We use a string here so that dependency tracking for useEffect works properly + const foundAmountStr = foundAmount + ? Amounts.stringify(foundAmount) + : undefined; + + useEffect(() => { + if (!talerPayUri) return; + const doFetch = async (): Promise<void> => { + try { + const p = await wxApi.preparePay(talerPayUri); + setPayStatus(p); + } catch (e) { + console.log("Got error while trying to pay", e); + if (e instanceof OperationFailedError) { + setPayErrMsg(e); + } + if (e instanceof Error) { + setPayErrMsg(e.message); + } + } + }; + doFetch(); + }, [talerPayUri, foundAmountStr]); + + if (!talerPayUri) { + return <span>missing pay uri</span>; + } + + if (!payStatus) { + if (payErrMsg instanceof OperationFailedError) { + return ( + <WalletAction> + <LogoHeader /> + <h2>{i18n.str`Digital cash payment`}</h2> + <section> + <ErrorTalerOperation + title="Could not get the payment information for this order" + error={payErrMsg?.operationError} + /> + </section> + </WalletAction> + ); + } + 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 <span>Loading payment information ...</span>; + } + + const onClick = async (): Promise<void> => { + // try { + // const res = await doPayment(payStatus); + // setPayResult(res); + // } catch (e) { + // console.error(e); + // if (e instanceof Error) { + // setPayErrMsg(e.message); + // } + // } + }; + + return ( + <PaymentRequestView + uri={talerPayUri} + payStatus={payStatus} + payResult={payResult} + onClick={onClick} + balance={foundAmount} + /> + ); +} + +export interface PaymentRequestViewProps { + payStatus: PreparePayResult; + payResult?: ConfirmPayResult; + onClick: () => void; + payErrMsg?: string; + uri: string; + balance: AmountJson | undefined; +} +export function PaymentRequestView({ + uri, + payStatus, + payResult, + onClick, + balance, +}: PaymentRequestViewProps): VNode { + let totalFees: AmountJson = Amounts.getZero(payStatus.amountRaw); + const contractTerms: ContractTerms = payStatus.contractTerms; + + return ( + <WalletAction> + <LogoHeader /> + + <h2>{i18n.str`Digital cash deposit`}</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={amountToPretty( + Amounts.parseOrThrow(payStatus.amountEffective), + )} + kind="negative" + /> + )} + <Part + big + title="Purchase amount" + text={amountToPretty(Amounts.parseOrThrow(payStatus.amountRaw))} + kind="neutral" + /> + {Amounts.isNonZero(totalFees) && ( + <Fragment> + <Part + big + title="Fee" + text={amountToPretty(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> + </WalletAction> + ); +} diff --git a/packages/taler-wallet-webextension/src/cta/Pay.tsx b/packages/taler-wallet-webextension/src/cta/Pay.tsx index d7419d410..e61d3a9d6 100644 --- a/packages/taler-wallet-webextension/src/cta/Pay.tsx +++ b/packages/taler-wallet-webextension/src/cta/Pay.tsx @@ -57,35 +57,10 @@ import * as wxApi from "../wxApi"; interface Props { talerPayUri?: string; - goToWalletManualWithdraw: () => void; + goToWalletManualWithdraw: (currency?: string) => void; + goBack: () => void; } -// 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> => { |