aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/wallet
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2022-08-31 00:20:35 -0300
committerSebastian <sebasjm@gmail.com>2022-08-31 00:20:35 -0300
commitd84424202dca22fff22cb1d304286f627642187b (patch)
tree39b69521a1e5a84c71b7752d355423705941bdd7 /packages/taler-wallet-webextension/src/wallet
parent7dc66c2441c4b77cfed0c4add592d4b7d5912ec3 (diff)
downloadwallet-core-d84424202dca22fff22cb1d304286f627642187b.tar.xz
p2p tx rendering
Diffstat (limited to 'packages/taler-wallet-webextension/src/wallet')
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Application.tsx26
-rw-r--r--packages/taler-wallet-webextension/src/wallet/History.stories.tsx47
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Invoice/index.ts66
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Invoice/state.ts37
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Invoice/stories.tsx29
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Invoice/test.ts31
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Invoice/views.tsx56
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Send/index.ts67
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Send/state.ts66
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Send/stories.tsx29
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Send/test.ts31
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Send/views.tsx58
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx44
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Transaction.tsx249
14 files changed, 360 insertions, 476 deletions
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 }))
}
/>
<Route
@@ -163,11 +165,9 @@ export function Application(): VNode {
redirectTo(Pages.ctaWithdrawManual({ amount }))
}
goToWalletWalletInvoice={(amount?: string) =>
- redirectTo(Pages.invoice({ amount }))
+ redirectTo(Pages.ctaInvoiceCreate({ amount }))
}
/>
- <Route path={Pages.invoice.pattern} component={InvoicePage} />
- <Route path={Pages.send.pattern} component={SendPage} />
<Route
path={Pages.balanceTransaction.pattern}
@@ -275,6 +275,20 @@ export function Application(): VNode {
component={DepositPageCTA}
cancel={() => redirectTo(Pages.balance)}
/>
+ <Route
+ path={Pages.ctaInvoiceCreate.pattern}
+ component={InvoiceCreatePage}
+ />
+ <Route
+ path={Pages.ctaTransferCreate.pattern}
+ component={TransferCreatePage}
+ />
+
+ <Route path={Pages.ctaInvoicePay} component={InvoicePayPage} />
+ <Route
+ path={Pages.ctaTransferPickup}
+ component={TransferPickupPage}
+ />
{/**
* 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 <http://www.gnu.org/licenses/>
- */
-
-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<State> = {
- 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 <http://www.gnu.org/licenses/>
- */
-
-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 <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @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 <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @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 <http://www.gnu.org/licenses/>
- */
-
-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 (
- <LoadingError
- title={<i18n.Translate>Could not load</i18n.Translate>}
- error={error}
- />
- );
-}
-
-const Container = styled.div``;
-
-export function ReadyView({ amount, subject }: State.Ready): VNode {
- const { i18n } = useTranslationContext();
-
- return (
- <Container>
- <p>Creating an invoice of {Amounts.stringify(amount)}</p>
- <TextField
- label="Subject"
- variant="filled"
- required
- value={subject.value}
- onChange={subject.onInput}
- />
- <p>to:</p>
- <Button>Scan QR code</Button>
- </Container>
- );
-}
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 <http://www.gnu.org/licenses/>
- */
-
-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<State> = {
- 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 <http://www.gnu.org/licenses/>
- */
-
-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<string, string>)
- 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 <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @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 <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @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 <http://www.gnu.org/licenses/>
- */
-
-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 (
- <LoadingError
- title={<i18n.Translate>Could not load</i18n.Translate>}
- error={error}
- />
- );
-}
-
-const Container = styled.div``;
-
-export function ReadyView({ amount, exchange, subject }: State.Ready): VNode {
- const { i18n } = useTranslationContext();
- return (
- <Container>
- <p>Sending {Amounts.stringify(amount)}</p>
- <TextField
- label="Subject"
- variant="filled"
- required
- value={subject.value}
- onChange={subject.onInput}
- />
- <p>to:</p>
- <Button>Scan QR code</Button>
- </Container>
- );
-}
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<void> {
+ navigator.clipboard.writeText(text);
+ }
+ async function toggle(): Promise<void> {
+ setShowing((s) => !s);
+ }
+ if (showing) {
+ return (
+ <div>
+ <QR text={text} />
+ <Button onClick={copy}>copy</Button>
+ <Button onClick={toggle}>hide qr</Button>
+ </div>
+ );
+ }
+ return (
+ <div>
+ <div>{text.substring(0, 64)}...</div>
+ <Button onClick={copy}>copy</Button>
+ <Button onClick={toggle}>show qr</Button>
+ </div>
+ );
+ }
+
+ if (transaction.type === TransactionType.PeerPullCredit) {
+ const total = Amounts.parseOrThrow(transaction.amountEffective);
+ return (
+ <TransactionTemplate>
+ <Header
+ timestamp={transaction.timestamp}
+ type={i18n.str`Credit`}
+ total={total}
+ kind="positive"
+ >
+ Invoice
+ </Header>
+
+ <Part
+ title={<i18n.Translate>Exchange</i18n.Translate>}
+ text={transaction.exchangeBaseUrl}
+ kind="neutral"
+ />
+ <Part
+ title={<i18n.Translate>URI</i18n.Translate>}
+ text={<ShowQrWithCopy text={transaction.talerUri} />}
+ kind="neutral"
+ />
+ <Part
+ title={<i18n.Translate>Details</i18n.Translate>}
+ text={
+ <InvoiceDetails
+ amount={{
+ effective: Amounts.parseOrThrow(transaction.amountEffective),
+ raw: Amounts.parseOrThrow(transaction.amountRaw),
+ }}
+ />
+ }
+ />
+ </TransactionTemplate>
+ );
+ }
+
+ if (transaction.type === TransactionType.PeerPullDebit) {
+ const total = Amounts.parseOrThrow(transaction.amountEffective);
+ return (
+ <TransactionTemplate>
+ <Header
+ timestamp={transaction.timestamp}
+ type={i18n.str`Debit`}
+ total={total}
+ kind="negative"
+ >
+ Invoice
+ </Header>
+
+ <Part
+ title={<i18n.Translate>Exchange</i18n.Translate>}
+ text={transaction.exchangeBaseUrl}
+ kind="neutral"
+ />
+ <Part
+ title={<i18n.Translate>Details</i18n.Translate>}
+ text={
+ <InvoiceDetails
+ amount={{
+ effective: Amounts.parseOrThrow(transaction.amountEffective),
+ raw: Amounts.parseOrThrow(transaction.amountRaw),
+ }}
+ />
+ }
+ />
+ </TransactionTemplate>
+ );
+ }
+ if (transaction.type === TransactionType.PeerPushDebit) {
+ const total = Amounts.parseOrThrow(transaction.amountEffective);
+ return (
+ <TransactionTemplate>
+ <Header
+ timestamp={transaction.timestamp}
+ type={i18n.str`Debit`}
+ total={total}
+ kind="negative"
+ >
+ Transfer
+ </Header>
+
+ <Part
+ title={<i18n.Translate>Exchange</i18n.Translate>}
+ text={transaction.exchangeBaseUrl}
+ kind="neutral"
+ />
+ <Part
+ title={<i18n.Translate>URI</i18n.Translate>}
+ text={<QR text={transaction.talerUri} />}
+ kind="neutral"
+ />
+ <Part
+ title={<i18n.Translate>Details</i18n.Translate>}
+ text={
+ <TransferDetails
+ amount={{
+ effective: Amounts.parseOrThrow(transaction.amountEffective),
+ raw: Amounts.parseOrThrow(transaction.amountRaw),
+ }}
+ />
+ }
+ />
+ </TransactionTemplate>
+ );
+ }
+
+ if (transaction.type === TransactionType.PeerPushCredit) {
+ const total = Amounts.parseOrThrow(transaction.amountEffective);
+ return (
+ <TransactionTemplate>
+ <Header
+ timestamp={transaction.timestamp}
+ type={i18n.str`Credit`}
+ total={total}
+ kind="positive"
+ >
+ Transfer
+ </Header>
+
+ <Part
+ title={<i18n.Translate>Exchange</i18n.Translate>}
+ text={transaction.exchangeBaseUrl}
+ kind="neutral"
+ />
+ <Part
+ title={<i18n.Translate>Details</i18n.Translate>}
+ text={
+ <TransferDetails
+ amount={{
+ effective: Amounts.parseOrThrow(transaction.amountEffective),
+ raw: Amounts.parseOrThrow(transaction.amountRaw),
+ }}
+ />
+ }
+ />
+ </TransactionTemplate>
+ );
+ }
return <div />;
}
@@ -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 (
+ <PurchaseDetailsTable>
+ <tr>
+ <td>Invoice</td>
+ <td>
+ <Amount value={amount.raw} maxFracSize={maxFrac} />
+ </td>
+ </tr>
+
+ {Amounts.isNonZero(fee) && (
+ <tr>
+ <td>Transaction fees</td>
+ <td>
+ <Amount value={fee} negative maxFracSize={maxFrac} />
+ </td>
+ </tr>
+ )}
+ <tr>
+ <td colSpan={2}>
+ <hr />
+ </td>
+ </tr>
+ <tr>
+ <td>Total</td>
+ <td>
+ <Amount value={amount.effective} maxFracSize={maxFrac} />
+ </td>
+ </tr>
+ </PurchaseDetailsTable>
+ );
+}
+
+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 (
+ <PurchaseDetailsTable>
+ <tr>
+ <td>Transfer</td>
+ <td>
+ <Amount value={amount.raw} maxFracSize={maxFrac} />
+ </td>
+ </tr>
+
+ {Amounts.isNonZero(fee) && (
+ <tr>
+ <td>Transaction fees</td>
+ <td>
+ <Amount value={fee} negative maxFracSize={maxFrac} />
+ </td>
+ </tr>
+ )}
+ <tr>
+ <td colSpan={2}>
+ <hr />
+ </td>
+ </tr>
+ <tr>
+ <td>Total</td>
+ <td>
+ <Amount value={amount.effective} maxFracSize={maxFrac} />
+ </td>
+ </tr>
+ </PurchaseDetailsTable>
+ );
+}
+
export function WithdrawDetails({ amount }: { amount: AmountWithFee }): VNode {
const { i18n } = useTranslationContext();