diff options
Diffstat (limited to 'packages/taler-wallet-webextension/src/cta')
11 files changed, 1065 insertions, 0 deletions
diff --git a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx b/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx new file mode 100644 index 000000000..38e3d0f35 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx @@ -0,0 +1,96 @@ +/* + 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 './Pay'; + +export default { + title: 'cta/pay', + component: TestedComponent, + argTypes: { + }, +}; + +export const InsufficientBalance = createExample(TestedComponent, { + payStatus: { + status: PreparePayResultType.InsufficientBalance, + proposalId: "proposal1234", + contractTerms: { + merchant: { + name: 'someone' + }, + amount: 'USD:10', + } as Partial<ContractTerms> as any, + amountRaw: 'USD:10', + } +}); + +export const PaymentPossible = createExample(TestedComponent, { + payStatus: { + status: PreparePayResultType.PaymentPossible, + amountEffective: 'USD:10', + amountRaw: 'USD:10', + contractTerms: { + merchant: { + name: 'someone' + }, + amount: 'USD:10', + } 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! ', + 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' + }, + amount: 'USD:10', + } as Partial<ContractTerms> as any, + contractTermsHash: '123456', + proposalId: 'proposal1234', + paid: false, + } +}); diff --git a/packages/taler-wallet-webextension/src/cta/Pay.tsx b/packages/taler-wallet-webextension/src/cta/Pay.tsx new file mode 100644 index 000000000..a5849bb28 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/Pay.tsx @@ -0,0 +1,253 @@ +/* + This file is part of TALER + (C) 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * Page shown to the user to confirm entering + * a contract. + */ + +/** + * Imports. + */ +// import * as i18n from "../i18n"; + +import { renderAmount, ProgressButton } from "../renderHtml"; +import * as wxApi from "../wxApi"; + +import { useState, useEffect } from "preact/hooks"; + +import { ConfirmPayResultDone, getJsonI18n, i18n } from "@gnu-taler/taler-util"; +import { + PreparePayResult, + ConfirmPayResult, + AmountJson, + PreparePayResultType, + Amounts, + ContractTerms, + ConfirmPayResultType, +} from "@gnu-taler/taler-util"; +import { JSX, VNode } from "preact"; + +interface Props { + talerPayUri?: string +} + +export function AlreadyPaid({ payStatus }: { payStatus: PreparePayResult }) { + const fulfillmentUrl = payStatus.contractTerms.fulfillment_url; + let message; + if (fulfillmentUrl) { + message = ( + <span> + You have already paid for this article. Click{" "} + <a href={fulfillmentUrl} target="_bank" rel="external">here</a> to view it again. + </span> + ); + } else { + message = <span> + You have already paid for this article:{" "} + <em> + {payStatus.contractTerms.fulfillment_message ?? "no message given"} + </em> + </span>; + } + return <section class="main"> + <h1>GNU Taler Wallet</h1> + <article class="fade"> + {message} + </article> + </section> +} + +const doPayment = async (payStatus: PreparePayResult): Promise<ConfirmPayResultDone> => { + if (payStatus.status !== "payment-possible") { + throw Error(`invalid state: ${payStatus.status}`); + } + const proposalId = payStatus.proposalId; + const res = await wxApi.confirmPay(proposalId, undefined); + if (res.type !== ConfirmPayResultType.Done) { + throw Error("payment pending"); + } + const fu = res.contractTerms.fulfillment_url; + if (fu) { + document.location.href = fu; + } + return res; +}; + + + +export function PayPage({ talerPayUri }: Props): JSX.Element { + const [payStatus, setPayStatus] = useState<PreparePayResult | undefined>(undefined); + const [payResult, setPayResult] = useState<ConfirmPayResult | undefined>(undefined); + const [payErrMsg, setPayErrMsg] = useState<string | undefined>(""); + + useEffect(() => { + if (!talerPayUri) return; + const doFetch = async (): Promise<void> => { + const p = await wxApi.preparePay(talerPayUri); + setPayStatus(p); + }; + doFetch(); + }, [talerPayUri]); + + if (!talerPayUri) { + return <span>missing pay uri</span> + } + + if (!payStatus) { + return <span>Loading payment information ...</span>; + } + + if (payResult && payResult.type === ConfirmPayResultType.Done) { + if (payResult.contractTerms.fulfillment_message) { + const obj = { + fulfillment_message: payResult.contractTerms.fulfillment_message, + fulfillment_message_i18n: + payResult.contractTerms.fulfillment_message_i18n, + }; + const msg = getJsonI18n(obj, "fulfillment_message"); + return ( + <div> + <p>Payment succeeded.</p> + <p>{msg}</p> + </div> + ); + } else { + return <span>Redirecting ...</span>; + } + } + + const onClick = async () => { + try { + const res = await doPayment(payStatus) + setPayResult(res); + } catch (e) { + console.error(e); + setPayErrMsg(e.message); + } + + } + + return <PaymentRequestView payStatus={payStatus} onClick={onClick} payErrMsg={payErrMsg} />; +} + +export interface PaymentRequestViewProps { + payStatus: PreparePayResult; + onClick: () => void; + payErrMsg?: string; + +} +export function PaymentRequestView({ payStatus, onClick, payErrMsg }: PaymentRequestViewProps) { + let totalFees: AmountJson | undefined = undefined; + let insufficientBalance = false; + const [loading, setLoading] = useState(false); + const contractTerms: ContractTerms = payStatus.contractTerms; + + if ( + payStatus.status === PreparePayResultType.AlreadyConfirmed + ) { + return <AlreadyPaid payStatus={payStatus} /> + } + + if (!contractTerms) { + return ( + <span> + Error: did not get contract terms from merchant or wallet backend. + </span> + ); + } + + if (payStatus.status == PreparePayResultType.InsufficientBalance) { + insufficientBalance = true; + } + + if (payStatus.status === PreparePayResultType.PaymentPossible) { + const amountRaw = Amounts.parseOrThrow(payStatus.amountRaw); + const amountEffective: AmountJson = Amounts.parseOrThrow( + payStatus.amountEffective, + ); + totalFees = Amounts.sub(amountEffective, amountRaw).amount; + } + + let merchantName: VNode; + if (contractTerms.merchant && contractTerms.merchant.name) { + merchantName = <strong>{contractTerms.merchant.name}</strong>; + } else { + merchantName = <strong>(pub: {contractTerms.merchant_pub})</strong>; + } + + const amount = ( + <strong>{renderAmount(Amounts.parseOrThrow(contractTerms.amount))}</strong> + ); + + return <section class="main"> + <h1>GNU Taler Wallet</h1> + <article class="fade"> + <div> + <p> + <i18n.Translate> + The merchant <span>{merchantName}</span> offers you to purchase: + </i18n.Translate> + <div style={{ textAlign: "center" }}> + <strong>{contractTerms.summary}</strong> + </div> + {totalFees ? ( + <i18n.Translate> + The total price is <span>{amount} </span> + (plus <span>{renderAmount(totalFees)}</span> fees). + </i18n.Translate> + ) : ( + <i18n.Translate> + The total price is <span>{amount}</span>. + </i18n.Translate> + )} + </p> + + {insufficientBalance ? ( + <div> + <p style={{ color: "red", fontWeight: "bold" }}> + Unable to pay: Your balance is insufficient. + </p> + </div> + ) : null} + + {payErrMsg ? ( + <div> + <p>Payment failed: {payErrMsg}</p> + <button + class="pure-button button-success" + onClick={onClick} + > + {i18n.str`Retry`} + </button> + </div> + ) : ( + <div> + <ProgressButton + isLoading={loading} + disabled={insufficientBalance} + onClick={onClick} + > + {i18n.str`Confirm payment`} + </ProgressButton> + </div> + )} + </div> + </article> + </section> + + +}
\ No newline at end of file diff --git a/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx b/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx new file mode 100644 index 000000000..88e714cb7 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx @@ -0,0 +1,77 @@ +/* + 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 { OrderShortInfo } from '@gnu-taler/taler-util'; +import { createExample } from '../test-utils'; +import { View as TestedComponent } from './Refund'; + + +export default { + title: 'cta/refund', + component: TestedComponent, + 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, + 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, + 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, + pendingAtExchange: true, + proposalId: "proposal123", + } +}); diff --git a/packages/taler-wallet-webextension/src/cta/Refund.tsx b/packages/taler-wallet-webextension/src/cta/Refund.tsx new file mode 100644 index 000000000..bb26d933b --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/Refund.tsx @@ -0,0 +1,95 @@ +/* + This file is part of TALER + (C) 2015-2016 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 that shows refund status for purchases. + * + * @author Florian Dold + */ + +import * as wxApi from "../wxApi"; +import { AmountView } from "../renderHtml"; +import { + ApplyRefundResponse, + Amounts, +} from "@gnu-taler/taler-util"; +import { useEffect, useState } from "preact/hooks"; +import { JSX } from "preact/jsx-runtime"; + +interface Props { + 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) ? ( + <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 [errMsg, setErrMsg] = useState<string | undefined>(undefined); + + useEffect(() => { + if (!talerRefundUri) return; + const doFetch = async (): Promise<void> => { + try { + const result = await wxApi.applyRefund(talerRefundUri); + setApplyResult(result); + } catch (e) { + console.error(e); + setErrMsg(e.message); + console.log("err message", e.message); + } + }; + doFetch(); + }, [talerRefundUri]); + + console.log("rendering"); + + if (!talerRefundUri) { + return <span>missing taler refund uri</span>; + } + + if (errMsg) { + return <span>Error: {errMsg}</span>; + } + + if (!applyResult) { + return <span>Updating refund status</span>; + } + + return <View applyResult={applyResult} />; +} diff --git a/packages/taler-wallet-webextension/src/cta/Tip.stories.tsx b/packages/taler-wallet-webextension/src/cta/Tip.stories.tsx new file mode 100644 index 000000000..389b183f0 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/Tip.stories.tsx @@ -0,0 +1,59 @@ +/* + 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 { createExample } from '../test-utils'; +import { View as TestedComponent } from './Tip'; + + +export default { + title: 'cta/tip', + component: TestedComponent, + argTypes: { + }, +}; + +export const Accepted = createExample(TestedComponent, { + prepareTipResult: { + accepted: true, + merchantBaseUrl: '', + exchangeBaseUrl: '', + expirationTimestamp : { + t_ms: 0 + }, + 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 + }, + 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 new file mode 100644 index 000000000..69886668b --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/Tip.tsx @@ -0,0 +1,110 @@ +/* + This file is part of TALER + (C) 2017 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 accept or ignore a tip from a merchant. + * + * @author Florian Dold <dold@taler.net> + */ + +import { useEffect, useState } from "preact/hooks"; +import { PrepareTipResult } from "@gnu-taler/taler-util"; +import { AmountView } from "../renderHtml"; +import * as wxApi from "../wxApi"; +import { JSX } from "preact/jsx-runtime"; + +interface Props { + 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> + ) : ( + <div> + <p> + The merchant <code>{prepareTipResult.merchantBaseUrl}</code> is + offering you a tip of{" "} + <strong> + <AmountView amount={prepareTipResult.tipAmountEffective} /> + </strong>{" "} + via the exchange <code>{prepareTipResult.exchangeBaseUrl}</code> + </p> + <button onClick={onAccept}>Accept tip</button> + <button onClick={onIgnore}>Ignore</button> + </div> + )} + </article> + </section> + +} + +export function TipPage({ talerTipUri }: Props): JSX.Element { + const [updateCounter, setUpdateCounter] = useState<number>(0); + const [prepareTipResult, setPrepareTipResult] = useState< + PrepareTipResult | undefined + >(undefined); + + const [tipIgnored, setTipIgnored] = useState(false); + + useEffect(() => { + if (!talerTipUri) return; + const doFetch = async (): Promise<void> => { + const p = await wxApi.prepareTip({ talerTipUri }); + setPrepareTipResult(p); + }; + doFetch(); + }, [talerTipUri, updateCounter]); + + const doAccept = async () => { + if (!prepareTipResult) { + return; + } + await wxApi.acceptTip({ walletTipId: prepareTipResult?.walletTipId }); + setUpdateCounter(updateCounter + 1); + }; + + const doIgnore = () => { + setTipIgnored(true); + }; + + if (!talerTipUri) { + return <span>missing tip uri</span>; + } + + if (tipIgnored) { + return <span>You've ignored the tip.</span>; + } + + if (!prepareTipResult) { + return <span>Loading ...</span>; + } + + 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 new file mode 100644 index 000000000..747f855fa --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx @@ -0,0 +1,45 @@ +/* + 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 { createExample } from '../test-utils'; +import { View as TestedComponent } from './Withdraw'; + + +export default { + title: 'cta/withdraw', + component: TestedComponent, + argTypes: { + }, +}; + +export const CompleteWithExchange = createExample(TestedComponent, { + details: { + amount: 'USD:2', + possibleExchanges: [], + }, + selectedExchange: 'Some exchange' +}) +export const CompleteWithoutExchange = createExample(TestedComponent, { + details: { + amount: 'USD:2', + possibleExchanges: [], + }, +}) diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx new file mode 100644 index 000000000..b5182b070 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx @@ -0,0 +1,172 @@ +/* + This file is part of TALER + (C) 2015-2016 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 creation + * of a reserve, usually requested by the bank. + * + * @author Florian Dold + */ + +import { i18n } from '@gnu-taler/taler-util' +import { renderAmount } from "../renderHtml"; + +import { useState, useEffect } from "preact/hooks"; +import { + acceptWithdrawal, + onUpdateNotification, + getWithdrawalDetailsForUri, +} from "../wxApi"; +import { WithdrawUriInfoResponse } from "@gnu-taler/taler-util"; +import { JSX } from "preact/jsx-runtime"; +import { WalletAction } from '../components/styled'; + +interface Props { + talerWithdrawUri?: string; +} + +export interface ViewProps { + details: WithdrawUriInfoResponse; + selectedExchange?: string; + accept: () => Promise<void>; + setCancelled: (b: boolean) => void; + setSelecting: (b: boolean) => void; +}; + +export function View({ details, selectedExchange, accept, setCancelled, setSelecting }: ViewProps) { + + return ( + <WalletAction> + <div style="border-bottom: 3px dashed #aa3939; margin-bottom: 2em;"> + <h1 style="font-family: monospace; font-size: 250%;"> + <span style="color: #aa3939;">❰</span>Taler Wallet<span style="color: #aa3939;">❱</span> + </h1> + </div> + <div class="fade"> + <div> + <h1><i18n.Translate>Digital Cash Withdrawal</i18n.Translate></h1> + <p><i18n.Translate> + You are about to withdraw{" "} + <strong>{renderAmount(details.amount)}</strong> from your bank account + into your wallet. + </i18n.Translate></p> + {selectedExchange ? ( + <p><i18n.Translate> + The exchange <strong>{selectedExchange}</strong> will be used as the + Taler payment service provider. + </i18n.Translate></p> + ) : null} + + <div> + <button + class="pure-button button-success" + disabled={!selectedExchange} + onClick={() => accept()} + > + {i18n.str`Accept fees and withdraw`} + </button> + <p> + <span + role="button" + tabIndex={0} + style={{ textDecoration: "underline", cursor: "pointer" }} + onClick={() => setSelecting(true)} + > + {i18n.str`Chose different exchange provider`} + </span> + <br /> + <span + role="button" + tabIndex={0} + style={{ textDecoration: "underline", cursor: "pointer" }} + onClick={() => setCancelled(true)} + > + {i18n.str`Cancel withdraw operation`} + </span> + </p> + </div> + </div> + </div> + </WalletAction> + ) +} + +export function WithdrawPage({ talerWithdrawUri, ...rest }: Props): JSX.Element { + const [details, setDetails] = useState<WithdrawUriInfoResponse | undefined>(undefined); + const [selectedExchange, setSelectedExchange] = useState<string | undefined>(undefined); + const [cancelled, setCancelled] = useState(false); + const [selecting, setSelecting] = useState(false); + const [error, setError] = useState<boolean>(false); + const [updateCounter, setUpdateCounter] = useState(1); + const [state, setState] = useState(1) + + useEffect(() => { + return onUpdateNotification(() => { + console.log('updating...') + setUpdateCounter(updateCounter + 1); + }); + }, []); + + useEffect(() => { + console.log('on effect yes', talerWithdrawUri) + if (!talerWithdrawUri) return + const fetchData = async (): Promise<void> => { + try { + const res = await getWithdrawalDetailsForUri({ talerWithdrawUri }); + setDetails(res); + if (res.defaultExchangeBaseUrl) { + setSelectedExchange(res.defaultExchangeBaseUrl); + } + } catch (e) { + console.error('error',JSON.stringify(e,undefined,2)) + setError(true) + } + }; + fetchData(); + }, [selectedExchange, selecting, talerWithdrawUri, updateCounter, state]); + + if (!talerWithdrawUri) { + return <span><i18n.Translate>missing withdraw uri</i18n.Translate></span>; + } + + const accept = async (): Promise<void> => { + if (!selectedExchange) { + throw Error("can't accept, no exchange selected"); + } + console.log("accepting exchange", selectedExchange); + const res = await acceptWithdrawal(talerWithdrawUri, selectedExchange); + console.log("accept withdrawal response", res); + if (res.confirmTransferUrl) { + document.location.href = res.confirmTransferUrl; + } + }; + + if (!details) { + return <span><i18n.Translate>Loading...</i18n.Translate></span>; + } + if (cancelled) { + return <span><i18n.Translate>Withdraw operation has been cancelled.</i18n.Translate></span>; + } + if (error) { + return <span><i18n.Translate>This URI is not valid anymore.</i18n.Translate></span>; + } + + return <View accept={accept} + setCancelled={setCancelled} setSelecting={setSelecting} + details={details} selectedExchange={selectedExchange} + /> +} + diff --git a/packages/taler-wallet-webextension/src/cta/payback.tsx b/packages/taler-wallet-webextension/src/cta/payback.tsx new file mode 100644 index 000000000..4233b1f96 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/payback.tsx @@ -0,0 +1,31 @@ +/* + This file is part of TALER + (C) 2017 Inria + + 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/> + */ + +import { JSX } from "preact/jsx-runtime"; + +/** + * View and edit auditors. + * + * @author Florian Dold + */ + +/** + * Imports. + */ + +export function makePaybackPage(): JSX.Element { + return <div>not implemented</div>; +} diff --git a/packages/taler-wallet-webextension/src/cta/reset-required.tsx b/packages/taler-wallet-webextension/src/cta/reset-required.tsx new file mode 100644 index 000000000..87751561c --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/reset-required.tsx @@ -0,0 +1,97 @@ +/* + This file is part of TALER + (C) 2017 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 to inform the user when a database reset is required. + * + * @author Florian Dold + */ + +import { Component, JSX } from "preact"; +import * as wxApi from "../wxApi"; + +interface State { + /** + * Did the user check the confirmation check box? + */ + checked: boolean; + + /** + * Do we actually need to reset the db? + */ + resetRequired: boolean; +} + +class ResetNotification extends Component<any, State> { + constructor(props: any) { + super(props); + this.state = { checked: false, resetRequired: true }; + setInterval(() => this.update(), 500); + } + async update(): Promise<void> { + const res = await wxApi.checkUpgrade(); + this.setState({ resetRequired: res.dbResetRequired }); + } + render(): JSX.Element { + if (this.state.resetRequired) { + return ( + <div> + <h1>Manual Reset Required</h1> + <p> + The wallet's database in your browser is incompatible with the{" "} + currently installed wallet. Please reset manually. + </p> + <p> + Once the database format has stabilized, we will provide automatic + upgrades. + </p> + <input + id="check" + type="checkbox" + checked={this.state.checked} + onChange={() => { + this.setState(prev => ({ checked: prev.checked })) + }} + />{" "} + <label htmlFor="check"> + I understand that I will lose all my data + </label> + <br /> + <button + class="pure-button" + disabled={!this.state.checked} + onClick={() => wxApi.resetDb()} + > + Reset + </button> + </div> + ); + } + return ( + <div> + <h1>Everything is fine!</h1>A reset is not required anymore, you can + close this page. + </div> + ); + } +} + +/** + * @deprecated to be removed + */ +export function createResetRequiredPage(): JSX.Element { + return <ResetNotification />; +} diff --git a/packages/taler-wallet-webextension/src/cta/return-coins.tsx b/packages/taler-wallet-webextension/src/cta/return-coins.tsx new file mode 100644 index 000000000..2273d1454 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/return-coins.tsx @@ -0,0 +1,30 @@ +/* + This file is part of TALER + (C) 2017 Inria + + 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/> + */ + +import { JSX } from "preact/jsx-runtime"; + +/** + * Return coins to own bank account. + * + * @author Florian Dold + */ + +/** + * Imports. + */ +export function createReturnCoinsPage(): JSX.Element { + return <span>Not implemented yet.</span>; +} |