From fdbd55d2bde0961a4c1ff26b04e442459ab782b0 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 3 Aug 2023 18:35:07 +0200 Subject: -towards tip->reward rename --- .../src/components/HistoryItem.tsx | 2 +- .../src/cta/Reward/index.ts | 84 ++++++++ .../src/cta/Reward/state.ts | 99 +++++++++ .../src/cta/Reward/stories.tsx | 46 +++++ .../src/cta/Reward/test.ts | 228 +++++++++++++++++++++ .../src/cta/Reward/views.tsx | 89 ++++++++ .../taler-wallet-webextension/src/cta/Tip/index.ts | 84 -------- .../taler-wallet-webextension/src/cta/Tip/state.ts | 99 --------- .../src/cta/Tip/stories.tsx | 46 ----- .../taler-wallet-webextension/src/cta/Tip/test.ts | 228 --------------------- .../src/cta/Tip/views.tsx | 89 -------- .../src/cta/index.stories.ts | 2 +- .../src/wallet/Application.tsx | 2 +- .../src/wallet/History.stories.tsx | 6 +- .../src/wallet/Transaction.stories.tsx | 6 +- .../src/wallet/Transaction.tsx | 2 +- 16 files changed, 556 insertions(+), 556 deletions(-) create mode 100644 packages/taler-wallet-webextension/src/cta/Reward/index.ts create mode 100644 packages/taler-wallet-webextension/src/cta/Reward/state.ts create mode 100644 packages/taler-wallet-webextension/src/cta/Reward/stories.tsx create mode 100644 packages/taler-wallet-webextension/src/cta/Reward/test.ts create mode 100644 packages/taler-wallet-webextension/src/cta/Reward/views.tsx delete mode 100644 packages/taler-wallet-webextension/src/cta/Tip/index.ts delete mode 100644 packages/taler-wallet-webextension/src/cta/Tip/state.ts delete mode 100644 packages/taler-wallet-webextension/src/cta/Tip/stories.tsx delete mode 100644 packages/taler-wallet-webextension/src/cta/Tip/test.ts delete mode 100644 packages/taler-wallet-webextension/src/cta/Tip/views.tsx (limited to 'packages/taler-wallet-webextension/src') diff --git a/packages/taler-wallet-webextension/src/components/HistoryItem.tsx b/packages/taler-wallet-webextension/src/components/HistoryItem.tsx index a0ce04460..e072d2581 100644 --- a/packages/taler-wallet-webextension/src/components/HistoryItem.tsx +++ b/packages/taler-wallet-webextension/src/components/HistoryItem.tsx @@ -134,7 +134,7 @@ export function HistoryItem(props: { tx: Transaction }): VNode { } /> ); - case TransactionType.Tip: + case TransactionType.Reward: return ( + */ + +import { AmountJson } 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 { AcceptedView, IgnoredView, ReadyView } from "./views.js"; + +export interface Props { + talerTipUri?: string; + onCancel: () => Promise; + onSuccess: (tx: string) => Promise; +} + +export type State = + | State.Loading + | State.LoadingUriError + | State.Ignored + | State.Accepted + | State.Ready + | State.Ignored; + +export namespace State { + export interface Loading { + status: "loading"; + error: undefined; + } + + export interface LoadingUriError { + status: "error"; + error: ErrorAlert; + } + + export interface BaseInfo { + merchantBaseUrl: string; + amount: AmountJson; + exchangeBaseUrl: string; + error: undefined; + cancel: ButtonHandler; + } + + export interface Ignored extends BaseInfo { + status: "ignored"; + } + + export interface Accepted extends BaseInfo { + status: "accepted"; + } + export interface Ready extends BaseInfo { + status: "ready"; + accept: ButtonHandler; + } +} + +const viewMapping: StateViewMap = { + loading: Loading, + error: ErrorAlertView, + accepted: AcceptedView, + ignored: IgnoredView, + ready: ReadyView, +}; + +export const TipPage = compose( + "Tip", + (p: Props) => useComponentState(p), + viewMapping, +); diff --git a/packages/taler-wallet-webextension/src/cta/Reward/state.ts b/packages/taler-wallet-webextension/src/cta/Reward/state.ts new file mode 100644 index 000000000..98463cb60 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/Reward/state.ts @@ -0,0 +1,99 @@ +/* + 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 { 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({ + talerTipUri: talerRewardUri, + onCancel, + onSuccess, +}: Props): State { + const api = useBackendContext(); + const { i18n } = useTranslationContext(); + const { pushAlertOnError } = useAlertContext(); + const tipInfo = useAsyncAsHook(async () => { + if (!talerRewardUri) throw Error("ERROR_NO-URI-FOR-TIP"); + const tip = await api.wallet.call(WalletApiOperation.PrepareReward, { + talerRewardUri, + }); + return { tip }; + }); + + if (!tipInfo) { + return { + status: "loading", + error: undefined, + }; + } + if (tipInfo.hasError) { + return { + status: "error", + error: alertFromError( + i18n.str`Could not load the status of the term of service`, + tipInfo, + ), + }; + } + // if (tipInfo.hasError) { + // return { + // status: "loading-uri", + // error: tipInfo, + // }; + // } + + const { tip } = tipInfo.response; + + const doAccept = async (): Promise => { + const res = await api.wallet.call(WalletApiOperation.AcceptReward, { + walletRewardId: tip.walletRewardId, + }); + + //FIX: this may not be seen since we are moving to the success also + tipInfo.retry(); + onSuccess(res.transactionId); + }; + + const baseInfo = { + merchantBaseUrl: tip.merchantBaseUrl, + exchangeBaseUrl: tip.exchangeBaseUrl, + amount: Amounts.parseOrThrow(tip.rewardAmountEffective), + error: undefined, + cancel: { + onClick: pushAlertOnError(onCancel), + }, + }; + + if (tip.accepted) { + return { + status: "accepted", + ...baseInfo, + }; + } + + return { + status: "ready", + ...baseInfo, + accept: { + onClick: pushAlertOnError(doAccept), + }, + }; +} diff --git a/packages/taler-wallet-webextension/src/cta/Reward/stories.tsx b/packages/taler-wallet-webextension/src/cta/Reward/stories.tsx new file mode 100644 index 000000000..bd5fdefd9 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/Reward/stories.tsx @@ -0,0 +1,46 @@ +/* + 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 { Amounts } from "@gnu-taler/taler-util"; +import * as tests from "@gnu-taler/web-util/testing"; +import { AcceptedView, ReadyView } from "./views.js"; + +export default { + title: "tip", +}; + +export const Accepted = tests.createExample(AcceptedView, { + status: "accepted", + error: undefined, + amount: Amounts.parseOrThrow("EUR:1"), + exchangeBaseUrl: "", + merchantBaseUrl: "", +}); + +export const Ready = tests.createExample(ReadyView, { + status: "ready", + error: undefined, + amount: Amounts.parseOrThrow("EUR:1"), + merchantBaseUrl: "http://merchant.url/", + exchangeBaseUrl: "http://exchange.url/", + accept: {}, + cancel: {}, +}); diff --git a/packages/taler-wallet-webextension/src/cta/Reward/test.ts b/packages/taler-wallet-webextension/src/cta/Reward/test.ts new file mode 100644 index 000000000..6d7bad0c8 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/Reward/test.ts @@ -0,0 +1,228 @@ +/* + 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 { Amounts } from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { expect } from "chai"; +import * as tests from "@gnu-taler/web-util/testing"; +import { nullFunction } from "../../mui/handlers.js"; +import { createWalletApiMock } from "../../test-utils.js"; +import { Props } from "./index.js"; +import { useComponentState } from "./state.js"; + +describe("Tip CTA states", () => { + it("should tell the user that the URI is missing", async () => { + const { handler, TestingContext } = createWalletApiMock(); + + const props: Props = { + talerTipUri: undefined, + onCancel: nullFunction, + onSuccess: nullFunction, + }; + + const hookBehavior = await tests.hookBehaveLikeThis( + useComponentState, + props, + [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + ({ status, error }) => { + expect(status).equals("error"); + if (!error) expect.fail(); + expect(error.description).eq("ERROR_NO-URI-FOR-TIP"); + }, + ], + TestingContext, + ); + + expect(hookBehavior).deep.equal({ result: "ok" }); + expect(handler.getCallingQueueState()).eq("empty"); + }); + + it("should be ready for accepting the tip", async () => { + const { handler, TestingContext } = createWalletApiMock(); + + handler.addWalletCallResponse(WalletApiOperation.PrepareReward, undefined, { + accepted: false, + exchangeBaseUrl: "exchange url", + merchantBaseUrl: "merchant url", + rewardAmountEffective: "EUR:1", + walletRewardId: "tip_id", + transactionId: "txn:tip:ABC1234", + expirationTimestamp: { + t_s: 1, + }, + rewardAmountRaw: "", + }); + + const props: Props = { + talerTipUri: "taler://tip/asd", + onCancel: nullFunction, + onSuccess: nullFunction, + }; + + const hookBehavior = await tests.hookBehaveLikeThis( + useComponentState, + props, + [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + if (state.status !== "ready") { + expect(state).eq({ status: "ready" }); + return; + } + if (state.error) expect.fail(); + expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1")); + expect(state.merchantBaseUrl).eq("merchant url"); + expect(state.exchangeBaseUrl).eq("exchange url"); + if (state.accept.onClick === undefined) expect.fail(); + + handler.addWalletCallResponse(WalletApiOperation.AcceptReward); + state.accept.onClick(); + + handler.addWalletCallResponse( + WalletApiOperation.PrepareReward, + undefined, + { + accepted: true, + exchangeBaseUrl: "exchange url", + merchantBaseUrl: "merchant url", + rewardAmountEffective: "EUR:1", + walletRewardId: "tip_id", + transactionId: "txn:tip:ABC1234", + expirationTimestamp: { + t_s: 1, + }, + rewardAmountRaw: "", + }, + ); + }, + (state) => { + if (state.status !== "accepted") expect.fail(); + if (state.error) expect.fail(); + expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1")); + expect(state.merchantBaseUrl).eq("merchant url"); + expect(state.exchangeBaseUrl).eq("exchange url"); + }, + ], + TestingContext, + ); + + expect(hookBehavior).deep.equal({ result: "ok" }); + expect(handler.getCallingQueueState()).eq("empty"); + }); + + it.skip("should be ignored after clicking the ignore button", async () => { + const { handler, TestingContext } = createWalletApiMock(); + handler.addWalletCallResponse(WalletApiOperation.PrepareReward, undefined, { + exchangeBaseUrl: "exchange url", + merchantBaseUrl: "merchant url", + rewardAmountEffective: "EUR:1", + walletRewardId: "tip_id", + transactionId: "txn:tip:ABC1234", + accepted: false, + expirationTimestamp: { + t_s: 1, + }, + rewardAmountRaw: "", + }); + + const props: Props = { + talerTipUri: "taler://tip/asd", + onCancel: nullFunction, + onSuccess: nullFunction, + }; + + const hookBehavior = await tests.hookBehaveLikeThis( + useComponentState, + props, + [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + if (state.status !== "ready") expect.fail(); + if (state.error) expect.fail(); + expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1")); + expect(state.merchantBaseUrl).eq("merchant url"); + expect(state.exchangeBaseUrl).eq("exchange url"); + + //FIXME: add ignore button + }, + ], + TestingContext, + ); + + expect(hookBehavior).deep.equal({ result: "ok" }); + expect(handler.getCallingQueueState()).eq("empty"); + }); + + it("should render accepted if the tip has been used previously", async () => { + const { handler, TestingContext } = createWalletApiMock(); + + handler.addWalletCallResponse(WalletApiOperation.PrepareReward, undefined, { + accepted: true, + exchangeBaseUrl: "exchange url", + merchantBaseUrl: "merchant url", + rewardAmountEffective: "EUR:1", + walletRewardId: "tip_id", + transactionId: "txn:tip:ABC1234", + expirationTimestamp: { + t_s: 1, + }, + rewardAmountRaw: "", + }); + + const props: Props = { + talerTipUri: "taler://tip/asd", + onCancel: nullFunction, + onSuccess: nullFunction, + }; + + const hookBehavior = await tests.hookBehaveLikeThis( + useComponentState, + props, + [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + if (state.status !== "accepted") expect.fail(); + if (state.error) expect.fail(); + expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1")); + expect(state.merchantBaseUrl).eq("merchant url"); + expect(state.exchangeBaseUrl).eq("exchange url"); + }, + ], + TestingContext, + ); + + expect(hookBehavior).deep.equal({ result: "ok" }); + expect(handler.getCallingQueueState()).eq("empty"); + }); +}); diff --git a/packages/taler-wallet-webextension/src/cta/Reward/views.tsx b/packages/taler-wallet-webextension/src/cta/Reward/views.tsx new file mode 100644 index 000000000..5d99a0132 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/Reward/views.tsx @@ -0,0 +1,89 @@ +/* + 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 { TranslatedString } from "@gnu-taler/taler-util"; +import { Fragment, h, VNode } from "preact"; +import { Amount } from "../../components/Amount.js"; +import { LogoHeader } from "../../components/LogoHeader.js"; +import { Part } from "../../components/Part.js"; +import { Link, SubTitle, WalletAction } from "../../components/styled/index.js"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { Button } from "../../mui/Button.js"; +import { State } from "./index.js"; + +export function IgnoredView(state: State.Ignored): VNode { + const { i18n } = useTranslationContext(); + return ( + + + You've ignored the tip. + + + ); +} + +export function ReadyView(state: State.Ready): VNode { + const { i18n } = useTranslationContext(); + return ( + +
+

+ The merchant is offering you a tip +

+ } + kind="positive" + /> + + +
+
+ +
+
+ ); +} + +export function AcceptedView(state: State.Accepted): VNode { + const { i18n } = useTranslationContext(); + return ( + +
+ + Tip from {state.merchantBaseUrl} accepted. Check your + transactions list for more details. + +
+
+ ); +} diff --git a/packages/taler-wallet-webextension/src/cta/Tip/index.ts b/packages/taler-wallet-webextension/src/cta/Tip/index.ts deleted file mode 100644 index 5e56db7bc..000000000 --- a/packages/taler-wallet-webextension/src/cta/Tip/index.ts +++ /dev/null @@ -1,84 +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 { AmountJson } 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 { AcceptedView, IgnoredView, ReadyView } from "./views.js"; - -export interface Props { - talerTipUri?: string; - onCancel: () => Promise; - onSuccess: (tx: string) => Promise; -} - -export type State = - | State.Loading - | State.LoadingUriError - | State.Ignored - | State.Accepted - | State.Ready - | State.Ignored; - -export namespace State { - export interface Loading { - status: "loading"; - error: undefined; - } - - export interface LoadingUriError { - status: "error"; - error: ErrorAlert; - } - - export interface BaseInfo { - merchantBaseUrl: string; - amount: AmountJson; - exchangeBaseUrl: string; - error: undefined; - cancel: ButtonHandler; - } - - export interface Ignored extends BaseInfo { - status: "ignored"; - } - - export interface Accepted extends BaseInfo { - status: "accepted"; - } - export interface Ready extends BaseInfo { - status: "ready"; - accept: ButtonHandler; - } -} - -const viewMapping: StateViewMap = { - loading: Loading, - error: ErrorAlertView, - accepted: AcceptedView, - ignored: IgnoredView, - ready: ReadyView, -}; - -export const TipPage = compose( - "Tip", - (p: Props) => useComponentState(p), - viewMapping, -); diff --git a/packages/taler-wallet-webextension/src/cta/Tip/state.ts b/packages/taler-wallet-webextension/src/cta/Tip/state.ts deleted file mode 100644 index d34e9e264..000000000 --- a/packages/taler-wallet-webextension/src/cta/Tip/state.ts +++ /dev/null @@ -1,99 +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 { 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({ - talerTipUri, - onCancel, - onSuccess, -}: Props): State { - const api = useBackendContext(); - const { i18n } = useTranslationContext(); - const { pushAlertOnError } = useAlertContext(); - const tipInfo = useAsyncAsHook(async () => { - if (!talerTipUri) throw Error("ERROR_NO-URI-FOR-TIP"); - const tip = await api.wallet.call(WalletApiOperation.PrepareTip, { - talerTipUri, - }); - return { tip }; - }); - - if (!tipInfo) { - return { - status: "loading", - error: undefined, - }; - } - if (tipInfo.hasError) { - return { - status: "error", - error: alertFromError( - i18n.str`Could not load the status of the term of service`, - tipInfo, - ), - }; - } - // if (tipInfo.hasError) { - // return { - // status: "loading-uri", - // error: tipInfo, - // }; - // } - - const { tip } = tipInfo.response; - - const doAccept = async (): Promise => { - const res = await api.wallet.call(WalletApiOperation.AcceptTip, { - walletTipId: tip.walletTipId, - }); - - //FIX: this may not be seen since we are moving to the success also - tipInfo.retry(); - onSuccess(res.transactionId); - }; - - const baseInfo = { - merchantBaseUrl: tip.merchantBaseUrl, - exchangeBaseUrl: tip.exchangeBaseUrl, - amount: Amounts.parseOrThrow(tip.tipAmountEffective), - error: undefined, - cancel: { - onClick: pushAlertOnError(onCancel), - }, - }; - - if (tip.accepted) { - return { - status: "accepted", - ...baseInfo, - }; - } - - return { - status: "ready", - ...baseInfo, - accept: { - onClick: pushAlertOnError(doAccept), - }, - }; -} diff --git a/packages/taler-wallet-webextension/src/cta/Tip/stories.tsx b/packages/taler-wallet-webextension/src/cta/Tip/stories.tsx deleted file mode 100644 index bd5fdefd9..000000000 --- a/packages/taler-wallet-webextension/src/cta/Tip/stories.tsx +++ /dev/null @@ -1,46 +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 { Amounts } from "@gnu-taler/taler-util"; -import * as tests from "@gnu-taler/web-util/testing"; -import { AcceptedView, ReadyView } from "./views.js"; - -export default { - title: "tip", -}; - -export const Accepted = tests.createExample(AcceptedView, { - status: "accepted", - error: undefined, - amount: Amounts.parseOrThrow("EUR:1"), - exchangeBaseUrl: "", - merchantBaseUrl: "", -}); - -export const Ready = tests.createExample(ReadyView, { - status: "ready", - error: undefined, - amount: Amounts.parseOrThrow("EUR:1"), - merchantBaseUrl: "http://merchant.url/", - exchangeBaseUrl: "http://exchange.url/", - accept: {}, - cancel: {}, -}); diff --git a/packages/taler-wallet-webextension/src/cta/Tip/test.ts b/packages/taler-wallet-webextension/src/cta/Tip/test.ts deleted file mode 100644 index e0b6210a2..000000000 --- a/packages/taler-wallet-webextension/src/cta/Tip/test.ts +++ /dev/null @@ -1,228 +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 { Amounts } from "@gnu-taler/taler-util"; -import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { expect } from "chai"; -import * as tests from "@gnu-taler/web-util/testing"; -import { nullFunction } from "../../mui/handlers.js"; -import { createWalletApiMock } from "../../test-utils.js"; -import { Props } from "./index.js"; -import { useComponentState } from "./state.js"; - -describe("Tip CTA states", () => { - it("should tell the user that the URI is missing", async () => { - const { handler, TestingContext } = createWalletApiMock(); - - const props: Props = { - talerTipUri: undefined, - onCancel: nullFunction, - onSuccess: nullFunction, - }; - - const hookBehavior = await tests.hookBehaveLikeThis( - useComponentState, - props, - [ - ({ status, error }) => { - expect(status).equals("loading"); - expect(error).undefined; - }, - ({ status, error }) => { - expect(status).equals("error"); - if (!error) expect.fail(); - expect(error.description).eq("ERROR_NO-URI-FOR-TIP"); - }, - ], - TestingContext, - ); - - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); - - it("should be ready for accepting the tip", async () => { - const { handler, TestingContext } = createWalletApiMock(); - - handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, { - accepted: false, - exchangeBaseUrl: "exchange url", - merchantBaseUrl: "merchant url", - tipAmountEffective: "EUR:1", - walletTipId: "tip_id", - transactionId: "txn:tip:ABC1234", - expirationTimestamp: { - t_s: 1, - }, - tipAmountRaw: "", - }); - - const props: Props = { - talerTipUri: "taler://tip/asd", - onCancel: nullFunction, - onSuccess: nullFunction, - }; - - const hookBehavior = await tests.hookBehaveLikeThis( - useComponentState, - props, - [ - ({ status, error }) => { - expect(status).equals("loading"); - expect(error).undefined; - }, - (state) => { - if (state.status !== "ready") { - expect(state).eq({ status: "ready" }); - return; - } - if (state.error) expect.fail(); - expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1")); - expect(state.merchantBaseUrl).eq("merchant url"); - expect(state.exchangeBaseUrl).eq("exchange url"); - if (state.accept.onClick === undefined) expect.fail(); - - handler.addWalletCallResponse(WalletApiOperation.AcceptTip); - state.accept.onClick(); - - handler.addWalletCallResponse( - WalletApiOperation.PrepareTip, - undefined, - { - accepted: true, - exchangeBaseUrl: "exchange url", - merchantBaseUrl: "merchant url", - tipAmountEffective: "EUR:1", - walletTipId: "tip_id", - transactionId: "txn:tip:ABC1234", - expirationTimestamp: { - t_s: 1, - }, - tipAmountRaw: "", - }, - ); - }, - (state) => { - if (state.status !== "accepted") expect.fail(); - if (state.error) expect.fail(); - expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1")); - expect(state.merchantBaseUrl).eq("merchant url"); - expect(state.exchangeBaseUrl).eq("exchange url"); - }, - ], - TestingContext, - ); - - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); - - it.skip("should be ignored after clicking the ignore button", async () => { - const { handler, TestingContext } = createWalletApiMock(); - handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, { - exchangeBaseUrl: "exchange url", - merchantBaseUrl: "merchant url", - tipAmountEffective: "EUR:1", - walletTipId: "tip_id", - transactionId: "txn:tip:ABC1234", - accepted: false, - expirationTimestamp: { - t_s: 1, - }, - tipAmountRaw: "", - }); - - const props: Props = { - talerTipUri: "taler://tip/asd", - onCancel: nullFunction, - onSuccess: nullFunction, - }; - - const hookBehavior = await tests.hookBehaveLikeThis( - useComponentState, - props, - [ - ({ status, error }) => { - expect(status).equals("loading"); - expect(error).undefined; - }, - (state) => { - if (state.status !== "ready") expect.fail(); - if (state.error) expect.fail(); - expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1")); - expect(state.merchantBaseUrl).eq("merchant url"); - expect(state.exchangeBaseUrl).eq("exchange url"); - - //FIXME: add ignore button - }, - ], - TestingContext, - ); - - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); - - it("should render accepted if the tip has been used previously", async () => { - const { handler, TestingContext } = createWalletApiMock(); - - handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, { - accepted: true, - exchangeBaseUrl: "exchange url", - merchantBaseUrl: "merchant url", - tipAmountEffective: "EUR:1", - walletTipId: "tip_id", - transactionId: "txn:tip:ABC1234", - expirationTimestamp: { - t_s: 1, - }, - tipAmountRaw: "", - }); - - const props: Props = { - talerTipUri: "taler://tip/asd", - onCancel: nullFunction, - onSuccess: nullFunction, - }; - - const hookBehavior = await tests.hookBehaveLikeThis( - useComponentState, - props, - [ - ({ status, error }) => { - expect(status).equals("loading"); - expect(error).undefined; - }, - (state) => { - if (state.status !== "accepted") expect.fail(); - if (state.error) expect.fail(); - expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1")); - expect(state.merchantBaseUrl).eq("merchant url"); - expect(state.exchangeBaseUrl).eq("exchange url"); - }, - ], - TestingContext, - ); - - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); -}); diff --git a/packages/taler-wallet-webextension/src/cta/Tip/views.tsx b/packages/taler-wallet-webextension/src/cta/Tip/views.tsx deleted file mode 100644 index 5d99a0132..000000000 --- a/packages/taler-wallet-webextension/src/cta/Tip/views.tsx +++ /dev/null @@ -1,89 +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 { TranslatedString } from "@gnu-taler/taler-util"; -import { Fragment, h, VNode } from "preact"; -import { Amount } from "../../components/Amount.js"; -import { LogoHeader } from "../../components/LogoHeader.js"; -import { Part } from "../../components/Part.js"; -import { Link, SubTitle, WalletAction } from "../../components/styled/index.js"; -import { useTranslationContext } from "@gnu-taler/web-util/browser"; -import { Button } from "../../mui/Button.js"; -import { State } from "./index.js"; - -export function IgnoredView(state: State.Ignored): VNode { - const { i18n } = useTranslationContext(); - return ( - - - You've ignored the tip. - - - ); -} - -export function ReadyView(state: State.Ready): VNode { - const { i18n } = useTranslationContext(); - return ( - -
-

- The merchant is offering you a tip -

- } - kind="positive" - /> - - -
-
- -
-
- ); -} - -export function AcceptedView(state: State.Accepted): VNode { - const { i18n } = useTranslationContext(); - return ( - -
- - Tip from {state.merchantBaseUrl} accepted. Check your - transactions list for more details. - -
-
- ); -} diff --git a/packages/taler-wallet-webextension/src/cta/index.stories.ts b/packages/taler-wallet-webextension/src/cta/index.stories.ts index 84863f84f..06b11ef6d 100644 --- a/packages/taler-wallet-webextension/src/cta/index.stories.ts +++ b/packages/taler-wallet-webextension/src/cta/index.stories.ts @@ -22,7 +22,7 @@ export * as a1 from "./Deposit/stories.jsx"; export * as a3 from "./Payment/stories.jsx"; export * as a4 from "./Refund/stories.jsx"; -export * as a5 from "./Tip/stories.jsx"; +export * as a5 from "./Reward/stories.js"; export * as a6 from "./Withdraw/stories.jsx"; export * as a8 from "./InvoiceCreate/stories.js"; export * as a9 from "./InvoicePay/stories.js"; diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx b/packages/taler-wallet-webextension/src/wallet/Application.tsx index d8cb22bf0..98515aac0 100644 --- a/packages/taler-wallet-webextension/src/wallet/Application.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx @@ -58,7 +58,7 @@ import { PaymentPage } from "../cta/Payment/index.js"; import { PaymentTemplatePage } from "../cta/PaymentTemplate/index.js"; import { RecoveryPage } from "../cta/Recovery/index.js"; import { RefundPage } from "../cta/Refund/index.js"; -import { TipPage } from "../cta/Tip/index.js"; +import { TipPage } from "../cta/Reward/index.js"; import { TransferCreatePage } from "../cta/TransferCreate/index.js"; import { TransferPickupPage } from "../cta/TransferPickup/index.js"; import { diff --git a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx index 149c8c1f4..1ddb24b02 100644 --- a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx @@ -34,7 +34,7 @@ import { TransactionPeerPushDebit, TransactionRefresh, TransactionRefund, - TransactionTip, + TransactionReward, TransactionType, TransactionWithdrawal, WithdrawalType, @@ -113,9 +113,9 @@ const exampleData = { } as TransactionRefresh, tip: { ...commonTransaction(), - type: TransactionType.Tip, + type: TransactionType.Reward, merchantBaseUrl: "http://ads.merchant.taler.net/", - } as TransactionTip, + } as TransactionReward, refund: { ...commonTransaction(), type: TransactionType.Refund, diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx index f2e3982f6..3ba3ac591 100644 --- a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx @@ -37,7 +37,7 @@ import { TransactionPeerPushDebit, TransactionRefresh, TransactionRefund, - TransactionTip, + TransactionReward, TransactionType, TransactionWithdrawal, WithdrawalDetails, @@ -138,7 +138,7 @@ const exampleData = { } as TransactionRefresh, tip: { ...commonTransaction, - type: TransactionType.Tip, + type: TransactionType.Reward, // merchant: { // name: "the merchant", // logo: merchantIcon, @@ -146,7 +146,7 @@ const exampleData = { // email: "contact@merchant.taler", // }, merchantBaseUrl: "http://merchant.taler", - } as TransactionTip, + } as TransactionReward, refund: { ...commonTransaction, type: TransactionType.Refund, diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx index 8d564a275..e54137016 100644 --- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx @@ -745,7 +745,7 @@ export function TransactionView({ ); } - if (transaction.type === TransactionType.Tip) { + if (transaction.type === TransactionType.Reward) { return ( Date: Thu, 3 Aug 2023 19:03:24 +0200 Subject: rename tip->reward in URI --- packages/taler-util/src/taleruri.test.ts | 8 +++---- packages/taler-util/src/taleruri.ts | 28 +++++++++++----------- packages/taler-wallet-cli/src/index.ts | 2 +- .../taler-wallet-core/src/operations/reward.ts | 4 ++-- .../src/NavigationBar.tsx | 2 +- .../src/platform/chrome.ts | 2 +- .../src/popup/TalerActionFound.tsx | 2 +- .../src/wallet/AddNewActionView.tsx | 2 +- 8 files changed, 25 insertions(+), 25 deletions(-) (limited to 'packages/taler-wallet-webextension/src') diff --git a/packages/taler-util/src/taleruri.test.ts b/packages/taler-util/src/taleruri.test.ts index 3244bbbd9..0dcf92252 100644 --- a/packages/taler-util/src/taleruri.test.ts +++ b/packages/taler-util/src/taleruri.test.ts @@ -21,7 +21,7 @@ import { parsePayUri, parseRefundUri, parseRestoreUri, - parseTipUri, + parseRewardUri, parseWithdrawExchangeUri, parseWithdrawUri, stringifyPayPushUri, @@ -161,7 +161,7 @@ test("taler refund uri parsing with instance", (t) => { test("taler tip pickup uri", (t) => { const url1 = "taler://tip/merchant.example.com/tipid"; - const r1 = parseTipUri(url1); + const r1 = parseRewardUri(url1); if (!r1) { t.fail(); return; @@ -171,7 +171,7 @@ test("taler tip pickup uri", (t) => { test("taler tip pickup uri with instance", (t) => { const url1 = "taler://tip/merchant.example.com/instances/tipm/tipid"; - const r1 = parseTipUri(url1); + const r1 = parseRewardUri(url1); if (!r1) { t.fail(); return; @@ -182,7 +182,7 @@ test("taler tip pickup uri with instance", (t) => { test("taler tip pickup uri with instance and prefix", (t) => { const url1 = "taler://tip/merchant.example.com/my/pfx/tipm/tipid"; - const r1 = parseTipUri(url1); + const r1 = parseRewardUri(url1); if (!r1) { t.fail(); return; diff --git a/packages/taler-util/src/taleruri.ts b/packages/taler-util/src/taleruri.ts index fc140811b..777cb5245 100644 --- a/packages/taler-util/src/taleruri.ts +++ b/packages/taler-util/src/taleruri.ts @@ -26,7 +26,7 @@ export type TalerUri = | PayPushUriResult | BackupRestoreUri | RefundUriResult - | TipUriResult + | RewardUriResult | WithdrawUriResult | ExchangeUri | WithdrawExchangeUri @@ -60,8 +60,8 @@ export interface RefundUriResult { orderId: string; } -export interface TipUriResult { - type: TalerUriAction.Tip; +export interface RewardUriResult { + type: TalerUriAction.Reward; merchantBaseUrl: string; merchantTipId: string; } @@ -167,7 +167,7 @@ export enum TalerUriAction { Pay = "pay", Withdraw = "withdraw", Refund = "refund", - Tip = "tip", + Reward = "reward", PayPull = "pay-pull", PayPush = "pay-push", PayTemplate = "pay-template", @@ -212,7 +212,7 @@ const parsers: { [A in TalerUriAction]: Parser } = { [TalerUriAction.PayTemplate]: parsePayTemplateUri, [TalerUriAction.Restore]: parseRestoreUri, [TalerUriAction.Refund]: parseRefundUri, - [TalerUriAction.Tip]: parseTipUri, + [TalerUriAction.Reward]: parseRewardUri, [TalerUriAction.Withdraw]: parseWithdrawUri, [TalerUriAction.DevExperiment]: parseDevExperimentUri, [TalerUriAction.Exchange]: parseExchangeUri, @@ -255,8 +255,8 @@ export function stringifyTalerUri(uri: TalerUri): string { case TalerUriAction.Refund: { return stringifyRefundUri(uri); } - case TalerUriAction.Tip: { - return stringifyTipUri(uri); + case TalerUriAction.Reward: { + return stringifyRewardUri(uri); } case TalerUriAction.Withdraw: { return stringifyWithdrawUri(uri); @@ -394,11 +394,11 @@ export function parsePayPullUri(s: string): PayPullUriResult | undefined { } /** - * Parse a taler[+http]://tip URI. + * Parse a taler[+http]://reward URI. * Return undefined if not passed a valid URI. */ -export function parseTipUri(s: string): TipUriResult | undefined { - const pi = parseProtoInfo(s, "tip"); +export function parseRewardUri(s: string): RewardUriResult | undefined { + const pi = parseProtoInfo(s, "reward"); if (!pi) { return undefined; } @@ -416,7 +416,7 @@ export function parseTipUri(s: string): TipUriResult | undefined { ); return { - type: TalerUriAction.Tip, + type: TalerUriAction.Reward, merchantBaseUrl, merchantTipId: tipId, }; @@ -699,12 +699,12 @@ export function stringifyRefundUri({ const { proto, path } = getUrlInfo(merchantBaseUrl); return `${proto}://refund/${path}${orderId}`; } -export function stringifyTipUri({ +export function stringifyRewardUri({ merchantBaseUrl, merchantTipId, -}: Omit): string { +}: Omit): string { const { proto, path } = getUrlInfo(merchantBaseUrl); - return `${proto}://tip/${path}${merchantTipId}`; + return `${proto}://reward/${path}${merchantTipId}`; } export function stringifyExchangeUri({ diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index a34f6be03..e2787db66 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -651,7 +651,7 @@ walletCli alwaysYes: args.handleUri.autoYes, }); break; - case TalerUriAction.Tip: { + case TalerUriAction.Reward: { const res = await wallet.client.call(WalletApiOperation.PrepareReward, { talerRewardUri: uri, }); diff --git a/packages/taler-wallet-core/src/operations/reward.ts b/packages/taler-wallet-core/src/operations/reward.ts index 58c745780..47956f15f 100644 --- a/packages/taler-wallet-core/src/operations/reward.ts +++ b/packages/taler-wallet-core/src/operations/reward.ts @@ -31,7 +31,7 @@ import { j2s, Logger, NotificationType, - parseTipUri, + parseRewardUri, PrepareTipResult, TalerErrorCode, TalerPreciseTimestamp, @@ -141,7 +141,7 @@ export async function prepareTip( ws: InternalWalletState, talerTipUri: string, ): Promise { - const res = parseTipUri(talerTipUri); + const res = parseRewardUri(talerTipUri); if (!res) { throw Error("invalid taler://tip URI"); } diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx b/packages/taler-wallet-webextension/src/NavigationBar.tsx index 231418861..167f1797c 100644 --- a/packages/taler-wallet-webextension/src/NavigationBar.tsx +++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx @@ -146,7 +146,7 @@ const talerUriActionToPageName: { } = { [TalerUriAction.Withdraw]: "ctaWithdraw", [TalerUriAction.Pay]: "ctaPay", - [TalerUriAction.Tip]: "ctaTips", + [TalerUriAction.Reward]: "ctaTips", [TalerUriAction.Refund]: "ctaRefund", [TalerUriAction.PayPull]: "ctaInvoicePay", [TalerUriAction.PayPush]: "ctaTransferPickup", diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts b/packages/taler-wallet-webextension/src/platform/chrome.ts index 1295fa514..a50f225dc 100644 --- a/packages/taler-wallet-webextension/src/platform/chrome.ts +++ b/packages/taler-wallet-webextension/src/platform/chrome.ts @@ -279,7 +279,7 @@ function openWalletURIFromPopup(uri: TalerUri): void { `static/wallet.html#/cta/pay?talerUri=${encodeURIComponent(talerUri)}`, ); break; - case TalerUriAction.Tip: + case TalerUriAction.Reward: url = chrome.runtime.getURL( `static/wallet.html#/cta/tip?talerUri=${encodeURIComponent(talerUri)}`, ); diff --git a/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx b/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx index 6a0585907..e120334e8 100644 --- a/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx +++ b/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx @@ -65,7 +65,7 @@ function ContentByUriType({ ); - case TalerUriAction.Tip: + case TalerUriAction.Reward: return (

diff --git a/packages/taler-wallet-webextension/src/wallet/AddNewActionView.tsx b/packages/taler-wallet-webextension/src/wallet/AddNewActionView.tsx index fd9815401..fc3a0916c 100644 --- a/packages/taler-wallet-webextension/src/wallet/AddNewActionView.tsx +++ b/packages/taler-wallet-webextension/src/wallet/AddNewActionView.tsx @@ -66,7 +66,7 @@ export function AddNewActionView({ onCancel }: Props): VNode { return Open pay page; case TalerUriAction.Refund: return Open refund page; - case TalerUriAction.Tip: + case TalerUriAction.Reward: return Open tip page; case TalerUriAction.Withdraw: return Open withdraw page; -- cgit v1.2.3