From 52ec740c825d4e94fd59ef0a5cd8e8b73f4dfc06 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 20 Sep 2022 16:04:51 -0300 Subject: new compose feature: sub-states implemented in withdraw page, WIP --- .../src/cta/InvoiceCreate/index.ts | 1 + .../src/cta/InvoiceCreate/state.ts | 3 + .../src/cta/InvoiceCreate/stories.tsx | 3 + .../src/cta/InvoiceCreate/views.tsx | 5 +- .../src/cta/Payment/state.ts | 1 + .../src/cta/Withdraw/index.ts | 18 +- .../src/cta/Withdraw/state.ts | 555 ++++++++------------- .../src/cta/Withdraw/stories.tsx | 12 + .../src/cta/Withdraw/test.ts | 29 +- .../src/cta/Withdraw/views.tsx | 14 +- 10 files changed, 256 insertions(+), 385 deletions(-) (limited to 'packages/taler-wallet-webextension/src/cta') diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts index 8beac2cb2..2bee51669 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts @@ -48,6 +48,7 @@ export namespace State { } export interface Ready extends BaseInfo { status: "ready"; + doSelectExchange: ButtonHandler; create: ButtonHandler; subject: TextFieldHandler; toBeReceived: AmountJson; diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts index 6b4f54504..9b67b4414 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts @@ -84,6 +84,9 @@ export function useComponentState( value: subject, onInput: async (e) => setSubject(e), }, + doSelectExchange: { + //FIX + }, invalid: !subject || Amounts.isZero(amount), exchangeUrl: selected.exchangeBaseUrl, create: { diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx index b5a0a52e2..306d1b199 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx @@ -37,6 +37,9 @@ export const Ready = createExample(ReadyView, { currency: "ARS", value: 1, fraction: 0, + }, + doSelectExchange: { + }, exchangeUrl: "https://exchange.taler.ar", subject: { diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx index 209fb31e5..603392b60 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx @@ -54,6 +54,7 @@ export function ReadyView({ create, toBeReceived, chosenAmount, + doSelectExchange, }: State.Ready): VNode { const { i18n } = useTranslationContext(); @@ -93,13 +94,13 @@ export function ReadyView({ }} > Exchange - {/* + } text={} diff --git a/packages/taler-wallet-webextension/src/cta/Payment/state.ts b/packages/taler-wallet-webextension/src/cta/Payment/state.ts index e8690be39..8d388aa60 100644 --- a/packages/taler-wallet-webextension/src/cta/Payment/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Payment/state.ts @@ -128,6 +128,7 @@ export function useComponentState( }); } const res = await api.confirmPay(payStatus.proposalId, undefined); + // handle confirm pay if (res.type !== ConfirmPayResultType.Done) { throw TalerError.fromUncheckedDetail({ code: TalerErrorCode.GENERIC_CLIENT_INTERNAL_ERROR, diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts index 2d9aaf828..d38c27a2f 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts @@ -25,12 +25,17 @@ import { useComponentStateFromParams, useComponentStateFromURI, } from "./state.js"; +import { + State as SelectExchangeState +} from "../../hooks/useSelectedExchange.js"; + import { LoadingExchangeView, LoadingInfoView, LoadingUriView, SuccessView, } from "./views.js"; +import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js"; export interface PropsFromURI { talerWithdrawUri: string | undefined; @@ -49,6 +54,7 @@ export type State = | State.LoadingUriError | State.LoadingExchangeError | State.LoadingInfoError + | SelectExchangeState.Selecting | State.Success; export namespace State { @@ -57,12 +63,12 @@ export namespace State { error: undefined; } export interface LoadingUriError { - status: "loading-uri"; + status: "loading-error"; error: HookError; } export interface LoadingExchangeError { - status: "loading-exchange"; - error: HookError; + status: "no-exchange"; + error: undefined, } export interface LoadingInfoError { status: "loading-info"; @@ -80,6 +86,7 @@ export namespace State { toBeReceived: AmountJson; doWithdrawal: ButtonHandler; + doSelectExchange: ButtonHandler; tosProps?: TermsOfServiceSectionProps; mustAcceptFirst: boolean; @@ -92,9 +99,10 @@ export namespace State { const viewMapping: StateViewMap = { loading: Loading, - "loading-uri": LoadingUriView, - "loading-exchange": LoadingExchangeView, + "loading-error": LoadingUriView, + "no-exchange": LoadingExchangeView, "loading-info": LoadingInfoView, + "selecting-exchange": ExchangeSelectionPage, success: SuccessView, }; diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts index 1256bf469..2e68d056e 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts @@ -14,223 +14,58 @@ GNU Taler; see the file COPYING. If not, see */ -import { Amounts, parsePaytoUri } from "@gnu-taler/taler-util"; +/* eslint-disable react-hooks/rules-of-hooks */ +import { AmountJson, Amounts, ExchangeListItem, parsePaytoUri } from "@gnu-taler/taler-util"; import { TalerError } from "@gnu-taler/taler-wallet-core"; import { useState } from "preact/hooks"; +import { Amount } from "../../components/Amount.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; +import { useSelectedExchange } from "../../hooks/useSelectedExchange.js"; import { buildTermsOfServiceState } from "../../utils/index.js"; import * as wxApi from "../../wxApi.js"; import { PropsFromURI, PropsFromParams, State } from "./index.js"; +type RecursiveState = S | (() => RecursiveState) + export function useComponentStateFromParams( { amount, cancel, onSuccess }: PropsFromParams, api: typeof wxApi, -): State { - const [ageRestricted, setAgeRestricted] = useState(0); - - const exchangeHook = useAsyncAsHook(api.listExchanges); - - const exchangeHookDep = - !exchangeHook || exchangeHook.hasError || !exchangeHook.response - ? undefined - : exchangeHook.response; - - const chosenAmount = Amounts.parseOrThrow(amount); - - // get the first exchange with the currency as the default one - const exchange = exchangeHookDep - ? exchangeHookDep.exchanges.find( - (e) => e.currency === chosenAmount.currency, - ) - : undefined; - /** - * For the exchange selected, bring the status of the terms of service - */ - const terms = useAsyncAsHook(async () => { - if (!exchange) return undefined; - - const exchangeTos = await api.getExchangeTos(exchange.exchangeBaseUrl, [ - "text/xml", - ]); - - const state = buildTermsOfServiceState(exchangeTos); - - return { state }; - }, [exchangeHookDep]); - - /** - * With the exchange and amount, ask the wallet the information - * about the withdrawal - */ - const amountHook = useAsyncAsHook(async () => { - if (!exchange) return undefined; - - const info = await api.getExchangeWithdrawalInfo({ - exchangeBaseUrl: exchange.exchangeBaseUrl, - amount: chosenAmount, - tosAcceptedFormat: ["text/xml"], - ageRestricted, - }); - - const withdrawAmount = { - raw: Amounts.parseOrThrow(info.withdrawalAmountRaw), - effective: Amounts.parseOrThrow(info.withdrawalAmountEffective), - }; - - return { - amount: withdrawAmount, - ageRestrictionOptions: info.ageRestrictionOptions, - }; - }, [exchangeHookDep]); - - const [reviewing, setReviewing] = useState(false); - const [reviewed, setReviewed] = useState(false); +): RecursiveState { + const uriInfoHook = useAsyncAsHook(async () => { + const exchanges = await api.listExchanges(); + return { amount: Amounts.parseOrThrow(amount), exchanges }; + }); - const [withdrawError, setWithdrawError] = useState( - undefined, - ); - const [doingWithdraw, setDoingWithdraw] = useState(false); + console.log("uri info", uriInfoHook) - if (!exchangeHook) return { status: "loading", error: undefined }; - if (exchangeHook.hasError) { - return { - status: "loading-uri", - error: exchangeHook, - }; - } + if (!uriInfoHook) return { status: "loading", error: undefined }; - if (!exchange) { + if (uriInfoHook.hasError) { return { - status: "loading-exchange", - error: { - hasError: true, - operational: false, - message: "ERROR_NO-DEFAULT-EXCHANGE", - }, + status: "loading-error", + error: uriInfoHook, }; } - async function doWithdrawAndCheckError(): Promise { - if (!exchange) return; + const chosenAmount = uriInfoHook.response.amount; + const exchangeList = uriInfoHook.response.exchanges.exchanges - try { - setDoingWithdraw(true); - - const response = await wxApi.acceptManualWithdrawal( - exchange.exchangeBaseUrl, - Amounts.stringify(amount), - ); - - onSuccess(response.transactionId); - } catch (e) { - if (e instanceof TalerError) { - setWithdrawError(e); - } - } - setDoingWithdraw(false); - } - - if (!amountHook) { - return { status: "loading", error: undefined }; - } - if (amountHook.hasError) { + async function doManualWithdraw(exchange: string, ageRestricted: number | undefined): Promise<{ transactionId: string, confirmTransferUrl: string | undefined }> { + const res = await api.acceptManualWithdrawal(exchange, Amounts.stringify(chosenAmount), ageRestricted); return { - status: "loading-info", - error: amountHook, + confirmTransferUrl: undefined, + transactionId: res.transactionId }; } - if (!amountHook.response) { - return { status: "loading", error: undefined }; - } - const withdrawalFee = Amounts.sub( - amountHook.response.amount.raw, - amountHook.response.amount.effective, - ).amount; - const toBeReceived = amountHook.response.amount.effective; - - const { state: termsState } = (!terms - ? undefined - : terms.hasError - ? undefined - : terms.response) || { state: undefined }; - - async function onAccept(accepted: boolean): Promise { - if (!termsState || !exchange) return; - - try { - await api.setExchangeTosAccepted( - exchange.exchangeBaseUrl, - accepted ? termsState.version : undefined, - ); - setReviewed(accepted); - } catch (e) { - if (e instanceof Error) { - //FIXME: uncomment this and display error - // setErrorAccepting(e.message); - } - } - } - - const mustAcceptFirst = - termsState !== undefined && - (termsState.status === "changed" || termsState.status === "new"); + return () => exchangeSelectionState(doManualWithdraw, cancel, onSuccess, undefined, chosenAmount, exchangeList, undefined, api) - const ageRestrictionOptions = - amountHook.response.ageRestrictionOptions?.reduce( - (p, c) => ({ ...p, [c]: `under ${c}` }), - {} as Record, - ); - - const ageRestrictionEnabled = ageRestrictionOptions !== undefined; - if (ageRestrictionEnabled) { - ageRestrictionOptions["0"] = "Not restricted"; - } - - //TODO: calculate based on exchange info - const ageRestriction = ageRestrictionEnabled - ? { - list: ageRestrictionOptions, - value: String(ageRestricted), - onChange: async (v: string) => setAgeRestricted(parseInt(v, 10)), - } - : undefined; - - return { - status: "success", - error: undefined, - exchangeUrl: exchange.exchangeBaseUrl, - toBeReceived, - withdrawalFee, - chosenAmount, - ageRestriction, - doWithdrawal: { - onClick: - doingWithdraw || (mustAcceptFirst && !reviewed) - ? undefined - : doWithdrawAndCheckError, - error: withdrawError, - }, - tosProps: !termsState - ? undefined - : { - onAccept, - onReview: setReviewing, - reviewed: reviewed, - reviewing: reviewing, - terms: termsState, - }, - mustAcceptFirst, - cancel, - }; } export function useComponentStateFromURI( { talerWithdrawUri, cancel, onSuccess }: PropsFromURI, api: typeof wxApi, -): State { - const [ageRestricted, setAgeRestricted] = useState(0); - +): RecursiveState { /** * Ask the wallet about the withdraw URI */ @@ -240,207 +75,219 @@ export function useComponentStateFromURI( const uriInfo = await api.getWithdrawalDetailsForUri({ talerWithdrawUri, }); + const exchanges = await api.listExchanges(); const { amount, defaultExchangeBaseUrl } = uriInfo; - return { amount, thisExchange: defaultExchangeBaseUrl }; + return { talerWithdrawUri, amount: Amounts.parseOrThrow(amount), thisExchange: defaultExchangeBaseUrl, exchanges }; }); - /** - * Get the amount and select one exchange - */ - const uriHookDep = - !uriInfoHook || uriInfoHook.hasError || !uriInfoHook.response - ? undefined - : uriInfoHook.response; - - /** - * For the exchange selected, bring the status of the terms of service - */ - const terms = useAsyncAsHook(async () => { - if (!uriHookDep?.thisExchange) return false; - - const exchangeTos = await api.getExchangeTos(uriHookDep.thisExchange, [ - "text/xml", - ]); - - const state = buildTermsOfServiceState(exchangeTos); - - return { state }; - }, [uriHookDep]); - - /** - * With the exchange and amount, ask the wallet the information - * about the withdrawal - */ - const amountHook = useAsyncAsHook(async () => { - if (!uriHookDep?.thisExchange) return false; - - const info = await api.getExchangeWithdrawalInfo({ - exchangeBaseUrl: uriHookDep?.thisExchange, - amount: Amounts.parseOrThrow(uriHookDep.amount), - tosAcceptedFormat: ["text/xml"], - ageRestricted, - }); - - const withdrawAmount = { - raw: Amounts.parseOrThrow(info.withdrawalAmountRaw), - effective: Amounts.parseOrThrow(info.withdrawalAmountEffective), - }; - - return { - amount: withdrawAmount, - ageRestrictionOptions: info.ageRestrictionOptions, - }; - }, [uriHookDep]); - - const [reviewing, setReviewing] = useState(false); - const [reviewed, setReviewed] = useState(false); - - const [withdrawError, setWithdrawError] = useState( - undefined, - ); - const [doingWithdraw, setDoingWithdraw] = useState(false); - + console.log("uri info", uriInfoHook) if (!uriInfoHook) return { status: "loading", error: undefined }; + if (uriInfoHook.hasError) { return { - status: "loading-uri", + status: "loading-error", error: uriInfoHook, }; } - const { amount, thisExchange } = uriInfoHook.response; + const uri = uriInfoHook.response.talerWithdrawUri; + const chosenAmount = uriInfoHook.response.amount; + const defaultExchange = uriInfoHook.response.thisExchange; + const exchangeList = uriInfoHook.response.exchanges.exchanges - const chosenAmount = Amounts.parseOrThrow(amount); - - if (!thisExchange) { + async function doManagedWithdraw(exchange: string, ageRestricted: number | undefined): Promise<{ transactionId: string, confirmTransferUrl: string | undefined }> { + const res = await api.acceptWithdrawal(uri, exchange, ageRestricted,); return { - status: "loading-exchange", - error: { - hasError: true, - operational: false, - message: "ERROR_NO-DEFAULT-EXCHANGE", - }, + confirmTransferUrl: res.confirmTransferUrl, + transactionId: res.transactionId }; } - // const selectedExchange = thisExchange; + return () => exchangeSelectionState(doManagedWithdraw, cancel, onSuccess, uri, chosenAmount, exchangeList, defaultExchange, api) - async function doWithdrawAndCheckError(): Promise { - if (!thisExchange) return; +} - try { - setDoingWithdraw(true); - if (!talerWithdrawUri) return; - const res = await api.acceptWithdrawal( - talerWithdrawUri, - thisExchange, - !ageRestricted ? undefined : ageRestricted, - ); - if (res.confirmTransferUrl) { - document.location.href = res.confirmTransferUrl; - } else { - onSuccess(res.transactionId); - } - } catch (e) { - if (e instanceof TalerError) { - setWithdrawError(e); - } - } - setDoingWithdraw(false); - } +type ManualOrManagedWithdrawFunction = (exchange: string, ageRestricted: number | undefined) => Promise<{ transactionId: string, confirmTransferUrl: string | undefined }> - if (!amountHook) { - return { status: "loading", error: undefined }; - } - if (amountHook.hasError) { +function exchangeSelectionState(doWithdraw: ManualOrManagedWithdrawFunction, cancel: () => Promise, onSuccess: (txid: string) => Promise, talerWithdrawUri: string | undefined, chosenAmount: AmountJson, exchangeList: ExchangeListItem[], defaultExchange: string | undefined, api: typeof wxApi,): RecursiveState { + + //FIXME: use substates here + const selectedExchange = useSelectedExchange({ currency: chosenAmount.currency, defaultExchange, list: exchangeList }) + + if (selectedExchange.status === 'no-exchange') { return { - status: "loading-info", - error: amountHook, - }; + status: "no-exchange", + error: undefined, + } } - if (!amountHook.response) { - return { status: "loading", error: undefined }; + + if (selectedExchange.status === 'selecting-exchange') { + return selectedExchange } + console.log("exchange selected", selectedExchange.selected) + + return () => { + + const [ageRestricted, setAgeRestricted] = useState(0); + const currentExchange = selectedExchange.selected + /** + * For the exchange selected, bring the status of the terms of service + */ + const terms = useAsyncAsHook(async () => { + const exchangeTos = await api.getExchangeTos(currentExchange.exchangeBaseUrl, [ + "text/xml", + ]); + + const state = buildTermsOfServiceState(exchangeTos); + + return { state }; + }, []); + console.log("terms", terms) + /** + * With the exchange and amount, ask the wallet the information + * about the withdrawal + */ + const amountHook = useAsyncAsHook(async () => { + + const info = await api.getExchangeWithdrawalInfo({ + exchangeBaseUrl: currentExchange.exchangeBaseUrl, + amount: chosenAmount, + tosAcceptedFormat: ["text/xml"], + ageRestricted, + }); + + const withdrawAmount = { + raw: Amounts.parseOrThrow(info.withdrawalAmountRaw), + effective: Amounts.parseOrThrow(info.withdrawalAmountEffective), + }; + + return { + amount: withdrawAmount, + ageRestrictionOptions: info.ageRestrictionOptions, + }; + }, []); + + const [reviewing, setReviewing] = useState(false); + const [reviewed, setReviewed] = useState(false); + + const [withdrawError, setWithdrawError] = useState( + undefined, + ); + const [doingWithdraw, setDoingWithdraw] = useState(false); + + + async function doWithdrawAndCheckError(): Promise { + + try { + setDoingWithdraw(true); + const res = await doWithdraw(currentExchange.exchangeBaseUrl, !ageRestricted ? undefined : ageRestricted) + if (res.confirmTransferUrl) { + document.location.href = res.confirmTransferUrl; + } else { + onSuccess(res.transactionId); + } + } catch (e) { + if (e instanceof TalerError) { + setWithdrawError(e); + } + } + setDoingWithdraw(false); + } - const withdrawalFee = Amounts.sub( - amountHook.response.amount.raw, - amountHook.response.amount.effective, - ).amount; - const toBeReceived = amountHook.response.amount.effective; - - const { state: termsState } = (!terms - ? undefined - : terms.hasError - ? undefined - : terms.response) || { state: undefined }; - - async function onAccept(accepted: boolean): Promise { - if (!termsState || !thisExchange) return; - - try { - await api.setExchangeTosAccepted( - thisExchange, - accepted ? termsState.version : undefined, - ); - setReviewed(accepted); - } catch (e) { - if (e instanceof Error) { - //FIXME: uncomment this and display error - // setErrorAccepting(e.message); + if (!amountHook) { + return { status: "loading", error: undefined }; + } + if (amountHook.hasError) { + return { + status: "loading-info", + error: amountHook, + }; + } + if (!amountHook.response) { + return { status: "loading", error: undefined }; + } + + const withdrawalFee = Amounts.sub( + amountHook.response.amount.raw, + amountHook.response.amount.effective, + ).amount; + const toBeReceived = amountHook.response.amount.effective; + + const { state: termsState } = (!terms + ? undefined + : terms.hasError + ? undefined + : terms.response) || { state: undefined }; + + async function onAccept(accepted: boolean): Promise { + if (!termsState) return; + + try { + await api.setExchangeTosAccepted( + currentExchange.exchangeBaseUrl, + accepted ? termsState.version : undefined, + ); + setReviewed(accepted); + } catch (e) { + if (e instanceof Error) { + //FIXME: uncomment this and display error + // setErrorAccepting(e.message); + } } } - } - const mustAcceptFirst = - termsState !== undefined && - (termsState.status === "changed" || termsState.status === "new"); + const mustAcceptFirst = + termsState !== undefined && + (termsState.status === "changed" || termsState.status === "new"); - const ageRestrictionOptions = - amountHook.response.ageRestrictionOptions?.reduce( - (p, c) => ({ ...p, [c]: `under ${c}` }), - {} as Record, - ); + const ageRestrictionOptions = + amountHook.response.ageRestrictionOptions?.reduce( + (p, c) => ({ ...p, [c]: `under ${c}` }), + {} as Record, + ); - const ageRestrictionEnabled = ageRestrictionOptions !== undefined; - if (ageRestrictionEnabled) { - ageRestrictionOptions["0"] = "Not restricted"; - } + const ageRestrictionEnabled = ageRestrictionOptions !== undefined; + if (ageRestrictionEnabled) { + ageRestrictionOptions["0"] = "Not restricted"; + } - //TODO: calculate based on exchange info - const ageRestriction = ageRestrictionEnabled - ? { + //TODO: calculate based on exchange info + const ageRestriction = ageRestrictionEnabled + ? { list: ageRestrictionOptions, value: String(ageRestricted), onChange: async (v: string) => setAgeRestricted(parseInt(v, 10)), } - : undefined; - - return { - status: "success", - error: undefined, - exchangeUrl: thisExchange, - toBeReceived, - withdrawalFee, - chosenAmount, - talerWithdrawUri, - ageRestriction, - doWithdrawal: { - onClick: - doingWithdraw || (mustAcceptFirst && !reviewed) - ? undefined - : doWithdrawAndCheckError, - error: withdrawError, - }, - tosProps: !termsState - ? undefined - : { + : undefined; + + return { + status: "success", + error: undefined, + doSelectExchange: selectedExchange.doSelect, + exchangeUrl: currentExchange.exchangeBaseUrl, + toBeReceived, + withdrawalFee, + chosenAmount, + talerWithdrawUri, + ageRestriction, + doWithdrawal: { + onClick: + doingWithdraw || (mustAcceptFirst && !reviewed) + ? undefined + : doWithdrawAndCheckError, + error: withdrawError, + }, + tosProps: !termsState + ? undefined + : { onAccept, onReview: setReviewing, reviewed: reviewed, reviewing: reviewing, terms: termsState, }, - mustAcceptFirst, - cancel, - }; + mustAcceptFirst, + cancel, + }; + } } diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx index 2be4437cc..a3daeb5e9 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx @@ -76,6 +76,8 @@ export const TermsOfServiceNotYetLoaded = createExample(SuccessView, { fraction: 10000000, value: 1, }, + doSelectExchange: { + }, toBeReceived: { currency: "USD", fraction: 0, @@ -104,6 +106,8 @@ export const WithSomeFee = createExample(SuccessView, { fraction: 0, value: 1, }, + doSelectExchange: { + }, tosProps: normalTosState, }); @@ -123,6 +127,8 @@ export const WithoutFee = createExample(SuccessView, { fraction: 0, value: 0, }, + doSelectExchange: { + }, toBeReceived: { currency: "USD", fraction: 0, @@ -147,6 +153,8 @@ export const EditExchangeUntouched = createExample(SuccessView, { fraction: 0, value: 0, }, + doSelectExchange: { + }, toBeReceived: { currency: "USD", fraction: 0, @@ -171,6 +179,8 @@ export const EditExchangeModified = createExample(SuccessView, { fraction: 0, value: 0, }, + doSelectExchange: { + }, toBeReceived: { currency: "USD", fraction: 0, @@ -188,6 +198,8 @@ export const WithAgeRestriction = createExample(SuccessView, { value: 2, fraction: 10000000, }, + doSelectExchange: { + }, doWithdrawal: nullHandler, exchangeUrl: "https://exchange.demo.taler.net", mustAcceptFirst: false, diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts index f614c1c8c..5c62671fe 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts @@ -29,6 +29,7 @@ import { ExchangeWithdrawDetails } from "@gnu-taler/taler-wallet-core"; import { expect } from "chai"; import { mountHook } from "../../test-utils.js"; import { useComponentStateFromURI } from "./state.js"; +import * as wxApi from "../../wxApi.js"; const exchanges: ExchangeFullDetails[] = [ { @@ -92,7 +93,7 @@ describe("Withdraw CTA states", () => { { const { status, error } = getLastResultOrThrow(); - if (status != "loading-uri") expect.fail(); + if (status != "loading-error") expect.fail(); if (!error) expect.fail(); if (!error.hasError) expect.fail(); if (error.operational) expect.fail(); @@ -127,7 +128,7 @@ describe("Withdraw CTA states", () => { { const { status } = getLastResultOrThrow(); - expect(status).equals("loading"); + expect(status).equals("loading", "1"); } await waitNextUpdate(); @@ -135,13 +136,9 @@ describe("Withdraw CTA states", () => { { const { status, error } = getLastResultOrThrow(); - expect(status).equals("loading-exchange"); + expect(status).equals("no-exchange", "3"); - expect(error).deep.equals({ - hasError: true, - operational: false, - message: "ERROR_NO-DEFAULT-EXCHANGE", - }); + expect(error).undefined; } await assertNoPendingUpdate(); @@ -169,10 +166,10 @@ describe("Withdraw CTA states", () => { }), getExchangeWithdrawalInfo: async (): Promise => - ({ - withdrawalAmountRaw: "ARS:2", - withdrawalAmountEffective: "ARS:2", - } as any), + ({ + withdrawalAmountRaw: "ARS:2", + withdrawalAmountEffective: "ARS:2", + } as any), getExchangeTos: async (): Promise => ({ contentType: "text", content: "just accept", @@ -246,10 +243,10 @@ describe("Withdraw CTA states", () => { }), getExchangeWithdrawalInfo: async (): Promise => - ({ - withdrawalAmountRaw: "ARS:2", - withdrawalAmountEffective: "ARS:2", - } as any), + ({ + withdrawalAmountRaw: "ARS:2", + withdrawalAmountEffective: "ARS:2", + } as any), getExchangeTos: async (): Promise => ({ contentType: "text", content: "just accept", diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx index 60157d289..82d6090e5 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx @@ -38,6 +38,7 @@ import editIcon from "../../svg/edit_24px.svg"; import { Amount } from "../../components/Amount.js"; import { QR } from "../../components/QR.js"; import { useState } from "preact/hooks"; +import { ErrorMessage } from "../../components/ErrorMessage.js"; export function LoadingUriView({ error }: State.LoadingUriError): VNode { const { i18n } = useTranslationContext(); @@ -52,15 +53,12 @@ export function LoadingUriView({ error }: State.LoadingUriError): VNode { ); } -export function LoadingExchangeView({ - error, -}: State.LoadingExchangeError): VNode { +export function LoadingExchangeView(p: State.LoadingExchangeError): VNode { const { i18n } = useTranslationContext(); return ( - Could not get exchange} - error={error} + Could not get a default exchange, please check configuration} /> ); } @@ -106,13 +104,13 @@ export function SuccessView(state: State.Success): VNode { }} > Exchange - {/* + } text={} -- cgit v1.2.3