From d84424202dca22fff22cb1d304286f627642187b Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 31 Aug 2022 00:20:35 -0300 Subject: p2p tx rendering --- .../src/NavigationBar.tsx | 12 +- .../src/components/TransactionItem.tsx | 54 ++++- .../src/cta/InvoiceCreate/index.ts | 79 +++++++ .../src/cta/InvoiceCreate/state.ts | 113 ++++++++++ .../src/cta/InvoiceCreate/stories.tsx | 57 +++++ .../src/cta/InvoiceCreate/test.ts | 31 +++ .../src/cta/InvoiceCreate/views.tsx | 150 +++++++++++++ .../src/cta/InvoicePay/index.ts | 67 ++++++ .../src/cta/InvoicePay/state.ts | 74 ++++++ .../src/cta/InvoicePay/stories.tsx | 36 +++ .../src/cta/InvoicePay/test.ts | 31 +++ .../src/cta/InvoicePay/views.tsx | 85 +++++++ .../src/cta/TransferCreate/index.ts | 78 +++++++ .../src/cta/TransferCreate/state.ts | 86 +++++++ .../src/cta/TransferCreate/stories.tsx | 56 +++++ .../src/cta/TransferCreate/test.ts | 31 +++ .../src/cta/TransferCreate/views.tsx | 117 ++++++++++ .../src/cta/TransferPickup/index.ts | 67 ++++++ .../src/cta/TransferPickup/state.ts | 72 ++++++ .../src/cta/TransferPickup/stories.tsx | 36 +++ .../src/cta/TransferPickup/test.ts | 31 +++ .../src/cta/TransferPickup/views.tsx | 74 ++++++ .../src/cta/index.stories.ts | 6 +- .../src/platform/chrome.ts | 26 ++- packages/taler-wallet-webextension/src/stories.tsx | 7 +- .../src/wallet/Application.tsx | 26 ++- .../src/wallet/History.stories.tsx | 47 ++++ .../src/wallet/Invoice/index.ts | 66 ------ .../src/wallet/Invoice/state.ts | 37 --- .../src/wallet/Invoice/stories.tsx | 29 --- .../src/wallet/Invoice/test.ts | 31 --- .../src/wallet/Invoice/views.tsx | 56 ----- .../src/wallet/Send/index.ts | 67 ------ .../src/wallet/Send/state.ts | 66 ------ .../src/wallet/Send/stories.tsx | 29 --- .../src/wallet/Send/test.ts | 31 --- .../src/wallet/Send/views.tsx | 58 ----- .../src/wallet/Transaction.stories.tsx | 44 ++++ .../src/wallet/Transaction.tsx | 249 +++++++++++++++++++++ packages/taler-wallet-webextension/src/wxApi.ts | 31 +++ .../taler-wallet-webextension/src/wxBackend.ts | 26 ++- 41 files changed, 1879 insertions(+), 490 deletions(-) create mode 100644 packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts create mode 100644 packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts create mode 100644 packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx create mode 100644 packages/taler-wallet-webextension/src/cta/InvoiceCreate/test.ts create mode 100644 packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx create mode 100644 packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts create mode 100644 packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts create mode 100644 packages/taler-wallet-webextension/src/cta/InvoicePay/stories.tsx create mode 100644 packages/taler-wallet-webextension/src/cta/InvoicePay/test.ts create mode 100644 packages/taler-wallet-webextension/src/cta/InvoicePay/views.tsx create mode 100644 packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts create mode 100644 packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts create mode 100644 packages/taler-wallet-webextension/src/cta/TransferCreate/stories.tsx create mode 100644 packages/taler-wallet-webextension/src/cta/TransferCreate/test.ts create mode 100644 packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx create mode 100644 packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts create mode 100644 packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts create mode 100644 packages/taler-wallet-webextension/src/cta/TransferPickup/stories.tsx create mode 100644 packages/taler-wallet-webextension/src/cta/TransferPickup/test.ts create mode 100644 packages/taler-wallet-webextension/src/cta/TransferPickup/views.tsx delete mode 100644 packages/taler-wallet-webextension/src/wallet/Invoice/index.ts delete mode 100644 packages/taler-wallet-webextension/src/wallet/Invoice/state.ts delete mode 100644 packages/taler-wallet-webextension/src/wallet/Invoice/stories.tsx delete mode 100644 packages/taler-wallet-webextension/src/wallet/Invoice/test.ts delete mode 100644 packages/taler-wallet-webextension/src/wallet/Invoice/views.tsx delete mode 100644 packages/taler-wallet-webextension/src/wallet/Send/index.ts delete mode 100644 packages/taler-wallet-webextension/src/wallet/Send/state.ts delete mode 100644 packages/taler-wallet-webextension/src/wallet/Send/stories.tsx delete mode 100644 packages/taler-wallet-webextension/src/wallet/Send/test.ts delete mode 100644 packages/taler-wallet-webextension/src/wallet/Send/views.tsx (limited to 'packages/taler-wallet-webextension') diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx b/packages/taler-wallet-webextension/src/NavigationBar.tsx index 1c4873b04..9b222cdb4 100644 --- a/packages/taler-wallet-webextension/src/NavigationBar.tsx +++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx @@ -108,16 +108,20 @@ export const Pages = { "/settings/exchange/add/:currency?", ), - invoice: pageDefinition<{ amount?: string }>("/invoice/:amount?"), - send: pageDefinition<{ amount?: string }>("/send/:amount?"), - cta: pageDefinition<{ action: string }>("/cta/:action"), ctaPay: "/cta/pay", ctaRefund: "/cta/refund", ctaTips: "/cta/tip", ctaWithdraw: "/cta/withdraw", ctaDeposit: "/cta/deposit", - + ctaInvoiceCreate: pageDefinition<{ amount?: string }>( + "/cta/invoice/create/:amount?", + ), + ctaTransferCreate: pageDefinition<{ amount?: string }>( + "/cta/transfer/create/:amount?", + ), + ctaInvoicePay: "/cta/invoice/pay", + ctaTransferPickup: "/cta/transfer/pickup", ctaWithdrawManual: pageDefinition<{ amount?: string }>( "/cta/manual-withdraw/:amount?", ), diff --git a/packages/taler-wallet-webextension/src/components/TransactionItem.tsx b/packages/taler-wallet-webextension/src/components/TransactionItem.tsx index 8033b3ee3..6dcee6eca 100644 --- a/packages/taler-wallet-webextension/src/components/TransactionItem.tsx +++ b/packages/taler-wallet-webextension/src/components/TransactionItem.tsx @@ -113,8 +113,58 @@ export function TransactionItem(props: { tx: Transaction }): VNode { pending={tx.pending} /> ); - default: - throw Error("unsupported transaction type"); + case TransactionType.PeerPullCredit: + return ( + + ); + case TransactionType.PeerPullDebit: + return ( + + ); + case TransactionType.PeerPushCredit: + return ( + + ); + case TransactionType.PeerPushDebit: + return ( + + ); + default: { + const pe: never = tx; + throw Error(`unsupported transaction type ${pe}`); + } } } diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts new file mode 100644 index 000000000..f12fd80e0 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts @@ -0,0 +1,79 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { Loading } from "../../components/Loading.js"; +import { HookError } from "../../hooks/useAsyncAsHook.js"; +import { compose, StateViewMap } from "../../utils/index.js"; +import { LoadingUriView, ReadyView, ShowQrView } from "./views.js"; +import * as wxApi from "../../wxApi.js"; +import { useComponentState } from "./state.js"; +import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util"; +import { ButtonHandler, SelectFieldHandler, TextFieldHandler } from "../../mui/handlers.js"; + +export interface Props { + amount: string; +} + +export type State = + | State.Loading + | State.LoadingUriError + | State.ShowQr + | State.Ready; + +export namespace State { + + export interface Loading { + status: "loading"; + error: undefined; + } + + export interface LoadingUriError { + status: "loading-uri"; + error: HookError; + } + + export interface BaseInfo { + error: undefined; + } + export interface ShowQr extends BaseInfo { + status: "show-qr"; + talerUri: string; + close: () => void; + } + export interface Ready extends BaseInfo { + status: "ready"; + showQr: ButtonHandler; + copyToClipboard: ButtonHandler; + subject: TextFieldHandler; + toBeReceived: AmountJson, + chosenAmount: AmountJson, + exchangeUrl: string; + invalid: boolean; + error: undefined; + operationError?: TalerErrorDetail; + } +} + +const viewMapping: StateViewMap = { + loading: Loading, + "loading-uri": LoadingUriView, + "show-qr": ShowQrView, + "ready": ReadyView, +}; + + +export const InvoiceCreatePage = compose("InvoiceCreatePage", (p: Props) => useComponentState(p, wxApi), viewMapping) + diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts new file mode 100644 index 000000000..dd9220480 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts @@ -0,0 +1,113 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { Amounts, TalerErrorDetail } from "@gnu-taler/taler-util"; +import { TalerError } from "@gnu-taler/taler-wallet-core"; +import { useState } from "preact/hooks"; +import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; +import * as wxApi from "../../wxApi.js"; +import { Props, State } from "./index.js"; + +export function useComponentState( + { amount: amountStr }: Props, + api: typeof wxApi, +): State { + const amount = Amounts.parseOrThrow(amountStr) + + const [subject, setSubject] = useState(""); + const [talerUri, setTalerUri] = useState("") + + const hook = useAsyncAsHook(api.listExchanges); + const [exchangeIdx, setExchangeIdx] = useState("0") + const [operationError, setOperationError] = useState(undefined) + + + if (!hook) { + return { + status: "loading", + error: undefined, + } + } + if (hook.hasError) { + return { + status: "loading-uri", + error: hook, + }; + } + + if (talerUri) { + return { + status: "show-qr", + talerUri, + error: undefined, + close: () => { null }, + // chosenAmount: amount, + // toBeReceived: amount, + } + } + + const exchanges = hook.response.exchanges.filter(e => e.currency === amount.currency); + const exchangeMap = exchanges.reduce((prev, cur, idx) => ({ ...prev, [String(idx)]: cur.exchangeBaseUrl }), {} as Record) + const selected = exchanges[Number(exchangeIdx)]; + + async function accept(): Promise { + try { + + const resp = await api.initiatePeerPullPayment({ + amount: Amounts.stringify(amount), + exchangeBaseUrl: selected.exchangeBaseUrl, + partialContractTerms: { + summary: subject + } + }) + return resp.talerUri + } catch (e) { + if (e instanceof TalerError) { + setOperationError(e.errorDetail) + } + console.error(e) + throw Error("error trying to accept") + } + } + + + return { + status: "ready", + subject: { + error: !subject ? "cant be empty" : undefined, + value: subject, + onInput: async (e) => setSubject(e) + }, + invalid: !subject || Amounts.isZero(amount), + exchangeUrl: selected.exchangeBaseUrl, + copyToClipboard: { + onClick: async () => { + const uri = await accept(); + navigator.clipboard.writeText(uri || ""); + } + }, + showQr: { + onClick: async () => { + const uri = await accept(); + setTalerUri(uri) + } + }, + chosenAmount: amount, + toBeReceived: amount, + error: undefined, + operationError + } +} diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx new file mode 100644 index 000000000..e6252062e --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx @@ -0,0 +1,57 @@ +/* + This file is part of GNU Taler + (C) 2022 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { createExample } from "../../test-utils.js"; +import { ReadyView, ShowQrView } from "./views.js"; + +export default { + title: "wallet/invoice create", +}; + +export const ShowQr = createExample(ShowQrView, { + talerUri: + "taler://pay-pull/exchange.taler.ar/HS585JK0QCXHJ8Z8QWZA3EBAY5WY7XNC1RR2MHJXSH2Z4WP0YPJ0", + close: () => { + null; + }, +}); + +export const Ready = createExample(ReadyView, { + chosenAmount: { + currency: "ARS", + value: 1, + fraction: 0, + }, + toBeReceived: { + currency: "ARS", + value: 1, + fraction: 0, + }, + exchangeUrl: "https://exchange.taler.ar", + subject: { + value: "some subject", + onInput: async () => { + null; + }, + }, + copyToClipboard: {}, + showQr: {}, +}); diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/test.ts b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/test.ts new file mode 100644 index 000000000..631e76d01 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/test.ts @@ -0,0 +1,31 @@ +/* + This file is part of GNU Taler + (C) 2022 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { expect } from "chai"; + +describe("test description", () => { + + it("should assert", () => { + + expect([]).deep.equals([]) + }); +}) + diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx new file mode 100644 index 000000000..ebb15e75c --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx @@ -0,0 +1,150 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { h, VNode } from "preact"; +import { LoadingError } from "../../components/LoadingError.js"; +import { LogoHeader } from "../../components/LogoHeader.js"; +import { Part } from "../../components/Part.js"; +import { QR } from "../../components/QR.js"; +import { + Link, + SubTitle, + SvgIcon, + WalletAction, +} from "../../components/styled/index.js"; +import { useTranslationContext } from "../../context/translation.js"; +import { Button } from "../../mui/Button.js"; +import { Grid } from "../../mui/Grid.js"; +import { TextField } from "../../mui/TextField.js"; +import editIcon from "../../svg/edit_24px.svg"; +import { ExchangeDetails, InvoiceDetails } from "../../wallet/Transaction.js"; +import { State } from "./index.js"; + +export function LoadingUriView({ error }: State.LoadingUriError): VNode { + const { i18n } = useTranslationContext(); + + return ( + Could not load} + error={error} + /> + ); +} + +export function ShowQrView({ talerUri, close }: State.ShowQr): VNode { + const { i18n } = useTranslationContext(); + return ( + + + + Digital invoice + +
+

