summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/cta/Deposit
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-webextension/src/cta/Deposit')
-rw-r--r--packages/taler-wallet-webextension/src/cta/Deposit/index.ts69
-rw-r--r--packages/taler-wallet-webextension/src/cta/Deposit/state.ts79
-rw-r--r--packages/taler-wallet-webextension/src/cta/Deposit/stories.tsx37
-rw-r--r--packages/taler-wallet-webextension/src/cta/Deposit/test.ts118
-rw-r--r--packages/taler-wallet-webextension/src/cta/Deposit/views.tsx72
5 files changed, 375 insertions, 0 deletions
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/index.ts b/packages/taler-wallet-webextension/src/cta/Deposit/index.ts
new file mode 100644
index 000000000..6b228188b
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/index.ts
@@ -0,0 +1,69 @@
+/*
+ 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 { AmountJson, AmountString } from "@gnu-taler/taler-util";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
+import { Loading } from "../../components/Loading.js";
+import { ErrorAlert } from "../../context/alert.js";
+import { ButtonHandler } from "../../mui/handlers.js";
+import { compose, StateViewMap } from "../../utils/index.js";
+import { useComponentState } from "./state.js";
+import { ReadyView } from "./views.js";
+
+export interface Props {
+ talerDepositUri: string | undefined;
+ amountStr: AmountString | undefined;
+ cancel: () => Promise<void>;
+ onSuccess: (tx: string) => Promise<void>;
+}
+
+export type State = State.Loading | State.LoadingUriError | State.Ready;
+
+export namespace State {
+ export interface Loading {
+ status: "loading";
+ error: undefined;
+ }
+ export interface LoadingUriError {
+ status: "error";
+ error: ErrorAlert;
+ }
+ export interface Ready {
+ status: "ready";
+ error: undefined;
+ fee: AmountJson;
+ cost: AmountJson;
+ effective: AmountJson;
+ confirm: ButtonHandler;
+ cancel: () => Promise<void>;
+ }
+ export interface Completed {
+ status: "completed";
+ error: undefined;
+ }
+}
+
+const viewMapping: StateViewMap<State> = {
+ loading: Loading,
+ error: ErrorAlertView,
+ ready: ReadyView,
+};
+
+export const DepositPage = compose(
+ "Deposit",
+ (p: Props) => useComponentState(p),
+ viewMapping,
+);
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/state.ts b/packages/taler-wallet-webextension/src/cta/Deposit/state.ts
new file mode 100644
index 000000000..efcef8c28
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/state.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 <http://www.gnu.org/licenses/>
+ */
+
+import { Amounts } from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import { alertFromError, useAlertContext } from "../../context/alert.js";
+import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
+import { Props, State } from "./index.js";
+
+export function useComponentState({
+ talerDepositUri,
+ amountStr,
+ cancel,
+ onSuccess,
+}: Props): State {
+ const api = useBackendContext();
+ const { pushAlertOnError } = useAlertContext();
+ const info = useAsyncAsHook(async () => {
+ if (!talerDepositUri) throw Error("ERROR_NO-URI-FOR-DEPOSIT");
+ if (!amountStr) throw Error("ERROR_NO-AMOUNT-FOR-DEPOSIT");
+ const amount = Amounts.parse(amountStr);
+ if (!amount) throw Error("ERROR_INVALID-AMOUNT-FOR-DEPOSIT");
+ const deposit = await api.wallet.call(WalletApiOperation.PrepareDeposit, {
+ amount: Amounts.stringify(amount),
+ depositPaytoUri: talerDepositUri,
+ });
+ return { deposit, uri: talerDepositUri, amount };
+ });
+ const { i18n } = useTranslationContext();
+
+ if (!info) return { status: "loading", error: undefined };
+ if (info.hasError) {
+ return {
+ status: "error",
+ error: alertFromError(
+ i18n,
+ i18n.str`Could not load the status of deposit`,
+ info,
+ ),
+ };
+ }
+
+ const { deposit, uri, amount } = info.response;
+ async function doDeposit(): Promise<void> {
+ const resp = await api.wallet.call(WalletApiOperation.CreateDepositGroup, {
+ amount: Amounts.stringify(amount),
+ depositPaytoUri: uri,
+ });
+ onSuccess(resp.transactionId);
+ }
+
+ return {
+ status: "ready",
+ error: undefined,
+ confirm: {
+ onClick: pushAlertOnError(doDeposit),
+ },
+ fee: Amounts.sub(deposit.totalDepositCost, deposit.effectiveDepositAmount)
+ .amount,
+ cost: Amounts.parseOrThrow(deposit.totalDepositCost),
+ effective: Amounts.parseOrThrow(deposit.effectiveDepositAmount),
+ cancel,
+ };
+}
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/stories.tsx b/packages/taler-wallet-webextension/src/cta/Deposit/stories.tsx
new file mode 100644
index 000000000..cd65ce8e1
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/stories.tsx
@@ -0,0 +1,37 @@
+/*
+ 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 { Amounts } from "@gnu-taler/taler-util";
+import * as tests from "@gnu-taler/web-util/testing";
+import { ReadyView } from "./views.js";
+
+export default {
+ title: "deposit",
+};
+
+export const Ready = tests.createExample(ReadyView, {
+ status: "ready",
+ confirm: {},
+ cost: Amounts.parseOrThrow("EUR:1.2"),
+ effective: Amounts.parseOrThrow("EUR:1"),
+ fee: Amounts.parseOrThrow("EUR:0.2"),
+ error: undefined,
+});
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/test.ts b/packages/taler-wallet-webextension/src/cta/Deposit/test.ts
new file mode 100644
index 000000000..100929918
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/test.ts
@@ -0,0 +1,118 @@
+/*
+ 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 { AmountString, Amounts } from "@gnu-taler/taler-util";
+import { expect } from "chai";
+import { createWalletApiMock } from "../../test-utils.js";
+import { useComponentState } from "./state.js";
+import * as tests from "@gnu-taler/web-util/testing";
+import { Props } from "./index.js";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+
+describe("Deposit CTA states", () => {
+ it("should tell the user that the URI is missing", async () => {
+ const { handler, TestingContext } = createWalletApiMock();
+
+ const props: Props = {
+ talerDepositUri: undefined,
+ amountStr: undefined,
+ cancel: async () => {
+ null;
+ },
+ onSuccess: async () => {
+ null;
+ },
+ };
+
+ const hookBehavior = await tests.hookBehaveLikeThis(
+ useComponentState,
+ props,
+ [
+ ({ status }) => {
+ expect(status).equals("loading");
+ },
+ ({ status, error }) => {
+ expect(status).equals("error");
+
+ if (!error) expect.fail();
+ // if (!error.hasError) expect.fail();
+ // if (error.operational) expect.fail();
+ expect(error.description).eq("ERROR_NO-URI-FOR-DEPOSIT");
+ },
+ ],
+ TestingContext,
+ );
+
+ expect(hookBehavior).deep.equal({ result: "ok" });
+ expect(handler.getCallingQueueState()).eq("empty");
+ });
+
+ it("should be ready after loading", async () => {
+ const { handler, TestingContext } = createWalletApiMock();
+
+ handler.addWalletCallResponse(
+ WalletApiOperation.PrepareDeposit,
+ undefined,
+ {
+ effectiveDepositAmount: "EUR:1" as AmountString,
+ totalDepositCost: "EUR:1.2" as AmountString,
+ fees: {
+ coin: "EUR:0" as AmountString,
+ refresh: "EUR:0.2" as AmountString,
+ wire: "EUR:0" as AmountString,
+ },
+ },
+ );
+
+ const props = {
+ talerDepositUri: "payto://refund/asdasdas",
+ amountStr: "EUR:1" as AmountString,
+ cancel: async () => {
+ null;
+ },
+ onSuccess: async () => {
+ null;
+ },
+ };
+
+ const hookBehavior = await tests.hookBehaveLikeThis(
+ useComponentState,
+ props,
+ [
+ ({ status }) => {
+ expect(status).equals("loading");
+ },
+ (state) => {
+ if (state.status !== "ready") expect.fail();
+ if (state.error) expect.fail();
+ expect(state.confirm.onClick).not.undefined;
+ expect(state.cost).deep.eq(Amounts.parseOrThrow("EUR:1.2"));
+ expect(state.fee).deep.eq(Amounts.parseOrThrow("EUR:0.2"));
+ expect(state.effective).deep.eq(Amounts.parseOrThrow("EUR:1"));
+ },
+ ],
+ TestingContext,
+ );
+
+ expect(hookBehavior).deep.equal({ result: "ok" });
+ expect(handler.getCallingQueueState()).eq("empty");
+ });
+});
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx b/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx
new file mode 100644
index 000000000..c683a755c
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx
@@ -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 <http://www.gnu.org/licenses/>
+ */
+
+import { Amounts } from "@gnu-taler/taler-util";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { Fragment, h, VNode } from "preact";
+import { Amount } from "../../components/Amount.js";
+import { Part } from "../../components/Part.js";
+import { Button } from "../../mui/Button.js";
+import { State } from "./index.js";
+
+/**
+ *
+ * @author sebasjm
+ */
+
+export function ReadyView(state: State.Ready): VNode {
+ const { i18n } = useTranslationContext();
+
+ return (
+ <Fragment>
+ <section>
+ {Amounts.isNonZero(state.cost) && (
+ <Part
+ big
+ title={i18n.str`Cost`}
+ text={<Amount value={state.cost} />}
+ kind="negative"
+ />
+ )}
+ {Amounts.isNonZero(state.fee) && (
+ <Part
+ big
+ title={i18n.str`Fee`}
+ text={<Amount value={state.fee} />}
+ kind="negative"
+ />
+ )}
+ <Part
+ big
+ title={i18n.str`To be received`}
+ text={<Amount value={state.effective} />}
+ kind="positive"
+ />
+ </section>
+ <section>
+ <Button
+ variant="contained"
+ color="success"
+ onClick={state.confirm.onClick}
+ >
+ <i18n.Translate>
+ Send &nbsp; {<Amount value={state.cost} />}
+ </i18n.Translate>
+ </Button>
+ </section>
+ </Fragment>
+ );
+}