set amount for manual withdraw when the qr does not have it

This commit is contained in:
Sebastian 2023-06-27 08:20:49 -03:00
parent 18a3d764de
commit 97a9e92d8b
No known key found for this signature in database
GPG Key ID: 173909D1A5F66069
4 changed files with 135 additions and 15 deletions

View File

@ -14,10 +14,18 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import { AmountJson, ExchangeListItem } from "@gnu-taler/taler-util";
import {
AmountJson,
AmountString,
ExchangeListItem,
} from "@gnu-taler/taler-util";
import { Loading } from "../../components/Loading.js";
import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js";
import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
import {
AmountFieldHandler,
ButtonHandler,
SelectFieldHandler,
} from "../../mui/handlers.js";
import { StateViewMap, compose } from "../../utils/index.js";
import {
useComponentStateFromParams,
@ -37,10 +45,11 @@ export interface PropsFromURI {
}
export interface PropsFromParams {
talerExchangeWithdrawUri: string;
amount: string;
talerExchangeWithdrawUri: string | undefined;
amount: string | undefined;
cancel: () => Promise<void>;
onSuccess: (txid: string) => Promise<void>;
onAmountChanged: (amount: AmountString) => Promise<void>;
}
export type State =
@ -64,7 +73,9 @@ export namespace State {
export interface SelectAmount {
status: "select-amount";
error: undefined;
currentExchange: ExchangeListItem;
exchangeBaseUrl: string;
confirm: ButtonHandler;
amount: AmountFieldHandler;
currency: string;
}

View File

@ -26,7 +26,7 @@ import {
stringifyWithdrawUri,
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useState } from "preact/hooks";
import { useEffect, useState } from "preact/hooks";
import { alertFromError, useAlertContext } from "../../context/alert.js";
import { useBackendContext } from "../../context/backend.js";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
@ -39,16 +39,20 @@ export function useComponentStateFromParams({
talerExchangeWithdrawUri: maybeTalerUri,
amount,
cancel,
onAmountChanged,
onSuccess,
}: PropsFromParams): RecursiveState<State> {
const api = useBackendContext();
const { i18n } = useTranslationContext();
const paramsAmount = amount ? Amounts.parse(amount) : undefined;
const uriInfoHook = useAsyncAsHook(async () => {
const exchanges = await api.wallet.call(
WalletApiOperation.ListExchanges,
{},
);
const uri = parseWithdrawExchangeUri(maybeTalerUri);
const uri = maybeTalerUri
? parseWithdrawExchangeUri(maybeTalerUri)
: undefined;
const exchangeByTalerUri = uri?.exchangeBaseUrl;
let ex: ExchangeFullDetails | undefined;
if (exchangeByTalerUri && uri.exchangePub) {
@ -65,11 +69,8 @@ export function useComponentStateFromParams({
ex = info.exchange;
}
const chosenAmount = uri
? uri.amount
? Amounts.parseOrThrow(uri.amount)
: Amounts.parseOrThrow(`${ex ? ex.currency : "KUDOS"}:66`)
: Amounts.parseOrThrow(amount);
const chosenAmount =
!uri || !uri.amount ? undefined : Amounts.parse(uri.amount);
return { amount: chosenAmount, exchanges, exchange: ex };
});
@ -85,10 +86,76 @@ export function useComponentStateFromParams({
};
}
const chosenAmount = uriInfoHook.response.amount;
useEffect(() => {
uriInfoHook?.retry();
}, [amount]);
const exchangeByTalerUri = uriInfoHook.response.exchange?.exchangeBaseUrl;
const exchangeList = uriInfoHook.response.exchanges.exchanges;
const maybeAmount = uriInfoHook.response.amount ?? paramsAmount;
if (!maybeAmount) {
const exchangeBaseUrl =
uriInfoHook.response.exchange?.exchangeBaseUrl ??
(exchangeList.length > 0 ? exchangeList[0].exchangeBaseUrl : undefined);
const currency =
uriInfoHook.response.exchange?.currency ??
(exchangeList.length > 0 ? exchangeList[0].currency : undefined);
if (!exchangeBaseUrl) {
return {
status: "error",
error: {
message: i18n.str`Can't withdraw from exchange`,
description: i18n.str`Missing base URL`,
cause: undefined,
context: {},
type: "error",
},
};
}
if (!currency) {
return {
status: "error",
error: {
message: i18n.str`Can't withdraw from exchange`,
description: i18n.str`Missing unknown currency`,
cause: undefined,
context: {},
type: "error",
},
};
}
return () => {
const { pushAlertOnError } = useAlertContext();
const [amount, setAmount] = useState<AmountJson>(
Amounts.zeroOfCurrency(currency),
);
const isValid = Amounts.isNonZero(amount);
return {
status: "select-amount",
currency,
exchangeBaseUrl,
error: undefined,
confirm: {
onClick: isValid
? pushAlertOnError(async () => {
onAmountChanged(Amounts.stringify(amount));
})
: undefined,
},
amount: {
value: amount,
onInput: pushAlertOnError(async (e) => {
setAmount(e);
}),
},
};
};
}
const chosenAmount = maybeAmount;
async function doManualWithdraw(
exchange: string,
ageRestricted: number | undefined,

View File

@ -32,6 +32,8 @@ import {
WithdrawDetails,
} from "../../wallet/Transaction.js";
import { State } from "./index.js";
import { Grid } from "../../mui/Grid.js";
import { AmountField } from "../../components/AmountField.js";
export function SuccessView(state: State.Success): VNode {
const { i18n } = useTranslationContext();
@ -143,11 +145,45 @@ function WithdrawWithMobile({
);
}
export function SelectAmountView({ currency }: State.SelectAmount): VNode {
export function SelectAmountView({
currency,
amount,
exchangeBaseUrl,
confirm,
}: State.SelectAmount): VNode {
const { i18n } = useTranslationContext();
return (
<Fragment>
<p>select the amount for ${currency}</p>
<section style={{ textAlign: "left" }}>
<Part
title={
<div
style={{
display: "flex",
alignItems: "center",
}}
>
<i18n.Translate>Exchange</i18n.Translate>
</div>
}
text={<ExchangeDetails exchange={exchangeBaseUrl} />}
kind="neutral"
big
/>
<Grid container columns={2} justifyContent="space-between">
<AmountField label={i18n.str`Amount`} required handler={amount} />
</Grid>
</section>
<section>
<Button
variant="contained"
color="info"
disabled={!confirm.onClick}
onClick={confirm.onClick}
>
<i18n.Translate>See details</i18n.Translate>
</Button>
</section>
</Fragment>
);
}

View File

@ -400,6 +400,12 @@ export function Application(): VNode {
}) => (
<CallToActionTemplate title={i18n.str`Digital cash withdrawal`}>
<WithdrawPageFromParams
onAmountChanged={async (e) => {
const page = `${Pages.ctaWithdrawManual({
amount,
})}?talerUri=${encodeURIComponent(talerUri)}`;
redirectTo(page);
}}
talerExchangeWithdrawUri={talerUri}
amount={amount}
cancel={() => redirectTo(Pages.balance)}