Scan this QR code with the wallet

+ +
+
+ + Close + +
+
+ ); +} + +export function ReadyView({ + invalid, + exchangeUrl, + subject, + showQr, + operationError, + copyToClipboard, + toBeReceived, + chosenAmount, +}: State.Ready): VNode { + const { i18n } = useTranslationContext(); + + return ( + + + + Digital invoice + +
+ + + + Exchange + + + + + } + text={} + kind="neutral" + big + /> + + Details} + text={ + + } + /> +
+
+

How do you want to send the invoice?

+ + + + + + + + + +
+
+ ); +} diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts b/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts new file mode 100644 index 000000000..8d1612c7a --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts @@ -0,0 +1,67 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util"; +import { Loading } from "../../components/Loading.js"; +import { HookError } from "../../hooks/useAsyncAsHook.js"; +import { ButtonHandler } from "../../mui/handlers.js"; +import { compose, StateViewMap } from "../../utils/index.js"; +import * as wxApi from "../../wxApi.js"; +import { useComponentState } from "./state.js"; +import { LoadingUriView, ReadyView } from "./views.js"; + +export interface Props { + talerPayPullUri: string; +} + +export type State = + | State.Loading + | State.LoadingUriError + | State.Ready; + +export namespace State { + + export interface Loading { + status: "loading"; + error: undefined; + } + + export interface LoadingUriError { + status: "loading-uri"; + error: HookError; + } + + export interface BaseInfo { + error: undefined; + } + export interface Ready extends BaseInfo { + status: "ready"; + amount: AmountJson, + error: undefined; + accept: ButtonHandler; + operationError?: TalerErrorDetail; + } +} + +const viewMapping: StateViewMap = { + loading: Loading, + "loading-uri": LoadingUriView, + "ready": ReadyView, +}; + + +export const InvoicePayPage = compose("InvoicePayPage", (p: Props) => useComponentState(p, wxApi), viewMapping) + diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts b/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts new file mode 100644 index 000000000..53db117f9 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts @@ -0,0 +1,74 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { Amounts, TalerErrorDetail } from "@gnu-taler/taler-util"; +import { TalerError } from "@gnu-taler/taler-wallet-core"; +import { useState } from "preact/hooks"; +import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; +import * as wxApi from "../../wxApi.js"; +import { Props, State } from "./index.js"; + +export function useComponentState( + { talerPayPullUri }: Props, + api: typeof wxApi, +): State { + const hook = useAsyncAsHook(async () => { + return await api.checkPeerPullPayment({ + talerUri: talerPayPullUri + }) + }, []) + const [operationError, setOperationError] = useState(undefined) + + if (!hook) { + return { + status: "loading", + error: undefined, + } + } + if (hook.hasError) { + return { + status: "loading-uri", + error: hook, + }; + } + + const { amount, peerPullPaymentIncomingId } = hook.response + + async function accept(): Promise { + try { + const resp = await api.acceptPeerPullPayment({ + peerPullPaymentIncomingId + }) + } catch (e) { + if (e instanceof TalerError) { + setOperationError(e.errorDetail) + } + console.error(e) + throw Error("error trying to accept") + } + } + + + return { + status: "ready", + amount: Amounts.parseOrThrow(amount), + error: undefined, + accept: { + onClick: accept + }, + operationError + } +} diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/stories.tsx b/packages/taler-wallet-webextension/src/cta/InvoicePay/stories.tsx new file mode 100644 index 000000000..6adaa5c22 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/stories.tsx @@ -0,0 +1,36 @@ +/* + This file is part of GNU Taler + (C) 2022 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { createExample } from "../../test-utils.js"; +import { ReadyView } from "./views.js"; + +export default { + title: "wallet/invoice payment", +}; + +export const Ready = createExample(ReadyView, { + amount: { + currency: "ARS", + value: 1, + fraction: 0, + }, + accept: {}, +}); diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/test.ts b/packages/taler-wallet-webextension/src/cta/InvoicePay/test.ts new file mode 100644 index 000000000..631e76d01 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/test.ts @@ -0,0 +1,31 @@ +/* + This file is part of GNU Taler + (C) 2022 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { expect } from "chai"; + +describe("test description", () => { + + it("should assert", () => { + + expect([]).deep.equals([]) + }); +}) + diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/views.tsx b/packages/taler-wallet-webextension/src/cta/InvoicePay/views.tsx new file mode 100644 index 000000000..2960c3168 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/views.tsx @@ -0,0 +1,85 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { h, VNode } from "preact"; +import { Amount } from "../../components/Amount.js"; +import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js"; +import { LoadingError } from "../../components/LoadingError.js"; +import { LogoHeader } from "../../components/LogoHeader.js"; +import { Part } from "../../components/Part.js"; +import { QR } from "../../components/QR.js"; +import { + Link, + SubTitle, + SvgIcon, + WalletAction, +} from "../../components/styled/index.js"; +import { useTranslationContext } from "../../context/translation.js"; +import { Button } from "../../mui/Button.js"; +import { Grid } from "../../mui/Grid.js"; +import { TextField } from "../../mui/TextField.js"; +import editIcon from "../../svg/edit_24px.svg"; +import { ExchangeDetails, InvoiceDetails } from "../../wallet/Transaction.js"; +import { State } from "./index.js"; + +export function LoadingUriView({ error }: State.LoadingUriError): VNode { + const { i18n } = useTranslationContext(); + + return ( + Could not load} + error={error} + /> + ); +} + +export function ReadyView({ + operationError, + accept, + amount, +}: State.Ready): VNode { + const { i18n } = useTranslationContext(); + + return ( + + + + Digital invoice + + {operationError && ( + + Could not finish the payment operation + + } + error={operationError} + /> + )} +
+ Amount} + text={} + /> +
+
+ +
+
+ ); +} diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts b/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts new file mode 100644 index 000000000..fd034341e --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts @@ -0,0 +1,78 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { Loading } from "../../components/Loading.js"; +import { HookError } from "../../hooks/useAsyncAsHook.js"; +import { compose, StateViewMap } from "../../utils/index.js"; +import { LoadingUriView, ReadyView, ShowQrView } from "./views.js"; +import * as wxApi from "../../wxApi.js"; +import { useComponentState } from "./state.js"; +import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util"; +import { ButtonHandler, SelectFieldHandler, TextFieldHandler } from "../../mui/handlers.js"; + +export interface Props { + amount: string; +} + +export type State = + | State.Loading + | State.LoadingUriError + | State.ShowQr + | State.Ready; + +export namespace State { + + export interface Loading { + status: "loading"; + error: undefined; + } + + export interface LoadingUriError { + status: "loading-uri"; + error: HookError; + } + + export interface BaseInfo { + error: undefined; + } + export interface ShowQr extends BaseInfo { + status: "show-qr"; + talerUri: string; + close: () => void; + } + export interface Ready extends BaseInfo { + status: "ready"; + showQr: ButtonHandler; + invalid: boolean; + copyToClipboard: ButtonHandler; + toBeReceived: AmountJson, + chosenAmount: AmountJson, + subject: TextFieldHandler, + error: undefined; + operationError?: TalerErrorDetail; + } +} + +const viewMapping: StateViewMap = { + loading: Loading, + "loading-uri": LoadingUriView, + "show-qr": ShowQrView, + "ready": ReadyView, +}; + + +export const TransferCreatePage = compose("TransferCreatePage", (p: Props) => useComponentState(p, wxApi), viewMapping) + diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts b/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts new file mode 100644 index 000000000..9853f05ff --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts @@ -0,0 +1,86 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { Amounts, TalerErrorDetail } from "@gnu-taler/taler-util"; +import { TalerError } from "@gnu-taler/taler-wallet-core"; +import { useState } from "preact/hooks"; +import * as wxApi from "../../wxApi.js"; +import { Props, State } from "./index.js"; + +export function useComponentState( + { amount: amountStr }: Props, + api: typeof wxApi, +): State { + const amount = Amounts.parseOrThrow(amountStr) + + const [subject, setSubject] = useState(""); + const [talerUri, setTalerUri] = useState("") + const [operationError, setOperationError] = useState(undefined) + + + if (talerUri) { + return { + status: "show-qr", + talerUri, + error: undefined, + close: () => { null }, + } + } + + + async function accept(): Promise { + try { + + const resp = await api.initiatePeerPushPayment({ + amount: Amounts.stringify(amount), + partialContractTerms: { + summary: subject + } + }) + return resp.talerUri + } catch (e) { + if (e instanceof TalerError) { + setOperationError(e.errorDetail) + } + console.error(e) + throw Error("error trying to accept") + } + } + return { + status: "ready", + invalid: !subject || Amounts.isZero(amount), + subject: { + value: subject, + onInput: async (e) => setSubject(e) + }, + copyToClipboard: { + onClick: async () => { + const uri = await accept(); + navigator.clipboard.writeText(uri || ""); + } + }, + showQr: { + onClick: async () => { + const uri = await accept(); + setTalerUri(uri) + } + }, + chosenAmount: amount, + toBeReceived: amount, + error: undefined, + operationError + } +} diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/stories.tsx b/packages/taler-wallet-webextension/src/cta/TransferCreate/stories.tsx new file mode 100644 index 000000000..1e528df73 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/stories.tsx @@ -0,0 +1,56 @@ +/* + This file is part of GNU Taler + (C) 2022 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { createExample } from "../../test-utils.js"; +import { ReadyView, ShowQrView } from "./views.js"; + +export default { + title: "wallet/transfer create", +}; + +export const ShowQr = createExample(ShowQrView, { + talerUri: + "taler://pay-push/exchange.taler.ar/HS585JK0QCXHJ8Z8QWZA3EBAY5WY7XNC1RR2MHJXSH2Z4WP0YPJ0", + close: () => { + null; + }, +}); + +export const Ready = createExample(ReadyView, { + chosenAmount: { + currency: "ARS", + value: 1, + fraction: 0, + }, + toBeReceived: { + currency: "ARS", + value: 1, + fraction: 0, + }, + copyToClipboard: {}, + showQr: {}, + subject: { + value: "the subject", + onInput: async () => { + null; + }, + }, +}); diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/test.ts b/packages/taler-wallet-webextension/src/cta/TransferCreate/test.ts new file mode 100644 index 000000000..631e76d01 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/test.ts @@ -0,0 +1,31 @@ +/* + This file is part of GNU Taler + (C) 2022 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { expect } from "chai"; + +describe("test description", () => { + + it("should assert", () => { + + expect([]).deep.equals([]) + }); +}) + diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx b/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx new file mode 100644 index 000000000..ebdf1e746 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx @@ -0,0 +1,117 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { h, VNode } from "preact"; +import { LoadingError } from "../../components/LoadingError.js"; +import { LogoHeader } from "../../components/LogoHeader.js"; +import { Part } from "../../components/Part.js"; +import { QR } from "../../components/QR.js"; +import { Link, SubTitle, WalletAction } from "../../components/styled/index.js"; +import { useTranslationContext } from "../../context/translation.js"; +import { Button } from "../../mui/Button.js"; +import { Grid } from "../../mui/Grid.js"; +import { TextField } from "../../mui/TextField.js"; +import { TransferDetails } from "../../wallet/Transaction.js"; +import { State } from "./index.js"; + +export function LoadingUriView({ error }: State.LoadingUriError): VNode { + const { i18n } = useTranslationContext(); + + return ( + Could not load} + error={error} + /> + ); +} + +export function ShowQrView({ talerUri, close }: State.ShowQr): VNode { + const { i18n } = useTranslationContext(); + return ( + + + + Digital invoice + +
+

