diff options
Diffstat (limited to 'packages/taler-wallet-webextension')
11 files changed, 450 insertions, 379 deletions
diff --git a/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx b/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx index 427c4bfee..3866fc991 100644 --- a/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx +++ b/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx @@ -16,9 +16,9 @@ import { AbsoluteTime, Amounts, - ExtendedStatus, NotificationType, Transaction, + TransactionMajorState, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { Fragment, h, JSX, VNode } from "preact"; @@ -58,7 +58,7 @@ export function PendingTransactions({ goToTransaction }: Props): VNode { !state || state.hasError ? cache.tx : state.response.transactions.filter( - (t) => t.extendedStatus === ExtendedStatus.Pending, + (t) => t.txState.major === TransactionMajorState.Pending, ); if (state && !state.hasError) { diff --git a/packages/taler-wallet-webextension/src/components/TransactionItem.tsx b/packages/taler-wallet-webextension/src/components/TransactionItem.tsx index 9af768641..eda190110 100644 --- a/packages/taler-wallet-webextension/src/components/TransactionItem.tsx +++ b/packages/taler-wallet-webextension/src/components/TransactionItem.tsx @@ -22,7 +22,7 @@ import { Transaction, TransactionType, WithdrawalType, - ExtendedStatus, + TransactionMajorState, } from "@gnu-taler/taler-util"; import { h, VNode } from "preact"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; @@ -42,6 +42,9 @@ import { Time } from "./Time.js"; export function TransactionItem(props: { tx: Transaction }): VNode { const tx = props.tx; const { i18n } = useTranslationContext(); + /** + * + */ switch (tx.type) { case TransactionType.Withdrawal: return ( @@ -53,7 +56,7 @@ export function TransactionItem(props: { tx: Transaction }): VNode { timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)} iconPath={"W"} pending={ - tx.extendedStatus === ExtendedStatus.Pending + tx.txState.major === TransactionMajorState.Pending ? tx.withdrawalDetails.type === WithdrawalType.TalerBankIntegrationApi ? !tx.withdrawalDetails.confirmed @@ -77,7 +80,7 @@ export function TransactionItem(props: { tx: Transaction }): VNode { timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)} iconPath={"P"} pending={ - tx.extendedStatus === ExtendedStatus.Pending + tx.txState.major === TransactionMajorState.Pending ? i18n.str`Payment in progress` : undefined } @@ -89,12 +92,12 @@ export function TransactionItem(props: { tx: Transaction }): VNode { id={tx.transactionId} amount={tx.amountEffective} debitCreditIndicator={"credit"} - subtitle={tx.info.summary} - title={tx.info.merchant.name} + subtitle={"tx.info.summary"} //FIXME: DD37 wallet-core is not returning this value + title={"tx.info.merchant.name"} //FIXME: DD37 wallet-core is not returning this value timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)} iconPath={"R"} pending={ - tx.extendedStatus === ExtendedStatus.Pending + tx.txState.major === TransactionMajorState.Pending ? i18n.str`Executing refund...` : undefined } @@ -110,7 +113,7 @@ export function TransactionItem(props: { tx: Transaction }): VNode { timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)} iconPath={"T"} pending={ - tx.extendedStatus === ExtendedStatus.Pending + tx.txState.major === TransactionMajorState.Pending ? i18n.str`Grabbing the tipping...` : undefined } @@ -126,7 +129,7 @@ export function TransactionItem(props: { tx: Transaction }): VNode { timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)} iconPath={"R"} pending={ - tx.extendedStatus === ExtendedStatus.Pending + tx.txState.major === TransactionMajorState.Pending ? i18n.str`Refreshing coins...` : undefined } @@ -142,7 +145,7 @@ export function TransactionItem(props: { tx: Transaction }): VNode { timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)} iconPath={"D"} pending={ - tx.extendedStatus === ExtendedStatus.Pending + tx.txState.major === TransactionMajorState.Pending ? i18n.str`Deposit in progress` : undefined } @@ -158,7 +161,7 @@ export function TransactionItem(props: { tx: Transaction }): VNode { timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)} iconPath={"I"} pending={ - tx.extendedStatus === ExtendedStatus.Pending + tx.txState.major === TransactionMajorState.Pending ? i18n.str`Waiting to be paid` : undefined } @@ -174,7 +177,7 @@ export function TransactionItem(props: { tx: Transaction }): VNode { timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)} iconPath={"I"} pending={ - tx.extendedStatus === ExtendedStatus.Pending + tx.txState.major === TransactionMajorState.Pending ? i18n.str`Payment in progress` : undefined } @@ -190,7 +193,7 @@ export function TransactionItem(props: { tx: Transaction }): VNode { timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)} iconPath={"T"} pending={ - tx.extendedStatus === ExtendedStatus.Pending + tx.txState.major === TransactionMajorState.Pending ? i18n.str`Receiving the transfer` : undefined } @@ -206,7 +209,7 @@ export function TransactionItem(props: { tx: Transaction }): VNode { timestamp={AbsoluteTime.fromTimestamp(tx.timestamp)} iconPath={"T"} pending={ - tx.extendedStatus === ExtendedStatus.Pending + tx.txState.major === TransactionMajorState.Pending ? i18n.str`Waiting to be received` : undefined } diff --git a/packages/taler-wallet-webextension/src/cta/Payment/stories.tsx b/packages/taler-wallet-webextension/src/cta/Payment/stories.tsx index 1450c627a..98d0c5f64 100644 --- a/packages/taler-wallet-webextension/src/cta/Payment/stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/Payment/stories.tsx @@ -48,6 +48,7 @@ export const NoEnoughBalanceAvailable = tests.createExample(BaseView, { uri: "", payStatus: { + transactionId: " ", status: PreparePayResultType.InsufficientBalance, balanceDetails: { amountRequested: "USD:10", @@ -87,6 +88,7 @@ export const NoEnoughBalanceMaterial = tests.createExample(BaseView, { uri: "", payStatus: { + transactionId: " ", status: PreparePayResultType.InsufficientBalance, balanceDetails: { amountRequested: "USD:10", @@ -126,6 +128,7 @@ export const NoEnoughBalanceAgeAcceptable = tests.createExample(BaseView, { uri: "", payStatus: { + transactionId: " ", status: PreparePayResultType.InsufficientBalance, balanceDetails: { amountRequested: "USD:10", @@ -166,6 +169,7 @@ export const NoEnoughBalanceMerchantAcceptable = tests.createExample(BaseView, { uri: "", payStatus: { + transactionId: " ", status: PreparePayResultType.InsufficientBalance, balanceDetails: { amountRequested: "USD:10", @@ -207,6 +211,7 @@ export const NoEnoughBalanceMerchantDepositable = tests.createExample( uri: "", payStatus: { + transactionId: " ", status: PreparePayResultType.InsufficientBalance, balanceDetails: { amountRequested: "USD:10", @@ -247,6 +252,7 @@ export const NoEnoughBalanceFeeGap = tests.createExample(BaseView, { uri: "", payStatus: { + transactionId: " ", status: PreparePayResultType.InsufficientBalance, balanceDetails: { amountRequested: "USD:10", @@ -290,6 +296,7 @@ export const PaymentPossible = tests.createExample(BaseView, { uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0", payStatus: { + transactionId: " ", status: PreparePayResultType.PaymentPossible, talerUri: "taler://pay/..", amountEffective: "USD:10", @@ -329,6 +336,7 @@ export const PaymentPossibleWithFee = tests.createExample(BaseView, { uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0", payStatus: { + transactionId: " ", status: PreparePayResultType.PaymentPossible, talerUri: "taler://pay/..", amountEffective: "USD:10.20", @@ -365,6 +373,7 @@ export const TicketWithAProductList = tests.createExample(BaseView, { uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0", payStatus: { + transactionId: " ", status: PreparePayResultType.PaymentPossible, talerUri: "taler://pay/..", amountEffective: "USD:10.20", @@ -420,6 +429,7 @@ export const TicketWithShipping = tests.createExample(BaseView, { uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0", payStatus: { + transactionId: " ", status: PreparePayResultType.PaymentPossible, talerUri: "taler://pay/..", amountEffective: "USD:10.20", @@ -467,6 +477,7 @@ export const AlreadyConfirmedByOther = tests.createExample(BaseView, { uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0", payStatus: { + transactionId: " ", status: PreparePayResultType.AlreadyConfirmed, talerUri: "taler://pay/..", amountEffective: "USD:10", diff --git a/packages/taler-wallet-webextension/src/cta/Refund/index.ts b/packages/taler-wallet-webextension/src/cta/Refund/index.ts index e90f770ff..bbb72c328 100644 --- a/packages/taler-wallet-webextension/src/cta/Refund/index.ts +++ b/packages/taler-wallet-webextension/src/cta/Refund/index.ts @@ -21,7 +21,7 @@ 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 { IgnoredView, InProgressView, ReadyView } from "./views.js"; +import { IgnoredView, ReadyView } from "./views.js"; export interface Props { talerRefundUri?: string; @@ -33,8 +33,8 @@ export type State = | State.Loading | State.LoadingUriError | State.Ready - | State.Ignored - | State.InProgress; + // | State.InProgress + | State.Ignored; export namespace State { export interface Loading { @@ -51,8 +51,8 @@ export namespace State { merchantName: string; products: Product[] | undefined; amount: AmountJson; - awaitingAmount: AmountJson; - granted: AmountJson; + // awaitingAmount: AmountJson; + // granted: AmountJson; } export interface Ready extends BaseInfo { @@ -69,16 +69,16 @@ export namespace State { status: "ignored"; error: undefined; } - export interface InProgress extends BaseInfo { - status: "in-progress"; - error: undefined; - } + // export interface InProgress extends BaseInfo { + // status: "in-progress"; + // error: undefined; + // } } const viewMapping: StateViewMap<State> = { loading: Loading, error: ErrorAlertView, - "in-progress": InProgressView, + // "in-progress": InProgressView, ignored: IgnoredView, ready: ReadyView, }; diff --git a/packages/taler-wallet-webextension/src/cta/Refund/state.ts b/packages/taler-wallet-webextension/src/cta/Refund/state.ts index 7d6576445..eb7d8834f 100644 --- a/packages/taler-wallet-webextension/src/cta/Refund/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Refund/state.ts @@ -14,7 +14,12 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { Amounts, NotificationType } from "@gnu-taler/taler-util"; +import { + Amounts, + NotificationType, + TransactionPayment, + TransactionType, +} from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useEffect, useState } from "preact/hooks"; import { alertFromError, useAlertContext } from "../../context/alert.js"; @@ -35,10 +40,22 @@ export function useComponentState({ const info = useAsyncAsHook(async () => { if (!talerRefundUri) throw Error("ERROR_NO-URI-FOR-REFUND"); - const refund = await api.wallet.call(WalletApiOperation.StartRefundQueryForUri, { - talerRefundUri, - }); - return { refund, uri: talerRefundUri }; + const refund = await api.wallet.call( + WalletApiOperation.StartRefundQueryForUri, + { + talerRefundUri, + }, + ); + const purchase = await api.wallet.call( + WalletApiOperation.GetTransactionById, + { + transactionId: refund.transactionId, + }, + ); + if (purchase.type !== TransactionType.Payment) { + throw Error("Refund of non purchase transaction is not handled"); + } + return { refund, purchase, uri: talerRefundUri }; }); useEffect(() => @@ -67,12 +84,15 @@ export function useComponentState({ // }; // } - const { refund, uri } = info.response; + const { refund, purchase, uri } = info.response; const doAccept = async (): Promise<void> => { - const res = await api.wallet.call(WalletApiOperation.AcceptPurchaseRefund, { - transactionId: uri, - }); + const res = await api.wallet.call( + WalletApiOperation.StartRefundQueryForUri, + { + talerRefundUri: uri, + }, + ); onSuccess(res.transactionId); }; @@ -82,11 +102,11 @@ export function useComponentState({ }; const baseInfo = { - amount: Amounts.parseOrThrow(info.response.refund.effectivePaid), - granted: Amounts.parseOrThrow(info.response.refund.granted), - merchantName: info.response.refund.info.merchant.name, - products: info.response.refund.info.products, - awaitingAmount: Amounts.parseOrThrow(refund.awaiting), + amount: Amounts.parseOrThrow(purchase.amountEffective), + // granted: Amounts.parseOrThrow(info.response.refund.granted), + // awaitingAmount: Amounts.parseOrThrow(refund.awaiting), + merchantName: purchase.info.merchant.name, + products: purchase.info.products, error: undefined, }; @@ -97,17 +117,18 @@ export function useComponentState({ }; } - if (refund.pending) { - return { - status: "in-progress", - ...baseInfo, - }; - } + //FIXME: DD37 wallet-core is not returning this value + // if (refund.pending) { + // return { + // status: "in-progress", + // ...baseInfo, + // }; + // } return { status: "ready", ...baseInfo, - orderId: info.response.refund.info.orderId, + orderId: purchase.info.orderId, accept: { onClick: pushAlertOnError(doAccept), }, diff --git a/packages/taler-wallet-webextension/src/cta/Refund/stories.tsx b/packages/taler-wallet-webextension/src/cta/Refund/stories.tsx index 649e427a5..ef1f76033 100644 --- a/packages/taler-wallet-webextension/src/cta/Refund/stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/Refund/stories.tsx @@ -22,20 +22,20 @@ import { Amounts } from "@gnu-taler/taler-util"; import beer from "../../../static-dev/beer.png"; import * as tests from "@gnu-taler/web-util/testing"; -import { IgnoredView, InProgressView, ReadyView } from "./views.js"; +import { IgnoredView, ReadyView } from "./views.js"; export default { title: "refund", }; -export const InProgress = tests.createExample(InProgressView, { - status: "in-progress", - error: undefined, - amount: Amounts.parseOrThrow("USD:1"), - awaitingAmount: Amounts.parseOrThrow("USD:1"), - granted: Amounts.parseOrThrow("USD:0"), - merchantName: "the merchant", - products: undefined, -}); +// export const InProgress = tests.createExample(InProgressView, { +// status: "in-progress", +// error: undefined, +// amount: Amounts.parseOrThrow("USD:1"), +// awaitingAmount: Amounts.parseOrThrow("USD:1"), +// granted: Amounts.parseOrThrow("USD:0"), +// merchantName: "the merchant", +// products: undefined, +// }); export const Ready = tests.createExample(ReadyView, { status: "ready", @@ -44,8 +44,8 @@ export const Ready = tests.createExample(ReadyView, { ignore: {}, amount: Amounts.parseOrThrow("USD:1"), - awaitingAmount: Amounts.parseOrThrow("USD:1"), - granted: Amounts.parseOrThrow("USD:0"), + // awaitingAmount: Amounts.parseOrThrow("USD:1"), + // granted: Amounts.parseOrThrow("USD:0"), merchantName: "the merchant", products: [], orderId: "abcdef", @@ -57,8 +57,8 @@ export const WithAProductList = tests.createExample(ReadyView, { accept: {}, ignore: {}, amount: Amounts.parseOrThrow("USD:1"), - awaitingAmount: Amounts.parseOrThrow("USD:1"), - granted: Amounts.parseOrThrow("USD:0"), + // awaitingAmount: Amounts.parseOrThrow("USD:1"), + // granted: Amounts.parseOrThrow("USD:0"), merchantName: "the merchant", products: [ { diff --git a/packages/taler-wallet-webextension/src/cta/Refund/test.ts b/packages/taler-wallet-webextension/src/cta/Refund/test.ts index a2e48f76d..1566b3b5b 100644 --- a/packages/taler-wallet-webextension/src/cta/Refund/test.ts +++ b/packages/taler-wallet-webextension/src/cta/Refund/test.ts @@ -31,251 +31,257 @@ import { nullFunction } from "../../mui/handlers.js"; import { createWalletApiMock } from "../../test-utils.js"; import { useComponentState } from "./state.js"; -describe("Refund CTA states", () => { - it("should tell the user that the URI is missing", async () => { - const { handler, TestingContext } = createWalletApiMock(); - - const props = { - talerRefundUri: undefined, - cancel: 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(); - // if (!error.hasError) expect.fail(); - // if (error.operational) expect.fail(); - expect(error.description).eq("ERROR_NO-URI-FOR-REFUND"); - }, - ], - TestingContext, - ); - - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); - - it("should be ready after loading", async () => { - const { handler, TestingContext } = createWalletApiMock(); - const props = { - talerRefundUri: "taler://refund/asdasdas", - cancel: nullFunction, - onSuccess: nullFunction, - }; - - handler.addWalletCallResponse(WalletApiOperation.StartRefundQueryForUri, undefined, { - awaiting: "EUR:2", - effectivePaid: "EUR:2", - gone: "EUR:0", - granted: "EUR:0", - pending: false, - proposalId: "1", - info: { - contractTermsHash: "123", - merchant: { - name: "the merchant name", - }, - orderId: "orderId1", - summary: "the summary", - } as OrderShortInfo, - }); - - 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.accept.onClick).not.undefined; - expect(state.ignore.onClick).not.undefined; - expect(state.merchantName).eq("the merchant name"); - expect(state.orderId).eq("orderId1"); - expect(state.products).undefined; - }, - ], - TestingContext, - ); - - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); - - it("should be ignored after clicking the ignore button", async () => { - const { handler, TestingContext } = createWalletApiMock(); - const props = { - talerRefundUri: "taler://refund/asdasdas", - cancel: async () => { - null; - }, - onSuccess: async () => { - null; - }, - }; - - handler.addWalletCallResponse(WalletApiOperation.StartRefundQueryForUri, undefined, { - awaiting: "EUR:2", - effectivePaid: "EUR:2", - gone: "EUR:0", - granted: "EUR:0", - pending: false, - proposalId: "1", - info: { - contractTermsHash: "123", - merchant: { - name: "the merchant name", - }, - orderId: "orderId1", - summary: "the summary", - } as OrderShortInfo, - }); - - 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.accept.onClick).not.undefined; - expect(state.merchantName).eq("the merchant name"); - expect(state.orderId).eq("orderId1"); - expect(state.products).undefined; - - if (state.ignore.onClick === undefined) expect.fail(); - state.ignore.onClick(); - }, - (state) => { - if (state.status !== "ignored") expect.fail(); - if (state.error) expect.fail(); - expect(state.merchantName).eq("the merchant name"); - }, - ], - TestingContext, - ); - - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); - - it("should be in progress when doing refresh", async () => { - const { handler, TestingContext } = createWalletApiMock(); - const props = { - talerRefundUri: "taler://refund/asdasdas", - cancel: async () => { - null; - }, - onSuccess: async () => { - null; - }, - }; - - handler.addWalletCallResponse(WalletApiOperation.StartRefundQueryForUri, undefined, { - awaiting: "EUR:2", - effectivePaid: "EUR:2", - gone: "EUR:0", - granted: "EUR:0", - pending: true, - proposalId: "1", - info: { - contractTermsHash: "123", - merchant: { - name: "the merchant name", - }, - orderId: "orderId1", - summary: "the summary", - } as OrderShortInfo, - }); - handler.addWalletCallResponse(WalletApiOperation.StartRefundQueryForUri, undefined, { - awaiting: "EUR:1", - effectivePaid: "EUR:2", - gone: "EUR:0", - granted: "EUR:1", - pending: true, - proposalId: "1", - info: { - contractTermsHash: "123", - merchant: { - name: "the merchant name", - }, - orderId: "orderId1", - summary: "the summary", - } as OrderShortInfo, - }); - handler.addWalletCallResponse(WalletApiOperation.StartRefundQueryForUri, undefined, { - awaiting: "EUR:0", - effectivePaid: "EUR:2", - gone: "EUR:0", - granted: "EUR:2", - pending: false, - proposalId: "1", - info: { - contractTermsHash: "123", - merchant: { - name: "the merchant name", - }, - orderId: "orderId1", - summary: "the summary", - } as OrderShortInfo, - }); - - const hookBehavior = await tests.hookBehaveLikeThis( - useComponentState, - props, - [ - ({ status, error }) => { - expect(status).equals("loading"); - expect(error).undefined; - }, - (state) => { - if (state.status !== "in-progress") expect.fail(); - if (state.error) expect.fail(); - expect(state.merchantName).eq("the merchant name"); - expect(state.products).undefined; - expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2")); - // expect(state.progress).closeTo(1 / 3, 0.01) - - handler.notifyEventFromWallet(NotificationType.RefreshMelted); - }, - (state) => { - if (state.status !== "in-progress") expect.fail(); - if (state.error) expect.fail(); - expect(state.merchantName).eq("the merchant name"); - expect(state.products).undefined; - expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2")); - // expect(state.progress).closeTo(2 / 3, 0.01) - - handler.notifyEventFromWallet(NotificationType.RefreshMelted); - }, - (state) => { - if (state.status !== "ready") expect.fail(); - if (state.error) expect.fail(); - expect(state.merchantName).eq("the merchant name"); - expect(state.products).undefined; - expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2")); - }, - ], - TestingContext, - ); +/** + * Commenting this tests out since the behavior + */ - expect(hookBehavior).deep.equal({ result: "ok" }); - expect(handler.getCallingQueueState()).eq("empty"); - }); +describe("Refund CTA states", () => { + // it("should tell the user that the URI is missing", async () => { + // const { handler, TestingContext } = createWalletApiMock(); + // const props = { + // talerRefundUri: undefined, + // cancel: 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(); + // // if (!error.hasError) expect.fail(); + // // if (error.operational) expect.fail(); + // expect(error.description).eq("ERROR_NO-URI-FOR-REFUND"); + // }, + // ], + // TestingContext, + // ); + // expect(hookBehavior).deep.equal({ result: "ok" }); + // expect(handler.getCallingQueueState()).eq("empty"); + // }); + // it("should be ready after loading", async () => { + // const { handler, TestingContext } = createWalletApiMock(); + // const props = { + // talerRefundUri: "taler://refund/asdasdas", + // cancel: nullFunction, + // onSuccess: nullFunction, + // }; + // handler.addWalletCallResponse( + // WalletApiOperation.StartRefundQueryForUri, + // undefined, + // { + // // awaiting: "EUR:2", + // // effectivePaid: "EUR:2", + // // gone: "EUR:0", + // // granted: "EUR:0", + // // pending: false, + // // proposalId: "1", + // // info: { + // // contractTermsHash: "123", + // // merchant: { + // // name: "the merchant name", + // // }, + // // orderId: "orderId1", + // // summary: "the summary", + // // } as OrderShortInfo, + // }, + // ); + // 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.accept.onClick).not.undefined; + // expect(state.ignore.onClick).not.undefined; + // expect(state.merchantName).eq("the merchant name"); + // expect(state.orderId).eq("orderId1"); + // expect(state.products).undefined; + // }, + // ], + // TestingContext, + // ); + // expect(hookBehavior).deep.equal({ result: "ok" }); + // expect(handler.getCallingQueueState()).eq("empty"); + // }); + // it("should be ignored after clicking the ignore button", async () => { + // const { handler, TestingContext } = createWalletApiMock(); + // const props = { + // talerRefundUri: "taler://refund/asdasdas", + // cancel: async () => { + // null; + // }, + // onSuccess: async () => { + // null; + // }, + // }; + // handler.addWalletCallResponse( + // WalletApiOperation.StartRefundQueryForUri, + // undefined, + // { + // // awaiting: "EUR:2", + // // effectivePaid: "EUR:2", + // // gone: "EUR:0", + // // granted: "EUR:0", + // // pending: false, + // // proposalId: "1", + // // info: { + // // contractTermsHash: "123", + // // merchant: { + // // name: "the merchant name", + // // }, + // // orderId: "orderId1", + // // summary: "the summary", + // // } as OrderShortInfo, + // }, + // ); + // 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.accept.onClick).not.undefined; + // expect(state.merchantName).eq("the merchant name"); + // expect(state.orderId).eq("orderId1"); + // expect(state.products).undefined; + // if (state.ignore.onClick === undefined) expect.fail(); + // state.ignore.onClick(); + // }, + // (state) => { + // if (state.status !== "ignored") expect.fail(); + // if (state.error) expect.fail(); + // expect(state.merchantName).eq("the merchant name"); + // }, + // ], + // TestingContext, + // ); + // expect(hookBehavior).deep.equal({ result: "ok" }); + // expect(handler.getCallingQueueState()).eq("empty"); + // }); + // it("should be in progress when doing refresh", async () => { + // const { handler, TestingContext } = createWalletApiMock(); + // const props = { + // talerRefundUri: "taler://refund/asdasdas", + // cancel: async () => { + // null; + // }, + // onSuccess: async () => { + // null; + // }, + // }; + // handler.addWalletCallResponse( + // WalletApiOperation.StartRefundQueryForUri, + // undefined, + // { + // // awaiting: "EUR:2", + // // effectivePaid: "EUR:2", + // // gone: "EUR:0", + // // granted: "EUR:0", + // // pending: true, + // // proposalId: "1", + // // info: { + // // contractTermsHash: "123", + // // merchant: { + // // name: "the merchant name", + // // }, + // // orderId: "orderId1", + // // summary: "the summary", + // // } as OrderShortInfo, + // }, + // ); + // handler.addWalletCallResponse( + // WalletApiOperation.StartRefundQueryForUri, + // undefined, + // { + // // awaiting: "EUR:1", + // // effectivePaid: "EUR:2", + // // gone: "EUR:0", + // // granted: "EUR:1", + // // pending: true, + // // proposalId: "1", + // // info: { + // // contractTermsHash: "123", + // // merchant: { + // // name: "the merchant name", + // // }, + // // orderId: "orderId1", + // // summary: "the summary", + // // } as OrderShortInfo, + // }, + // ); + // handler.addWalletCallResponse( + // WalletApiOperation.StartRefundQueryForUri, + // undefined, + // { + // // awaiting: "EUR:0", + // // effectivePaid: "EUR:2", + // // gone: "EUR:0", + // // granted: "EUR:2", + // // pending: false, + // // proposalId: "1", + // // info: { + // // contractTermsHash: "123", + // // merchant: { + // // name: "the merchant name", + // // }, + // // orderId: "orderId1", + // // summary: "the summary", + // // } as OrderShortInfo, + // }, + // ); + // const hookBehavior = await tests.hookBehaveLikeThis( + // useComponentState, + // props, + // [ + // ({ status, error }) => { + // expect(status).equals("loading"); + // expect(error).undefined; + // }, + // (state) => { + // if (state.status !== "in-progress") expect.fail(); + // if (state.error) expect.fail(); + // expect(state.merchantName).eq("the merchant name"); + // expect(state.products).undefined; + // expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2")); + // // expect(state.progress).closeTo(1 / 3, 0.01) + // handler.notifyEventFromWallet(NotificationType.RefreshMelted); + // }, + // (state) => { + // if (state.status !== "in-progress") expect.fail(); + // if (state.error) expect.fail(); + // expect(state.merchantName).eq("the merchant name"); + // expect(state.products).undefined; + // expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2")); + // // expect(state.progress).closeTo(2 / 3, 0.01) + // handler.notifyEventFromWallet(NotificationType.RefreshMelted); + // }, + // (state) => { + // if (state.status !== "ready") expect.fail(); + // if (state.error) expect.fail(); + // expect(state.merchantName).eq("the merchant name"); + // expect(state.products).undefined; + // expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2")); + // }, + // ], + // TestingContext, + // ); + // expect(hookBehavior).deep.equal({ result: "ok" }); + // expect(handler.getCallingQueueState()).eq("empty"); + // }); }); diff --git a/packages/taler-wallet-webextension/src/cta/Refund/views.tsx b/packages/taler-wallet-webextension/src/cta/Refund/views.tsx index 8f69056de..accdab0c3 100644 --- a/packages/taler-wallet-webextension/src/cta/Refund/views.tsx +++ b/packages/taler-wallet-webextension/src/cta/Refund/views.tsx @@ -38,38 +38,38 @@ export function IgnoredView(state: State.Ignored): VNode { </Fragment> ); } -export function InProgressView(state: State.InProgress): VNode { - const { i18n } = useTranslationContext(); +// export function InProgressView(state: State.InProgress): VNode { +// const { i18n } = useTranslationContext(); - return ( - <Fragment> - <section> - <p> - <i18n.Translate>The refund is in progress.</i18n.Translate> - </p> - </section> - <section> - <Part - big - title={i18n.str`Total to refund`} - text={<Amount value={state.awaitingAmount} />} - kind="negative" - /> - <Part - big - title={i18n.str`Refunded`} - text={<Amount value={state.amount} />} - kind="negative" - /> - </section> - {state.products && state.products.length ? ( - <section> - <ProductList products={state.products} /> - </section> - ) : undefined} - </Fragment> - ); -} +// return ( +// <Fragment> +// <section> +// <p> +// <i18n.Translate>The refund is in progress.</i18n.Translate> +// </p> +// </section> +// <section> +// <Part +// big +// title={i18n.str`Total to refund`} +// text={<Amount value={state.awaitingAmount} />} +// kind="negative" +// /> +// <Part +// big +// title={i18n.str`Refunded`} +// text={<Amount value={state.amount} />} +// kind="negative" +// /> +// </section> +// {state.products && state.products.length ? ( +// <section> +// <ProductList products={state.products} /> +// </section> +// ) : undefined} +// </Fragment> +// ); +// } export function ReadyView(state: State.Ready): VNode { const { i18n } = useTranslationContext(); return ( @@ -89,7 +89,7 @@ export function ReadyView(state: State.Ready): VNode { text={<Amount value={state.amount} />} kind="neutral" /> - {Amounts.isNonZero(state.granted) && ( + {/* {Amounts.isNonZero(state.granted) && ( <Part big title={i18n.str`Already refunded`} @@ -102,7 +102,7 @@ export function ReadyView(state: State.Ready): VNode { title={i18n.str`Refund offered (without fee)`} text={<Amount value={state.awaitingAmount} />} kind="positive" - /> + /> */} </section> {state.products && state.products.length ? ( <section> @@ -116,7 +116,8 @@ export function ReadyView(state: State.Ready): VNode { onClick={state.accept.onClick} > <i18n.Translate> - Accept <Amount value={state.awaitingAmount} /> + {/* Accept <Amount value={state.awaitingAmount} /> */} + Accept </i18n.Translate> </Button> </section> diff --git a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx index d27224a77..1c5ba61c3 100644 --- a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx @@ -26,6 +26,7 @@ import { TalerProtocolTimestamp, TransactionCommon, TransactionDeposit, + TransactionMajorState, TransactionPayment, TransactionPeerPullCredit, TransactionPeerPullDebit, @@ -52,6 +53,9 @@ const commonTransaction = (): TransactionCommon => amountRaw: "USD:10", amountEffective: "USD:9", pending: false, + txState: { + major: TransactionMajorState.Done, + }, timestamp: TalerProtocolTimestamp.fromSeconds( new Date().getTime() / 1000 - count++ * 60 * 60 * 7, ), @@ -237,7 +241,9 @@ export const OneTransactionPending = tests.createExample(TestedComponent, { transactions: [ { ...exampleData.withdraw, - pending: true, + txState: { + major: TransactionMajorState.Pending, + }, }, ], balances: [ diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx index 71f8cfe1a..78b741b51 100644 --- a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx @@ -21,7 +21,6 @@ import { AbsoluteTime, - ExtendedStatus, PaymentStatus, RefreshReason, TalerProtocolTimestamp, @@ -56,19 +55,20 @@ export default { }, }; -const commonTransaction = { +const commonTransaction: TransactionCommon = { + error: undefined, amountRaw: "KUDOS:11", amountEffective: "KUDOS:9.2", - extendedStatus: ExtendedStatus.Done, - pending: undefined as any as boolean, //deprecated + txState: { + major: TransactionMajorState.Done, + }, timestamp: TalerProtocolTimestamp.now(), transactionId: "txn:deposit:12", - frozen: undefined as any as boolean, //deprecated type: TransactionType.Deposit, - txState: { - major: TransactionMajorState.Unknown, - }, -} as TransactionCommon; +} as Omit< + Omit<Omit<TransactionCommon, "extendedStatus">, "frozen">, + "pending" +> as TransactionCommon; import merchantIcon from "../../static-dev/merchant-icon.jpeg"; @@ -262,7 +262,9 @@ export const WithdrawFiveMinutesAgoAndPending = tests.createExample( timestamp: TalerProtocolTimestamp.fromSeconds( new Date().getTime() / 1000 - 60 * 5, ), - extendedStatus: ExtendedStatus.Pending, + txState: { + major: TransactionMajorState.Pending, + }, }, }), ); @@ -302,7 +304,9 @@ export const WithdrawPendingManual = tests.createExample( exchangePaytoUris: ["payto://iban/ES8877998399652238"], reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG", } as WithdrawalDetails, - extendedStatus: ExtendedStatus.Pending, + txState: { + major: TransactionMajorState.Pending, + }, }, }), ); @@ -319,7 +323,9 @@ export const WithdrawPendingTalerBankUnconfirmed = tests.createExample( reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG", bankConfirmationUrl: "http://bank.demo.taler.net", }, - extendedStatus: ExtendedStatus.Pending, + txState: { + major: TransactionMajorState.Pending, + }, }, }, ); @@ -335,7 +341,9 @@ export const WithdrawPendingTalerBankConfirmed = tests.createExample( reserveIsReady: false, reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG", }, - extendedStatus: ExtendedStatus.Pending, + txState: { + major: TransactionMajorState.Pending, + }, }, }, ); @@ -461,7 +469,9 @@ export const PaymentWithoutFee = tests.createExample(TestedComponent, { export const PaymentPending = tests.createExample(TestedComponent, { transaction: { ...exampleData.payment, - extendedStatus: ExtendedStatus.Pending, + txState: { + major: TransactionMajorState.Pending, + }, }, }); @@ -561,7 +571,9 @@ export const DepositError = tests.createExample(TestedComponent, { export const DepositPending = tests.createExample(TestedComponent, { transaction: { ...exampleData.deposit, - extendedStatus: ExtendedStatus.Pending, + txState: { + major: TransactionMajorState.Pending, + }, }, }); @@ -588,7 +600,12 @@ export const TipError = tests.createExample(TestedComponent, { }); export const TipPending = tests.createExample(TestedComponent, { - transaction: { ...exampleData.tip, extendedStatus: ExtendedStatus.Pending }, + transaction: { + ...exampleData.tip, + txState: { + major: TransactionMajorState.Pending, + }, + }, }); export const Refund = tests.createExample(TestedComponent, { @@ -605,7 +622,9 @@ export const RefundError = tests.createExample(TestedComponent, { export const RefundPending = tests.createExample(TestedComponent, { transaction: { ...exampleData.refund, - extendedStatus: ExtendedStatus.Pending, + txState: { + major: TransactionMajorState.Pending, + }, }, }); @@ -616,7 +635,9 @@ export const InvoiceCreditComplete = tests.createExample(TestedComponent, { export const InvoiceCreditIncomplete = tests.createExample(TestedComponent, { transaction: { ...exampleData.pull_credit, - extendedStatus: ExtendedStatus.Pending, + txState: { + major: TransactionMajorState.Pending, + }, }, }); @@ -634,6 +655,8 @@ export const TransferDebitComplete = tests.createExample(TestedComponent, { export const TransferDebitIncomplete = tests.createExample(TestedComponent, { transaction: { ...exampleData.push_debit, - extendedStatus: ExtendedStatus.Pending, + txState: { + major: TransactionMajorState.Pending, + }, }, }); diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx index 8c2839324..cd240ffea 100644 --- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx @@ -18,7 +18,6 @@ import { AbsoluteTime, AmountJson, Amounts, - ExtendedStatus, Location, MerchantInfo, NotificationType, @@ -29,6 +28,7 @@ import { TalerProtocolTimestamp, Transaction, TransactionDeposit, + TransactionMajorState, TransactionType, TranslatedString, WithdrawalType, @@ -136,9 +136,9 @@ export function TransactionPage({ }); goToWalletHistory(currency); }} - onRefund={async (purchaseId) => { - await api.wallet.call(WalletApiOperation.ApplyRefundFromPurchaseId, { - purchaseId, + onRefund={async (transactionId) => { + await api.wallet.call(WalletApiOperation.StartRefundQuery, { + transactionId, }); }} onBack={() => goToWalletHistory(currency)} @@ -186,7 +186,7 @@ function TransactionTemplate({ async function doCheckBeforeForget(): Promise<void> { if ( - transaction.extendedStatus === ExtendedStatus.Pending && + transaction.txState.major === TransactionMajorState.Pending && transaction.type === TransactionType.Withdrawal ) { setConfirmBeforeForget(true); @@ -206,16 +206,16 @@ function TransactionTemplate({ transaction.type === TransactionType.Payment; const transactionStillActive = - transaction.extendedStatus !== ExtendedStatus.Aborted && - transaction.extendedStatus !== ExtendedStatus.Done && - transaction.extendedStatus !== ExtendedStatus.Failed; + transaction.txState.major !== TransactionMajorState.Aborted && + transaction.txState.major !== TransactionMajorState.Done && + transaction.txState.major !== TransactionMajorState.Failed; // show retry if there is an error in an active state, or after some time // if it is not aborting const showRetry = transactionStillActive && (transaction.error !== undefined || - (transaction.extendedStatus !== ExtendedStatus.Aborting && + (transaction.txState.major === TransactionMajorState.Aborting && (transaction.timestamp.t_s === "never" || differenceInSeconds(new Date(), transaction.timestamp.t_s * 1000) > SHOWING_RETRY_THRESHOLD_SECS))); @@ -252,7 +252,7 @@ function TransactionTemplate({ /> ) ) : undefined} - {transaction.extendedStatus === ExtendedStatus.Pending && ( + {transaction.txState.major === TransactionMajorState.Pending && ( <WarningBox> <i18n.Translate>This transaction is not completed</i18n.Translate> </WarningBox> @@ -417,9 +417,10 @@ export function TransactionView({ {transaction.exchangeBaseUrl} </Header> - {transaction.extendedStatus !== - ExtendedStatus.Pending ? undefined : transaction.withdrawalDetails - .type === WithdrawalType.ManualTransfer ? ( + {/**FIXME: DD37 check if this holds */} + {transaction.txState.major === + TransactionMajorState.Pending ? undefined : transaction + .withdrawalDetails.type === WithdrawalType.ManualTransfer ? ( //manual withdrawal <Fragment> <BankDetailsByPaytoType @@ -822,12 +823,12 @@ export function TransactionView({ total={effective} kind="positive" > - {transaction.info.summary} + {"transaction.info.summary"} </Header> <Part title={i18n.str`Merchant`} - text={transaction.info.merchant.name as TranslatedString} + text={"transaction.info.merchant.name" as TranslatedString} kind="neutral" /> <Part @@ -838,14 +839,14 @@ export function TransactionView({ tid: transaction.refundedTransactionId, })} > - {transaction.info.orderId} + {"transaction.info.orderId"} </a> } kind="neutral" /> <Part title={i18n.str`Purchase summary`} - text={transaction.info.summary as TranslatedString} + text={"transaction.info.summary" as TranslatedString} kind="neutral" /> <Part @@ -890,8 +891,7 @@ export function TransactionView({ text={transaction.exchangeBaseUrl as TranslatedString} kind="neutral" /> - {transaction.extendedStatus === - ExtendedStatus.Pending /** pending is not-pay */ && + {transaction.txState.major === TransactionMajorState.Pending && !transaction.error && ( <Part title={i18n.str`URI`} |