From be8e3f4b1d090a536967f132a7fd4742bbcd5343 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 11 Oct 2021 15:59:55 -0300 Subject: fixing withdrawal process --- .../taler-wallet-webextension/src/cta/Withdraw.tsx | 171 +++++++++++---------- 1 file changed, 86 insertions(+), 85 deletions(-) (limited to 'packages/taler-wallet-webextension/src/cta/Withdraw.tsx') diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx index 46451e72c..52295f1af 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx +++ b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx @@ -21,18 +21,21 @@ * @author Florian Dold */ -import { AmountLike, Amounts, i18n, WithdrawUriInfoResponse } from '@gnu-taler/taler-util'; +import { AmountJson, Amounts, ExchangeListItem, i18n, WithdrawUriInfoResponse } from '@gnu-taler/taler-util'; import { ExchangeWithdrawDetails } from '@gnu-taler/taler-wallet-core/src/operations/withdraw'; -import { useEffect, useState } from "preact/hooks"; +import { useState } from "preact/hooks"; +import { Fragment } from 'preact/jsx-runtime'; import { CheckboxOutlined } from '../components/CheckboxOutlined'; import { ExchangeXmlTos } from '../components/ExchangeToS'; import { LogoHeader } from '../components/LogoHeader'; import { Part } from '../components/Part'; -import { ButtonDestructive, ButtonSuccess, ButtonWarning, LinkSuccess, LinkWarning, TermsOfService, WalletAction } from '../components/styled'; +import { SelectList } from '../components/SelectList'; +import { ButtonSuccess, ButtonWarning, LinkSuccess, LinkWarning, TermsOfService, WalletAction } from '../components/styled'; +import { useAsyncAsHook } from '../hooks/useAsyncAsHook'; import { - acceptWithdrawal, getExchangeWithdrawalInfo, getWithdrawalDetailsForUri, onUpdateNotification, setExchangeTosAccepted + acceptWithdrawal, getExchangeWithdrawalInfo, getWithdrawalDetailsForUri, setExchangeTosAccepted, listExchanges } from "../wxApi"; -import { h } from 'preact'; +import { wxMain } from '../wxBackend.js'; interface Props { talerWithdrawUri?: string; @@ -40,7 +43,8 @@ interface Props { export interface ViewProps { details: ExchangeWithdrawDetails; - amount: string; + amount: AmountJson; + onSwitchExchange: (ex: string) => void; onWithdraw: () => Promise; onReview: (b: boolean) => void; onAccept: (b: boolean) => void; @@ -50,7 +54,8 @@ export interface ViewProps { terms: { value?: TermsDocument; status: TermsStatus; - } + }, + knownExchanges: ExchangeListItem[] }; @@ -68,15 +73,18 @@ interface TermsDocumentHtml { href: string, } -function amountToString(text: AmountLike) { +function amountToString(text: AmountJson) { const aj = Amounts.jsonifyAmount(text) const amount = Amounts.stringifyValue(aj) return `${amount} ${aj.currency}` } -export function View({ details, amount, onWithdraw, terms, reviewing, onReview, onAccept, accepted, confirmed }: ViewProps) { +export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExchange, terms, reviewing, onReview, onAccept, accepted, confirmed }: ViewProps) { const needsReview = terms.status === 'changed' || terms.status === 'new' + const [switchingExchange, setSwitchingExchange] = useState(undefined) + const exchanges = knownExchanges.reduce((prev, ex) => ({ ...prev, [ex.exchangeBaseUrl]: ex.exchangeBaseUrl }), {}) + return ( @@ -84,7 +92,7 @@ export function View({ details, amount, onWithdraw, terms, reviewing, onReview, {i18n.str`Digital cash withdrawal`}
- + {Amounts.isNonZero(details.withdrawFee) && @@ -93,11 +101,21 @@ export function View({ details, amount, onWithdraw, terms, reviewing, onReview,
{!reviewing &&
- - {i18n.str`Edit exchange`} - + {switchingExchange !== undefined ? +
+ +
+

+ This is the list of known exchanges +

+ onSwitchExchange(switchingExchange)}> + {i18n.str`Confirm exchange selection`} + +
+ : setSwitchingExchange("")}> + {i18n.str`Switch exchange`} + } +
} {!reviewing && accepted && @@ -140,6 +158,9 @@ export function View({ details, amount, onWithdraw, terms, reviewing, onReview, } + {/** + * Main action section + */}
{terms.status === 'new' && !accepted && !reviewing && (undefined); - const [details, setDetails] = useState(undefined); - const [cancelled, setCancelled] = useState(false); - const [selecting, setSelecting] = useState(false); - const [error, setError] = useState(false); - const [updateCounter, setUpdateCounter] = useState(1); +export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriInfo: WithdrawUriInfoResponse }) { + const [customExchange, setCustomExchange] = useState(undefined) + const [errorAccepting, setErrorAccepting] = useState(undefined) + const [reviewing, setReviewing] = useState(false) const [accepted, setAccepted] = useState(false) const [confirmed, setConfirmed] = useState(false) - useEffect(() => { - return onUpdateNotification(() => { - console.log('updating...') - setUpdateCounter(updateCounter + 1); - }); - }, []); - - useEffect(() => { - console.log('on effect yes', talerWithdrawUri) - if (!talerWithdrawUri) return - const fetchData = async (): Promise => { - try { - const res = await getWithdrawalDetailsForUri({ talerWithdrawUri }); - setUriInfo(res); - } catch (e) { - console.error('error', JSON.stringify(e, undefined, 2)) - setError(true) - } - }; - fetchData(); - }, [selecting, talerWithdrawUri, updateCounter]); + const knownExchangesHook = useAsyncAsHook(() => listExchanges()) - useEffect(() => { - async function fetchData() { - if (!uriInfo || !uriInfo.defaultExchangeBaseUrl) return - try { - const res = await getExchangeWithdrawalInfo({ - exchangeBaseUrl: uriInfo.defaultExchangeBaseUrl, - amount: Amounts.parseOrThrow(uriInfo.amount), - tosAcceptedFormat: ['text/json', 'text/xml', 'text/pdf'] - }) - setDetails(res) - } catch (e) { - setError(true) - } - } - fetchData() - }, [uriInfo]) + const knownExchanges = !knownExchangesHook || knownExchangesHook.hasError ? [] : knownExchangesHook.response.exchanges + const withdrawAmount = Amounts.parseOrThrow(uriInfo.amount) + const thisCurrencyExchanges = knownExchanges.filter(ex => ex.currency === withdrawAmount.currency) - if (!talerWithdrawUri) { - return missing withdraw uri; + const exchange = customExchange || uriInfo.defaultExchangeBaseUrl || thisCurrencyExchanges[0]?.exchangeBaseUrl + const detailsHook = useAsyncAsHook(async () => { + if (!exchange) throw Error('no default exchange') + return getExchangeWithdrawalInfo({ + exchangeBaseUrl: exchange, + amount: withdrawAmount, + tosAcceptedFormat: ['text/json', 'text/xml', 'text/pdf'] + }) + }) + + if (!detailsHook) { + return Getting withdrawal details.; + } + if (detailsHook.hasError) { + return Problems getting details: {detailsHook.message}; } + const details = detailsHook.response + const onAccept = async (): Promise => { - if (!details) { - throw Error("can't accept, no exchange selected"); - } try { - await setExchangeTosAccepted(details.exchangeDetails.exchangeBaseUrl, details.tosRequested?.tosEtag) + await setExchangeTosAccepted(details.exchangeInfo.baseUrl, details.tosRequested?.tosEtag) setAccepted(true) } catch (e) { - setError(true) + if (e instanceof Error) { + setErrorAccepting(e.message) + } } } const onWithdraw = async (): Promise => { - if (!details) { - throw Error("can't accept, no exchange selected"); - } setConfirmed(true) - console.log("accepting exchange", details.exchangeInfo.baseUrl); + console.log("accepting exchange", details.exchangeDetails.exchangeBaseUrl); try { - const res = await acceptWithdrawal(talerWithdrawUri, details.exchangeInfo.baseUrl); + const res = await acceptWithdrawal(uri, details.exchangeInfo.baseUrl); console.log("accept withdrawal response", res); if (res.confirmTransferUrl) { document.location.href = res.confirmTransferUrl; @@ -261,19 +257,6 @@ export function WithdrawPage({ talerWithdrawUri, ...rest }: Props): JSX.Element } }; - if (cancelled) { - return Withdraw operation has been cancelled.; - } - if (error) { - return This URI is not valid anymore.; - } - if (!uriInfo) { - return Loading...; - } - if (!details) { - return Getting withdrawal details.; - } - let termsContent: TermsDocument | undefined = undefined; if (details.tosRequested) { if (details.tosRequested.tosContentType === 'text/xml') { @@ -295,14 +278,32 @@ export function WithdrawPage({ talerWithdrawUri, ...rest }: Props): JSX.Element return } +export function WithdrawPage({ talerWithdrawUri }: Props): JSX.Element { + const uriInfoHook = useAsyncAsHook(() => !talerWithdrawUri ? Promise.reject(undefined) : + getWithdrawalDetailsForUri({ talerWithdrawUri }) + ) + + if (!talerWithdrawUri) { + return missing withdraw uri; + } + if (!uriInfoHook) { + return Loading...; + } + if (uriInfoHook.hasError) { + return This URI is not valid anymore: {uriInfoHook.message}; + } + return +} -- cgit v1.2.3