Scan this QR code with the wallet

+ +
+
+ + Close + +
+
+ ); +} + +export function ReadyView({ + subject, + toBeReceived, + chosenAmount, + showQr, + copyToClipboard, + invalid, +}: State.Ready): VNode { + const { i18n } = useTranslationContext(); + return ( + + + + Digital cash transfer + +
+ + Details} + text={ + + } + /> +
+
+

How do you want to transfer?

+ + + + + + + + + +
+
+ ); +} diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts b/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts new file mode 100644 index 000000000..603200747 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts @@ -0,0 +1,67 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util"; +import { Loading } from "../../components/Loading.js"; +import { HookError } from "../../hooks/useAsyncAsHook.js"; +import { ButtonHandler } from "../../mui/handlers.js"; +import { compose, StateViewMap } from "../../utils/index.js"; +import * as wxApi from "../../wxApi.js"; +import { useComponentState } from "./state.js"; +import { LoadingUriView, ReadyView } from "./views.js"; + +export interface Props { + talerPayPushUri: string; +} + +export type State = + | State.Loading + | State.LoadingUriError + | State.Ready; + +export namespace State { + + export interface Loading { + status: "loading"; + error: undefined; + } + + export interface LoadingUriError { + status: "loading-uri"; + error: HookError; + } + + export interface BaseInfo { + error: undefined; + } + export interface Ready extends BaseInfo { + status: "ready"; + amount: AmountJson, + error: undefined; + accept: ButtonHandler; + operationError?: TalerErrorDetail; + } +} + +const viewMapping: StateViewMap = { + loading: Loading, + "loading-uri": LoadingUriView, + "ready": ReadyView, +}; + + +export const TransferPickupPage = compose("TransferPickupPage", (p: Props) => useComponentState(p, wxApi), viewMapping) + diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts new file mode 100644 index 000000000..a16389709 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts @@ -0,0 +1,72 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { Amounts, TalerErrorDetail } from "@gnu-taler/taler-util"; +import { TalerError } from "@gnu-taler/taler-wallet-core"; +import { useState } from "preact/hooks"; +import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; +import * as wxApi from "../../wxApi.js"; +import { Props, State } from "./index.js"; + +export function useComponentState( + { talerPayPushUri }: Props, + api: typeof wxApi, +): State { + const hook = useAsyncAsHook(async () => { + return await api.checkPeerPushPayment({ + talerUri: talerPayPushUri, + }) + }, []) + const [operationError, setOperationError] = useState(undefined) + + if (!hook) { + return { + status: "loading", + error: undefined, + } + } + if (hook.hasError) { + return { + status: "loading-uri", + error: hook, + }; + } + + const { amount, peerPushPaymentIncomingId } = hook.response + + async function accept(): Promise { + try { + const resp = await api.acceptPeerPushPayment({ + peerPushPaymentIncomingId + }) + } catch (e) { + if (e instanceof TalerError) { + setOperationError(e.errorDetail) + } + console.error(e) + throw Error("error trying to accept") + } + } + return { + status: "ready", + amount: Amounts.parseOrThrow(amount), + error: undefined, + accept: { + onClick: accept + }, + operationError + } +} diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/stories.tsx b/packages/taler-wallet-webextension/src/cta/TransferPickup/stories.tsx new file mode 100644 index 000000000..7a3ccb60d --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/stories.tsx @@ -0,0 +1,36 @@ +/* + This file is part of GNU Taler + (C) 2022 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { createExample } from "../../test-utils.js"; +import { ReadyView } from "./views.js"; + +export default { + title: "wallet/transfer pickup", +}; + +export const Ready = createExample(ReadyView, { + amount: { + currency: "ARS", + value: 1, + fraction: 0, + }, + accept: {}, +}); diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/test.ts b/packages/taler-wallet-webextension/src/cta/TransferPickup/test.ts new file mode 100644 index 000000000..631e76d01 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/test.ts @@ -0,0 +1,31 @@ +/* + This file is part of GNU Taler + (C) 2022 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { expect } from "chai"; + +describe("test description", () => { + + it("should assert", () => { + + expect([]).deep.equals([]) + }); +}) + diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/views.tsx b/packages/taler-wallet-webextension/src/cta/TransferPickup/views.tsx new file mode 100644 index 000000000..22ef8c776 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/views.tsx @@ -0,0 +1,74 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { h, VNode } from "preact"; +import { Amount } from "../../components/Amount.js"; +import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js"; +import { LoadingError } from "../../components/LoadingError.js"; +import { LogoHeader } from "../../components/LogoHeader.js"; +import { Part } from "../../components/Part.js"; +import { SubTitle, WalletAction } from "../../components/styled/index.js"; +import { useTranslationContext } from "../../context/translation.js"; +import { Button } from "../../mui/Button.js"; +import { State } from "./index.js"; + +export function LoadingUriView({ error }: State.LoadingUriError): VNode { + const { i18n } = useTranslationContext(); + + return ( + Could not load} + error={error} + /> + ); +} + +export function ReadyView({ + accept, + amount, + operationError, +}: State.Ready): VNode { + const { i18n } = useTranslationContext(); + return ( + + + + Digital cash transfer + + {operationError && ( + + Could not finish the pickup operation + + } + error={operationError} + /> + )} +
+ Amount} + text={} + /> +
+
+ +
+
+ ); +} diff --git a/packages/taler-wallet-webextension/src/cta/index.stories.ts b/packages/taler-wallet-webextension/src/cta/index.stories.ts index 92f4bbcb1..2f0ef33fb 100644 --- a/packages/taler-wallet-webextension/src/cta/index.stories.ts +++ b/packages/taler-wallet-webextension/src/cta/index.stories.ts @@ -25,5 +25,9 @@ import * as a4 from "./Refund/stories.jsx"; import * as a5 from "./Tip/stories.jsx"; import * as a6 from "./Withdraw/stories.jsx"; import * as a7 from "./TermsOfServiceSection.stories.js"; +import * as a8 from "./InvoiceCreate/stories.js"; +import * as a9 from "./InvoicePay/stories.js"; +import * as a10 from "./TransferCreate/stories.js"; +import * as a11 from "./TransferPickup/stories.js"; -export default [a1, a3, a4, a5, a6, a7]; +export default [a1, a3, a4, a5, a6, a7, a8, a9, a10, a11]; diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts b/packages/taler-wallet-webextension/src/platform/chrome.ts index 21fc180c3..f2c7e9d2d 100644 --- a/packages/taler-wallet-webextension/src/platform/chrome.ts +++ b/packages/taler-wallet-webextension/src/platform/chrome.ts @@ -201,11 +201,33 @@ function openWalletURIFromPopup(talerUri: string): void { `static/wallet.html#/cta/refund?talerRefundUri=${talerUri}`, ); break; - default: + case TalerUriType.TalerPayPull: + url = chrome.runtime.getURL( + `static/wallet.html#/cta/invoice/pay?talerPayPullUri=${talerUri}`, + ); + break; + case TalerUriType.TalerPayPush: + url = chrome.runtime.getURL( + `static/wallet.html#/cta/transfer/pickup?talerPayPushUri=${talerUri}`, + ); + break; + case TalerUriType.TalerNotifyReserve: logger.warn( - "Response with HTTP 402 has Taler header, but header value is not a taler:// URI.", + `Response with HTTP 402 the Taler header but it is deprecated ${talerUri}`, + ); + break; + case TalerUriType.Unknown: + logger.warn( + `Response with HTTP 402 the Taler header but could not classify ${talerUri}`, + ); + return; + default: { + const error: never = uriType; + logger.warn( + `Response with HTTP 402 the Taler header "${error}", but header value is not a taler:// URI.`, ); return; + } } chrome.tabs.create({ active: true, url }, () => { diff --git a/packages/taler-wallet-webextension/src/stories.tsx b/packages/taler-wallet-webextension/src/stories.tsx index a032222a0..09261d6f7 100644 --- a/packages/taler-wallet-webextension/src/stories.tsx +++ b/packages/taler-wallet-webextension/src/stories.tsx @@ -181,10 +181,11 @@ function getContentForExample(item: ExampleItem | undefined): () => VNode { item.component, item.name, ); - if (!example) + if (!example) { return function ExampleNotFoundMessage() { return
example not found
; }; + } return () => example.render(example.render.args); } @@ -314,7 +315,9 @@ function ErrorReport({ children: ComponentChild; selected: ExampleItem | undefined; }): VNode { - const [error] = useErrorBoundary(); + const [error, resetError] = useErrorBoundary(); + //if there is an error, reset when unloading this component + useEffect(() => (error ? resetError : undefined)); if (error) { return (
diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx b/packages/taler-wallet-webextension/src/wallet/Application.tsx index caed45d33..253d5fba7 100644 --- a/packages/taler-wallet-webextension/src/wallet/Application.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx @@ -60,8 +60,10 @@ import { DestinationSelectionSendCash, } from "./DestinationSelection.js"; import { ExchangeSelectionPage } from "./ExchangeSelection/index.js"; -import { InvoicePage } from "./Invoice/index.js"; -import { SendPage } from "./Send/index.js"; +import { TransferCreatePage } from "../cta/TransferCreate/index.js"; +import { InvoiceCreatePage } from "../cta/InvoiceCreate/index.js"; +import { TransferPickupPage } from "../cta/TransferPickup/index.js"; +import { InvoicePayPage } from "../cta/InvoicePay/index.js"; export function Application(): VNode { const [globalNotification, setGlobalNotification] = useState< @@ -153,7 +155,7 @@ export function Application(): VNode { redirectTo(Pages.balanceDeposit({ amount })) } goToWalletWalletSend={(amount: string) => - redirectTo(Pages.send({ amount })) + redirectTo(Pages.ctaTransferCreate({ amount })) } /> - redirectTo(Pages.invoice({ amount })) + redirectTo(Pages.ctaInvoiceCreate({ amount })) } /> - - redirectTo(Pages.balance)} /> + + + + + {/** * NOT FOUND diff --git a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx index 9577bb9d7..335d5ea9c 100644 --- a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx @@ -25,6 +25,10 @@ import { TransactionCommon, TransactionDeposit, TransactionPayment, + TransactionPeerPullCredit, + TransactionPeerPullDebit, + TransactionPeerPushCredit, + TransactionPeerPushDebit, TransactionRefresh, TransactionRefund, TransactionTip, @@ -118,6 +122,31 @@ const exampleData = { }, refundPending: undefined, } as TransactionRefund, + push_credit: { + ...commonTransaction(), + type: TransactionType.PeerPushCredit, + + exchangeBaseUrl: "https://exchange.taler.net", + } as TransactionPeerPushCredit, + push_debit: { + ...commonTransaction(), + type: TransactionType.PeerPushDebit, + talerUri: + "taler://pay-push/exchange.taler.ar/HS585JK0QCXHJ8Z8QWZA3EBAY5WY7XNC1RR2MHJXSH2Z4WP0YPJ0", + exchangeBaseUrl: "https://exchange.taler.net", + } as TransactionPeerPushDebit, + pull_credit: { + ...commonTransaction(), + type: TransactionType.PeerPullCredit, + talerUri: + "taler://pay-push/exchange.taler.ar/HS585JK0QCXHJ8Z8QWZA3EBAY5WY7XNC1RR2MHJXSH2Z4WP0YPJ0", + exchangeBaseUrl: "https://exchange.taler.net", + } as TransactionPeerPullCredit, + pull_debit: { + ...commonTransaction(), + type: TransactionType.PeerPullDebit, + exchangeBaseUrl: "https://exchange.taler.net", + } as TransactionPeerPullDebit, }; export const NoBalance = createExample(TestedComponent, { @@ -327,3 +356,21 @@ export const FiveOfficialCurrenciesWithHighValue = createExample( ], }, ); + +export const PeerToPeer = createExample(TestedComponent, { + transactions: [ + exampleData.pull_credit, + exampleData.pull_debit, + exampleData.push_credit, + exampleData.push_debit, + ], + balances: [ + { + available: "USD:10", + pendingIncoming: "USD:0", + pendingOutgoing: "USD:0", + hasPendingTransactions: false, + requiresUserInput: false, + }, + ], +}); diff --git a/packages/taler-wallet-webextension/src/wallet/Invoice/index.ts b/packages/taler-wallet-webextension/src/wallet/Invoice/index.ts deleted file mode 100644 index 20d902e65..000000000 --- a/packages/taler-wallet-webextension/src/wallet/Invoice/index.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see - */ - -import { Loading } from "../../components/Loading.js"; -import { HookError } from "../../hooks/useAsyncAsHook.js"; -import { compose, StateViewMap } from "../../utils/index.js"; -import { LoadingUriView, ReadyView } from "./views.js"; -import * as wxApi from "../../wxApi.js"; -import { useComponentState } from "./state.js"; -import { AmountJson } from "@gnu-taler/taler-util"; -import { TextFieldHandler } from "../../mui/handlers.js"; - -export interface Props { - p: string; -} - -export type State = - | State.Loading - | State.LoadingUriError - | State.Ready; - -export namespace State { - - export interface Loading { - status: "loading"; - error: undefined; - } - - export interface LoadingUriError { - status: "loading-uri"; - error: HookError; - } - - export interface BaseInfo { - error: undefined; - } - export interface Ready extends BaseInfo { - status: "ready"; - amount: AmountJson; - subject: TextFieldHandler; - error: undefined; - } -} - -const viewMapping: StateViewMap = { - loading: Loading, - "loading-uri": LoadingUriView, - "ready": ReadyView, -}; - - -export const InvoicePage = compose("InvoicePage", (p: Props) => useComponentState(p, wxApi), viewMapping) - diff --git a/packages/taler-wallet-webextension/src/wallet/Invoice/state.ts b/packages/taler-wallet-webextension/src/wallet/Invoice/state.ts deleted file mode 100644 index 48cfd359b..000000000 --- a/packages/taler-wallet-webextension/src/wallet/Invoice/state.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see - */ - -import { Amounts } from "@gnu-taler/taler-util"; -import { useState } from "preact/hooks"; -import * as wxApi from "../../wxApi.js"; -import { Props, State } from "./index.js"; - -export function useComponentState( - { p }: Props, - api: typeof wxApi, -): State { - const [subject, setSubject] = useState(""); - const amount = Amounts.parseOrThrow("ARS:0") - return { - status: "ready", - subject: { - value: subject, - onInput: async (e) => setSubject(e) - }, - amount, - error: undefined, - } -} diff --git a/packages/taler-wallet-webextension/src/wallet/Invoice/stories.tsx b/packages/taler-wallet-webextension/src/wallet/Invoice/stories.tsx deleted file mode 100644 index 75f78be1d..000000000 --- a/packages/taler-wallet-webextension/src/wallet/Invoice/stories.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 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 - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -import { createExample } from "../../test-utils.js"; -import { ReadyView } from "./views.js"; - -export default { - title: "wallet/invoice", -}; - -export const Ready = createExample(ReadyView, {}); diff --git a/packages/taler-wallet-webextension/src/wallet/Invoice/test.ts b/packages/taler-wallet-webextension/src/wallet/Invoice/test.ts deleted file mode 100644 index 631e76d01..000000000 --- a/packages/taler-wallet-webextension/src/wallet/Invoice/test.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 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 - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -import { expect } from "chai"; - -describe("test description", () => { - - it("should assert", () => { - - expect([]).deep.equals([]) - }); -}) - diff --git a/packages/taler-wallet-webextension/src/wallet/Invoice/views.tsx b/packages/taler-wallet-webextension/src/wallet/Invoice/views.tsx deleted file mode 100644 index 94e8f8625..000000000 --- a/packages/taler-wallet-webextension/src/wallet/Invoice/views.tsx +++ /dev/null @@ -1,56 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see - */ - -import { Amounts } from "@gnu-taler/taler-util"; -import { styled } from "@linaria/react"; -import { h, VNode } from "preact"; -import { LoadingError } from "../../components/LoadingError.js"; -import { useTranslationContext } from "../../context/translation.js"; -import { Button } from "../../mui/Button.js"; -import { TextField } from "../../mui/TextField.js"; -import { State } from "./index.js"; - -export function LoadingUriView({ error }: State.LoadingUriError): VNode { - const { i18n } = useTranslationContext(); - - return ( - Could not load} - error={error} - /> - ); -} - -const Container = styled.div``; - -export function ReadyView({ amount, subject }: State.Ready): VNode { - const { i18n } = useTranslationContext(); - - return ( - -

Creating an invoice of {Amounts.stringify(amount)}

- -

to:

- -
- ); -} diff --git a/packages/taler-wallet-webextension/src/wallet/Send/index.ts b/packages/taler-wallet-webextension/src/wallet/Send/index.ts deleted file mode 100644 index fb69c6280..000000000 --- a/packages/taler-wallet-webextension/src/wallet/Send/index.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see - */ - -import { Loading } from "../../components/Loading.js"; -import { HookError } from "../../hooks/useAsyncAsHook.js"; -import { compose, StateViewMap } from "../../utils/index.js"; -import { LoadingUriView, ReadyView } from "./views.js"; -import * as wxApi from "../../wxApi.js"; -import { useComponentState } from "./state.js"; -import { AmountJson } from "@gnu-taler/taler-util"; -import { SelectFieldHandler, TextFieldHandler } from "../../mui/handlers.js"; - -export interface Props { - p: string; -} - -export type State = - | State.Loading - | State.LoadingUriError - | State.Ready; - -export namespace State { - - export interface Loading { - status: "loading"; - error: undefined; - } - - export interface LoadingUriError { - status: "loading-uri"; - error: HookError; - } - - export interface BaseInfo { - error: undefined; - } - export interface Ready extends BaseInfo { - status: "ready"; - amount: AmountJson; - exchange: SelectFieldHandler, - subject: TextFieldHandler, - error: undefined; - } -} - -const viewMapping: StateViewMap = { - loading: Loading, - "loading-uri": LoadingUriView, - "ready": ReadyView, -}; - - -export const SendPage = compose("SendPage", (p: Props) => useComponentState(p, wxApi), viewMapping) - diff --git a/packages/taler-wallet-webextension/src/wallet/Send/state.ts b/packages/taler-wallet-webextension/src/wallet/Send/state.ts deleted file mode 100644 index 1359c1804..000000000 --- a/packages/taler-wallet-webextension/src/wallet/Send/state.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see - */ - -import { Amounts } from "@gnu-taler/taler-util"; -import { useState } from "preact/hooks"; -import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; -import * as wxApi from "../../wxApi.js"; -import { Props, State } from "./index.js"; - -export function useComponentState( - { p }: Props, - api: typeof wxApi, -): State { - const [subject, setSubject] = useState(""); - const amount = Amounts.parseOrThrow("ARS:0") - - const hook = useAsyncAsHook(api.listExchanges); - const [exchangeIdx, setExchangeIdx] = useState("0") - - if (!hook) { - return { - status: "loading", - error: undefined, - } - } - if (hook.hasError) { - return { - status: "loading-uri", - error: hook, - }; - } - - const exchanges = hook.response.exchanges; - const exchangeMap = exchanges.reduce((prev, cur, idx) => ({ ...prev, [cur.exchangeBaseUrl]: String(idx) }), {} as Record) - const selected = exchanges[Number(exchangeIdx)]; - - return { - status: "ready", - exchange: { - list: exchangeMap, - value: exchangeIdx, - onChange: async (v) => { - setExchangeIdx(v) - } - }, - subject: { - value: subject, - onInput: async (e) => setSubject(e) - }, - amount, - error: undefined, - } -} diff --git a/packages/taler-wallet-webextension/src/wallet/Send/stories.tsx b/packages/taler-wallet-webextension/src/wallet/Send/stories.tsx deleted file mode 100644 index 75f78be1d..000000000 --- a/packages/taler-wallet-webextension/src/wallet/Send/stories.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 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 - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -import { createExample } from "../../test-utils.js"; -import { ReadyView } from "./views.js"; - -export default { - title: "wallet/invoice", -}; - -export const Ready = createExample(ReadyView, {}); diff --git a/packages/taler-wallet-webextension/src/wallet/Send/test.ts b/packages/taler-wallet-webextension/src/wallet/Send/test.ts deleted file mode 100644 index 631e76d01..000000000 --- a/packages/taler-wallet-webextension/src/wallet/Send/test.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 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 - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -import { expect } from "chai"; - -describe("test description", () => { - - it("should assert", () => { - - expect([]).deep.equals([]) - }); -}) - diff --git a/packages/taler-wallet-webextension/src/wallet/Send/views.tsx b/packages/taler-wallet-webextension/src/wallet/Send/views.tsx deleted file mode 100644 index 63310f443..000000000 --- a/packages/taler-wallet-webextension/src/wallet/Send/views.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see - */ - -import { Amounts } from "@gnu-taler/taler-util"; -import { styled } from "@linaria/react"; -import { h, VNode } from "preact"; -import { useState } from "preact/hooks"; -import { LoadingError } from "../../components/LoadingError.js"; -import { SelectList } from "../../components/SelectList.js"; -import { Input } from "../../components/styled/index.js"; -import { useTranslationContext } from "../../context/translation.js"; -import { Button } from "../../mui/Button.js"; -import { TextField } from "../../mui/TextField.js"; -import { State } from "./index.js"; - -export function LoadingUriView({ error }: State.LoadingUriError): VNode { - const { i18n } = useTranslationContext(); - - return ( - Could not load} - error={error} - /> - ); -} - -const Container = styled.div``; - -export function ReadyView({ amount, exchange, subject }: State.Ready): VNode { - const { i18n } = useTranslationContext(); - return ( - -

Sending {Amounts.stringify(amount)}

- -

to:

- -
- ); -} diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx index ba61e35f3..6c591611a 100644 --- a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx @@ -25,6 +25,10 @@ import { TransactionCommon, TransactionDeposit, TransactionPayment, + TransactionPeerPullCredit, + TransactionPeerPullDebit, + TransactionPeerPushCredit, + TransactionPeerPushDebit, TransactionRefresh, TransactionRefund, TransactionTip, @@ -139,6 +143,30 @@ const exampleData = { }, refundPending: undefined, } as TransactionRefund, + push_credit: { + ...commonTransaction, + type: TransactionType.PeerPushCredit, + exchangeBaseUrl: "https://exchange.taler.net", + } as TransactionPeerPushCredit, + push_debit: { + ...commonTransaction, + type: TransactionType.PeerPushDebit, + talerUri: + "taler://pay-push/exchange.taler.ar/HS585JK0QCXHJ8Z8QWZA3EBAY5WY7XNC1RR2MHJXSH2Z4WP0YPJ0", + exchangeBaseUrl: "https://exchange.taler.net", + } as TransactionPeerPushDebit, + pull_credit: { + ...commonTransaction, + type: TransactionType.PeerPullCredit, + talerUri: + "taler://pay-push/exchange.taler.ar/HS585JK0QCXHJ8Z8QWZA3EBAY5WY7XNC1RR2MHJXSH2Z4WP0YPJ0", + exchangeBaseUrl: "https://exchange.taler.net", + } as TransactionPeerPullCredit, + pull_debit: { + ...commonTransaction, + type: TransactionType.PeerPullDebit, + exchangeBaseUrl: "https://exchange.taler.net", + } as TransactionPeerPullDebit, }; const transactionError = { @@ -498,3 +526,19 @@ export const RefundError = createExample(TestedComponent, { export const RefundPending = createExample(TestedComponent, { transaction: { ...exampleData.refund, pending: true }, }); + +export const InvoiceCredit = createExample(TestedComponent, { + transaction: { ...exampleData.pull_credit }, +}); + +export const InvoiceDebit = createExample(TestedComponent, { + transaction: { ...exampleData.pull_debit }, +}); + +export const TransferCredit = createExample(TestedComponent, { + transaction: { ...exampleData.push_credit }, +}); + +export const TransferDebit = createExample(TestedComponent, { + transaction: { ...exampleData.push_debit }, +}); diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx index ff3b70b65..c8c4e3ae1 100644 --- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx @@ -45,6 +45,7 @@ import { ErrorTalerOperation } from "../components/ErrorTalerOperation.js"; import { Loading } from "../components/Loading.js"; import { LoadingError } from "../components/LoadingError.js"; import { Kind, Part, PartCollapsible, PartPayto } from "../components/Part.js"; +import { QR } from "../components/QR.js"; import { ShowFullContractTermPopup } from "../components/ShowFullContractTermPopup.js"; import { CenteredDialog, @@ -557,6 +558,172 @@ export function TransactionView({ ); } + function ShowQrWithCopy({ text }: { text: string }): VNode { + const [showing, setShowing] = useState(false); + async function copy(): Promise { + navigator.clipboard.writeText(text); + } + async function toggle(): Promise { + setShowing((s) => !s); + } + if (showing) { + return ( +
+ + + +
+ ); + } + return ( +
+
{text.substring(0, 64)}...
+ + +
+ ); + } + + if (transaction.type === TransactionType.PeerPullCredit) { + const total = Amounts.parseOrThrow(transaction.amountEffective); + return ( + +
+ Invoice +
+ + Exchange} + text={transaction.exchangeBaseUrl} + kind="neutral" + /> + URI} + text={} + kind="neutral" + /> + Details} + text={ + + } + /> +
+ ); + } + + if (transaction.type === TransactionType.PeerPullDebit) { + const total = Amounts.parseOrThrow(transaction.amountEffective); + return ( + +
+ Invoice +
+ + Exchange} + text={transaction.exchangeBaseUrl} + kind="neutral" + /> + Details} + text={ + + } + /> +
+ ); + } + if (transaction.type === TransactionType.PeerPushDebit) { + const total = Amounts.parseOrThrow(transaction.amountEffective); + return ( + +
+ Transfer +
+ + Exchange} + text={transaction.exchangeBaseUrl} + kind="neutral" + /> + URI} + text={} + kind="neutral" + /> + Details} + text={ + + } + /> +
+ ); + } + + if (transaction.type === TransactionType.PeerPushCredit) { + const total = Amounts.parseOrThrow(transaction.amountEffective); + return ( + +
+ Transfer +
+ + Exchange} + text={transaction.exchangeBaseUrl} + kind="neutral" + /> + Details} + text={ + + } + /> +
+ ); + } return
; } @@ -736,6 +903,88 @@ export interface AmountWithFee { raw: AmountJson; } +export function InvoiceDetails({ amount }: { amount: AmountWithFee }): VNode { + const { i18n } = useTranslationContext(); + + const fee = Amounts.sub(amount.raw, amount.effective).amount; + + const maxFrac = [amount.raw, amount.effective, fee] + .map((a) => Amounts.maxFractionalDigits(a)) + .reduce((c, p) => Math.max(c, p), 0); + + return ( + + + Invoice + + + + + + {Amounts.isNonZero(fee) && ( + + Transaction fees + + + + + )} + + +
+ + + + Total + + + + +
+ ); +} + +export function TransferDetails({ amount }: { amount: AmountWithFee }): VNode { + const { i18n } = useTranslationContext(); + + const fee = Amounts.sub(amount.raw, amount.effective).amount; + + const maxFrac = [amount.raw, amount.effective, fee] + .map((a) => Amounts.maxFractionalDigits(a)) + .reduce((c, p) => Math.max(c, p), 0); + + return ( + + + Transfer + + + + + + {Amounts.isNonZero(fee) && ( + + Transaction fees + + + + + )} + + +
+ + + + Total + + + + +
+ ); +} + export function WithdrawDetails({ amount }: { amount: AmountWithFee }): VNode { const { i18n } = useTranslationContext(); diff --git a/packages/taler-wallet-webextension/src/wxApi.ts b/packages/taler-wallet-webextension/src/wxApi.ts index 9700c475e..a796755e5 100644 --- a/packages/taler-wallet-webextension/src/wxApi.ts +++ b/packages/taler-wallet-webextension/src/wxApi.ts @@ -24,12 +24,18 @@ import { AcceptExchangeTosRequest, AcceptManualWithdrawalResult, + AcceptPeerPullPaymentRequest, + AcceptPeerPushPaymentRequest, AcceptTipRequest, AcceptWithdrawalResponse, AddExchangeRequest, AmountString, ApplyRefundResponse, BalancesResponse, + CheckPeerPullPaymentRequest, + CheckPeerPullPaymentResponse, + CheckPeerPushPaymentRequest, + CheckPeerPushPaymentResponse, CoinDumpJson, ConfirmPayResult, CoreApiResponse, @@ -41,6 +47,10 @@ import { GetExchangeWithdrawalInfo, GetFeeForDepositRequest, GetWithdrawalDetailsForUriRequest, + InitiatePeerPullPaymentRequest, + InitiatePeerPullPaymentResponse, + InitiatePeerPushPaymentRequest, + InitiatePeerPushPaymentResponse, KnownBankAccounts, Logger, NotificationType, @@ -473,3 +483,24 @@ export function onUpdateNotification( }; return platform.listenToWalletBackground(onNewMessage); } + +export function initiatePeerPushPayment(req: InitiatePeerPushPaymentRequest): Promise { + return callBackend("initiatePeerPushPayment", req); +} +export function checkPeerPushPayment(req: CheckPeerPushPaymentRequest): Promise { + return callBackend("checkPeerPushPayment", req); +} +export function acceptPeerPushPayment(req: AcceptPeerPushPaymentRequest): Promise { + return callBackend("acceptPeerPushPayment", req); +} +export function initiatePeerPullPayment(req: InitiatePeerPullPaymentRequest): Promise { + return callBackend("initiatePeerPullPayment", req); +} +export function checkPeerPullPayment(req: CheckPeerPullPaymentRequest): Promise { + return callBackend("checkPeerPullPayment", req); +} +export function acceptPeerPullPayment(req: AcceptPeerPullPaymentRequest): Promise { + return callBackend("acceptPeerPullPayment", req); +} + + diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts index c6d9aa70e..ae0103555 100644 --- a/packages/taler-wallet-webextension/src/wxBackend.ts +++ b/packages/taler-wallet-webextension/src/wxBackend.ts @@ -276,15 +276,35 @@ function parseTalerUriAndRedirect(tabId: number, talerUri: string): void { tabId, `/cta/refund?talerRefundUri=${talerUri}`, ); + case TalerUriType.TalerPayPull: + return platform.redirectTabToWalletPage( + tabId, + `/cta/invoice/pay?talerPayPullUri=${talerUri}`, + ); + case TalerUriType.TalerPayPush: + return platform.redirectTabToWalletPage( + tabId, + `/cta/transfer/pickup?talerPayPushUri=${talerUri}`, + ); case TalerUriType.TalerNotifyReserve: // FIXME: Is this still useful? // handleNotifyReserve(w); - break; - default: logger.warn( - "Response with HTTP 402 has Taler header, but header value is not a taler:// URI.", + `Response with HTTP 402 the Taler header but it is deprecated ${talerUri}`, ); break; + case TalerUriType.Unknown: + logger.warn( + `Response with HTTP 402 the Taler header but could not classify ${talerUri}`, + ); + return; + default: { + const error: never = uriType; + logger.warn( + `Response with HTTP 402 the Taler header "${error}", but header value is not a taler:// URI.`, + ); + return; + } } } -- cgit v1.2.3