summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/cta
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-01-15 17:34:19 -0300
committerSebastian <sebasjm@gmail.com>2024-01-15 17:36:48 -0300
commit2e2cf4049a771c82fcc520686de3ace7603baa05 (patch)
tree620ab22d4fc0f621d0a574c8f98d1c49f1d67804 /packages/taler-wallet-webextension/src/cta
parentef0bb60f23c0c755814f648b8d71a29a843e066c (diff)
downloadwallet-core-2e2cf4049a771c82fcc520686de3ace7603baa05.tar.gz
wallet-core-2e2cf4049a771c82fcc520686de3ace7603baa05.tar.bz2
wallet-core-2e2cf4049a771c82fcc520686de3ace7603baa05.zip
fixes #8083
Diffstat (limited to 'packages/taler-wallet-webextension/src/cta')
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw/index.ts10
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw/state.ts49
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx19
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw/test.ts22
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx29
5 files changed, 120 insertions, 9 deletions
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
index 04713f3c4..1f8745a5d 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
@@ -38,7 +38,7 @@ import { ErrorAlertView } from "../../components/CurrentAlerts.js";
import { ErrorAlert } from "../../context/alert.js";
import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js";
import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
-import { SelectAmountView, SuccessView } from "./views.js";
+import { FinalStateOperation, SelectAmountView, SuccessView } from "./views.js";
export interface PropsFromURI {
talerWithdrawUri: string | undefined;
@@ -60,6 +60,7 @@ export type State =
| SelectExchangeState.NoExchangeFound
| SelectExchangeState.Selecting
| State.SelectAmount
+ | State.AlreadyCompleted
| State.Success;
export namespace State {
@@ -80,6 +81,12 @@ export namespace State {
amount: AmountFieldHandler;
currency: string;
}
+ export interface AlreadyCompleted {
+ status: "already-completed";
+ operationState: "confirmed" | "aborted" | "selected";
+ confirmTransferUrl?: string,
+ error: undefined;
+ }
export type Success = {
status: "success";
@@ -116,6 +123,7 @@ const viewMapping: StateViewMap<State> = {
"no-exchange-found": NoExchangesView,
"selecting-exchange": ExchangeSelectionPage,
success: SuccessView,
+ "already-completed": FinalStateOperation,
};
export const WithdrawPageFromURI = compose(
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
index 7bff13e51..bf460834d 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
@@ -21,11 +21,12 @@ import {
ExchangeFullDetails,
ExchangeListItem,
ExchangeTosStatus,
+ NotificationType,
TalerError,
parseWithdrawExchangeUri,
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
-import { useEffect, useState } from "preact/hooks";
+import { useEffect, useState, useMemo, useCallback } from "preact/hooks";
import { alertFromError, useAlertContext } from "../../context/alert.js";
import { useBackendContext } from "../../context/backend.js";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
@@ -208,17 +209,40 @@ export function useComponentStateFromURI({
WalletApiOperation.GetWithdrawalDetailsForUri,
{
talerWithdrawUri,
+ notifyChangeFromPendingTimeoutMs: 30 * 1000
},
);
- const { amount, defaultExchangeBaseUrl, possibleExchanges } = uriInfo;
+ const { amount, defaultExchangeBaseUrl, possibleExchanges, operationId, confirmTransferUrl, status } = uriInfo;
+ const transaction = await api.wallet.call(
+ WalletApiOperation.GetWithdrawalTransactionByUri,
+ { talerWithdrawUri },
+ );
return {
talerWithdrawUri,
+ operationId,
+ status,
+ transaction,
+ confirmTransferUrl,
amount: Amounts.parseOrThrow(amount),
thisExchange: defaultExchangeBaseUrl,
exchanges: possibleExchanges,
};
});
+ const readyToListen = uriInfoHook && !uriInfoHook.hasError
+
+ useEffect(() => {
+ if (!uriInfoHook) {
+ return;
+ }
+ return api.listener.onUpdateNotification(
+ [NotificationType.WithdrawalOperationTransition],
+ () => {
+ uriInfoHook.retry()
+ },
+ );
+ }, [readyToListen]);
+
if (!uriInfoHook) return { status: "loading", error: undefined };
if (uriInfoHook.hasError) {
@@ -257,8 +281,20 @@ export function useComponentStateFromURI({
};
}
- return () =>
- exchangeSelectionState(
+ if (uriInfoHook.response.status !== "pending") {
+ if (uriInfoHook.response.transaction) {
+ onSuccess(uriInfoHook.response.transaction.transactionId)
+ }
+ return {
+ status: "already-completed",
+ operationState: uriInfoHook.response.status,
+ confirmTransferUrl: uriInfoHook.response.confirmTransferUrl,
+ error: undefined,
+ }
+ }
+
+ return useCallback(() => {
+ return exchangeSelectionState(
doManagedWithdraw,
cancel,
onSuccess,
@@ -267,6 +303,7 @@ export function useComponentStateFromURI({
exchangeList,
defaultExchange,
);
+ }, [])
}
type ManualOrManagedWithdrawFunction = (
@@ -294,7 +331,7 @@ function exchangeSelectionState(
return selectedExchange;
}
- return (): State.Success | State.LoadingUriError | State.Loading => {
+ return useCallback((): State.Success | State.LoadingUriError | State.Loading => {
const { i18n } = useTranslationContext();
const { pushAlertOnError } = useAlertContext();
const [ageRestricted, setAgeRestricted] = useState(0);
@@ -428,5 +465,5 @@ function exchangeSelectionState(
},
cancel,
};
- };
+ }, []);
}
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx
index a3127fafc..29f39054f 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx
@@ -23,7 +23,7 @@ import { CurrencySpecification, ExchangeListItem } from "@gnu-taler/taler-util";
import * as tests from "@gnu-taler/web-util/testing";
import { nullFunction } from "../../mui/handlers.js";
// import { TermsState } from "../../utils/index.js";
-import { SuccessView } from "./views.js";
+import { SuccessView, FinalStateOperation } from "./views.js";
export default {
title: "withdraw",
@@ -67,6 +67,23 @@ export const TermsOfServiceNotYetLoaded = tests.createExample(SuccessView, {
chooseCurrencies: [],
});
+export const AlreadyAborted = tests.createExample(FinalStateOperation, {
+ error: undefined,
+ status: "already-completed",
+ operationState: "aborted"
+});
+export const AlreadySelected = tests.createExample(FinalStateOperation, {
+ error: undefined,
+ status: "already-completed",
+ operationState: "selected"
+});
+export const AlreadyConfirmed = tests.createExample(FinalStateOperation, {
+ error: undefined,
+ status: "already-completed",
+ operationState: "confirmed"
+});
+
+
export const WithSomeFee = tests.createExample(SuccessView, {
error: undefined,
status: "success",
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
index 3493415d9..f90f7bed7 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
@@ -111,10 +111,19 @@ describe("Withdraw CTA states", () => {
WalletApiOperation.GetWithdrawalDetailsForUri,
undefined,
{
+ status: "pending",
+ operationId: "123",
amount: "EUR:2" as AmountString,
possibleExchanges: [],
},
);
+ handler.addWalletCallResponse(
+ WalletApiOperation.GetWithdrawalTransactionByUri,
+ undefined,
+ {
+ transactionId: "123"
+ } as any,
+ );
const hookBehavior = await tests.hookBehaveLikeThis(
useComponentStateFromURI,
@@ -147,12 +156,21 @@ describe("Withdraw CTA states", () => {
WalletApiOperation.GetWithdrawalDetailsForUri,
undefined,
{
+ status: "pending",
+ operationId: "123",
amount: "ARS:2" as AmountString,
possibleExchanges: exchanges,
defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl,
},
);
handler.addWalletCallResponse(
+ WalletApiOperation.GetWithdrawalTransactionByUri,
+ undefined,
+ {
+ transactionId: "123"
+ } as any,
+ );
+ handler.addWalletCallResponse(
WalletApiOperation.GetWithdrawalDetailsForAmount,
undefined,
{
@@ -217,6 +235,8 @@ describe("Withdraw CTA states", () => {
WalletApiOperation.GetWithdrawalDetailsForUri,
undefined,
{
+ status: "pending",
+ operationId: "123",
amount: "ARS:2" as AmountString,
possibleExchanges: exchangeWithNewTos,
defaultExchangeBaseUrl: exchangeWithNewTos[0].exchangeBaseUrl,
@@ -245,6 +265,8 @@ describe("Withdraw CTA states", () => {
WalletApiOperation.GetWithdrawalDetailsForUri,
undefined,
{
+ status: "pending",
+ operationId: "123",
amount: "ARS:2" as AmountString,
possibleExchanges: exchanges,
defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl,
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
index 748b65817..bd9f75696 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
@@ -21,7 +21,7 @@ import { Amount } from "../../components/Amount.js";
import { Part } from "../../components/Part.js";
import { QR } from "../../components/QR.js";
import { SelectList } from "../../components/SelectList.js";
-import { Input, LinkSuccess, SvgIcon } from "../../components/styled/index.js";
+import { Input, LinkSuccess, SvgIcon, WarningBox } from "../../components/styled/index.js";
import { TermsOfService } from "../../components/TermsOfService/index.js";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { Button } from "../../mui/Button.js";
@@ -35,6 +35,33 @@ import { State } from "./index.js";
import { Grid } from "../../mui/Grid.js";
import { AmountField } from "../../components/AmountField.js";
+export function FinalStateOperation(state: State.AlreadyCompleted): VNode {
+ const { i18n } = useTranslationContext();
+
+ switch (state.operationState) {
+ case "confirmed": return <WarningBox>
+ <div style={{ justifyContent: "center", lineHeight: "25px" }}>
+ <i18n.Translate>This operation has already been completed by another wallet.</i18n.Translate>
+ </div>
+ </WarningBox>
+ case "aborted": return <WarningBox>
+ <div style={{ justifyContent: "center", lineHeight: "25px" }}>
+ <i18n.Translate>This operation has already been aborted</i18n.Translate>
+ </div>
+ </WarningBox>
+ case "selected": return <WarningBox>
+ <div style={{ justifyContent: "center", lineHeight: "25px" }}>
+ <i18n.Translate>This operation has already been used by another wallet.</i18n.Translate>
+ </div>
+ <div style={{ justifyContent: "center", lineHeight: "25px" }}>
+ <i18n.Translate>It can be confirmed in</i18n.Translate>&nbsp;<a target="_bank" rel="noreferrer" href={state.confirmTransferUrl}>
+ <i18n.Translate>this page</i18n.Translate>
+ </a>
+ </div>
+ </WarningBox>
+ }
+}
+
export function SuccessView(state: State.Success): VNode {
const { i18n } = useTranslationContext();
// const currentTosVersionIsAccepted =