summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/cta/Withdraw.tsx
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2021-10-11 15:59:55 -0300
committerSebastian <sebasjm@gmail.com>2021-10-11 15:59:55 -0300
commitbe8e3f4b1d090a536967f132a7fd4742bbcd5343 (patch)
treed184ba3cf40510009e4121c6daa5653e0be475b0 /packages/taler-wallet-webextension/src/cta/Withdraw.tsx
parent78fb5f79a8690ee490c96b271dadd37f4c9442d6 (diff)
downloadwallet-core-be8e3f4b1d090a536967f132a7fd4742bbcd5343.tar.gz
wallet-core-be8e3f4b1d090a536967f132a7fd4742bbcd5343.tar.bz2
wallet-core-be8e3f4b1d090a536967f132a7fd4742bbcd5343.zip
fixing withdrawal process
Diffstat (limited to 'packages/taler-wallet-webextension/src/cta/Withdraw.tsx')
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw.tsx171
1 files changed, 86 insertions, 85 deletions
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<void>;
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<string | undefined>(undefined)
+ const exchanges = knownExchanges.reduce((prev, ex) => ({ ...prev, [ex.exchangeBaseUrl]: ex.exchangeBaseUrl }), {})
+
return (
<WalletAction>
<LogoHeader />
@@ -84,7 +92,7 @@ export function View({ details, amount, onWithdraw, terms, reviewing, onReview,
{i18n.str`Digital cash withdrawal`}
</h2>
<section>
- <Part title="Total to withdraw" text={amountToString(Amounts.sub(Amounts.parseOrThrow(amount), details.withdrawFee).amount)} kind='positive' />
+ <Part title="Total to withdraw" text={amountToString(Amounts.sub(amount, details.withdrawFee).amount)} kind='positive' />
<Part title="Chosen amount" text={amountToString(amount)} kind='neutral' />
{Amounts.isNonZero(details.withdrawFee) &&
<Part title="Exchange fee" text={amountToString(details.withdrawFee)} kind='negative' />
@@ -93,11 +101,21 @@ export function View({ details, amount, onWithdraw, terms, reviewing, onReview,
</section>
{!reviewing &&
<section>
- <LinkSuccess
- upperCased
- >
- {i18n.str`Edit exchange`}
- </LinkSuccess>
+ {switchingExchange !== undefined ? <Fragment>
+ <div>
+ <SelectList label="Known exchanges" list={exchanges} name="" onChange={onSwitchExchange} />
+ </div>
+ <p>
+ This is the list of known exchanges
+ </p>
+ <LinkSuccess upperCased onClick={() => onSwitchExchange(switchingExchange)}>
+ {i18n.str`Confirm exchange selection`}
+ </LinkSuccess>
+ </Fragment>
+ : <LinkSuccess upperCased onClick={() => setSwitchingExchange("")}>
+ {i18n.str`Switch exchange`}
+ </LinkSuccess>}
+
</section>
}
{!reviewing && accepted &&
@@ -140,6 +158,9 @@ export function View({ details, amount, onWithdraw, terms, reviewing, onReview,
</section>
}
+ {/**
+ * Main action section
+ */}
<section>
{terms.status === 'new' && !accepted && !reviewing &&
<ButtonSuccess
@@ -178,80 +199,55 @@ export function View({ details, amount, onWithdraw, terms, reviewing, onReview,
)
}
-export function WithdrawPage({ talerWithdrawUri, ...rest }: Props): JSX.Element {
- const [uriInfo, setUriInfo] = useState<WithdrawUriInfoResponse | undefined>(undefined);
- const [details, setDetails] = useState<ExchangeWithdrawDetails | undefined>(undefined);
- const [cancelled, setCancelled] = useState(false);
- const [selecting, setSelecting] = useState(false);
- const [error, setError] = useState<boolean>(false);
- const [updateCounter, setUpdateCounter] = useState(1);
+export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriInfo: WithdrawUriInfoResponse }) {
+ const [customExchange, setCustomExchange] = useState<string | undefined>(undefined)
+ const [errorAccepting, setErrorAccepting] = useState<string | undefined>(undefined)
+
const [reviewing, setReviewing] = useState<boolean>(false)
const [accepted, setAccepted] = useState<boolean>(false)
const [confirmed, setConfirmed] = useState<boolean>(false)
- useEffect(() => {
- return onUpdateNotification(() => {
- console.log('updating...')
- setUpdateCounter(updateCounter + 1);
- });
- }, []);
-
- useEffect(() => {
- console.log('on effect yes', talerWithdrawUri)
- if (!talerWithdrawUri) return
- const fetchData = async (): Promise<void> => {
- 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 <span><i18n.Translate>missing withdraw uri</i18n.Translate></span>;
+ 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 <span><i18n.Translate>Getting withdrawal details.</i18n.Translate></span>;
+ }
+ if (detailsHook.hasError) {
+ return <span><i18n.Translate>Problems getting details: {detailsHook.message}</i18n.Translate></span>;
}
+ const details = detailsHook.response
+
const onAccept = async (): Promise<void> => {
- 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<void> => {
- 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 <span><i18n.Translate>Withdraw operation has been cancelled.</i18n.Translate></span>;
- }
- if (error) {
- return <span><i18n.Translate>This URI is not valid anymore.</i18n.Translate></span>;
- }
- if (!uriInfo) {
- return <span><i18n.Translate>Loading...</i18n.Translate></span>;
- }
- if (!details) {
- return <span><i18n.Translate>Getting withdrawal details.</i18n.Translate></span>;
- }
-
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 <View onWithdraw={onWithdraw}
// setCancelled={setCancelled} setSelecting={setSelecting}
- details={details} amount={uriInfo.amount}
+ details={details} amount={withdrawAmount}
terms={{
status, value: termsContent
}}
+ onSwitchExchange={setCustomExchange}
+ knownExchanges={knownExchanges}
confirmed={confirmed}
accepted={accepted} onAccept={onAccept}
reviewing={reviewing} onReview={setReviewing}
// terms={[]}
/>
}
+export function WithdrawPage({ talerWithdrawUri }: Props): JSX.Element {
+ const uriInfoHook = useAsyncAsHook(() => !talerWithdrawUri ? Promise.reject(undefined) :
+ getWithdrawalDetailsForUri({ talerWithdrawUri })
+ )
+
+ if (!talerWithdrawUri) {
+ return <span><i18n.Translate>missing withdraw uri</i18n.Translate></span>;
+ }
+ if (!uriInfoHook) {
+ return <span><i18n.Translate>Loading...</i18n.Translate></span>;
+ }
+ if (uriInfoHook.hasError) {
+ return <span><i18n.Translate>This URI is not valid anymore: {uriInfoHook.message}</i18n.Translate></span>;
+ }
+ return <WithdrawPageWithParsedURI uri={talerWithdrawUri} uriInfo={uriInfoHook.response} />
+}