set amount for manual withdraw when the qr does not have it
This commit is contained in:
parent
18a3d764de
commit
97a9e92d8b
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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)}
|
||||
|
Loading…
Reference in New Issue
Block a user