fix #7791
This commit is contained in:
parent
d5c5c7463e
commit
8eee38d559
@ -122,7 +122,7 @@ export function AlertView({
|
||||
<Alert title={alert.message} severity={alert.type} onClose={onClose}>
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
<div>{alert.description}</div>
|
||||
{alert.type === "error" ? (
|
||||
{alert.type === "error" && alert.cause !== undefined ? (
|
||||
<AlertContext context={alert.context} cause={alert.cause} />
|
||||
) : undefined}
|
||||
</div>
|
||||
|
@ -40,8 +40,8 @@ export interface ErrorAlert {
|
||||
message: TranslatedString;
|
||||
description: TranslatedString | VNode;
|
||||
type: "error";
|
||||
context: object;
|
||||
cause: any;
|
||||
context: object | undefined;
|
||||
cause: any | undefined;
|
||||
}
|
||||
|
||||
type Type = {
|
||||
|
@ -37,7 +37,7 @@ export type State =
|
||||
| State.LoadingUriError
|
||||
| State.Ready
|
||||
| SelectExchangeState.Selecting
|
||||
| SelectExchangeState.NoExchange;
|
||||
| SelectExchangeState.NoExchangeFound;
|
||||
|
||||
export namespace State {
|
||||
export interface Loading {
|
||||
@ -70,7 +70,7 @@ export namespace State {
|
||||
const viewMapping: StateViewMap<State> = {
|
||||
loading: Loading,
|
||||
error: ErrorAlertView,
|
||||
"no-exchange": NoExchangesView,
|
||||
"no-exchange-found": NoExchangesView,
|
||||
"selecting-exchange": ExchangeSelectionPage,
|
||||
ready: ReadyView,
|
||||
};
|
||||
|
@ -46,7 +46,7 @@ export interface PropsFromParams {
|
||||
export type State =
|
||||
| State.Loading
|
||||
| State.LoadingUriError
|
||||
| SelectExchangeState.NoExchange
|
||||
| SelectExchangeState.NoExchangeFound
|
||||
| SelectExchangeState.Selecting
|
||||
| State.Success;
|
||||
|
||||
@ -84,7 +84,7 @@ export namespace State {
|
||||
const viewMapping: StateViewMap<State> = {
|
||||
loading: Loading,
|
||||
error: ErrorAlertView,
|
||||
"no-exchange": NoExchangesView,
|
||||
"no-exchange-found": NoExchangesView,
|
||||
"selecting-exchange": ExchangeSelectionPage,
|
||||
success: SuccessView,
|
||||
};
|
||||
|
@ -118,12 +118,12 @@ export function useComponentStateFromURI({
|
||||
talerWithdrawUri,
|
||||
},
|
||||
);
|
||||
const { amount, defaultExchangeBaseUrl } = uriInfo;
|
||||
const { amount, defaultExchangeBaseUrl, possibleExchanges } = uriInfo;
|
||||
return {
|
||||
talerWithdrawUri,
|
||||
amount: Amounts.parseOrThrow(amount),
|
||||
thisExchange: defaultExchangeBaseUrl,
|
||||
exchanges: uriInfo.possibleExchanges,
|
||||
exchanges: possibleExchanges,
|
||||
};
|
||||
});
|
||||
|
||||
@ -191,12 +191,12 @@ function exchangeSelectionState(
|
||||
talerWithdrawUri: string | undefined,
|
||||
chosenAmount: AmountJson,
|
||||
exchangeList: ExchangeListItem[],
|
||||
defaultExchange: string | undefined,
|
||||
exchangeSuggestedByTheBank: string | undefined,
|
||||
): RecursiveState<State> {
|
||||
const api = useBackendContext();
|
||||
const selectedExchange = useSelectedExchange({
|
||||
currency: chosenAmount.currency,
|
||||
defaultExchange,
|
||||
defaultExchange: exchangeSuggestedByTheBank,
|
||||
list: exchangeList,
|
||||
});
|
||||
|
||||
|
@ -122,7 +122,7 @@ describe("Withdraw CTA states", () => {
|
||||
expect(status).equals("loading");
|
||||
},
|
||||
({ status, error }) => {
|
||||
expect(status).equals("no-exchange");
|
||||
expect(status).equals("no-exchange-found");
|
||||
expect(error).undefined;
|
||||
},
|
||||
],
|
||||
|
@ -19,13 +19,14 @@ import { useState } from "preact/hooks";
|
||||
import { useAlertContext } from "../context/alert.js";
|
||||
import { ButtonHandler } from "../mui/handlers.js";
|
||||
|
||||
type State = State.Ready | State.NoExchange | State.Selecting;
|
||||
type State = State.Ready | State.NoExchangeFound | State.Selecting;
|
||||
|
||||
export namespace State {
|
||||
export interface NoExchange {
|
||||
status: "no-exchange";
|
||||
export interface NoExchangeFound {
|
||||
status: "no-exchange-found";
|
||||
error: undefined;
|
||||
currency: string | undefined;
|
||||
currency: string;
|
||||
defaultExchange: string | undefined;
|
||||
}
|
||||
export interface Ready {
|
||||
status: "ready";
|
||||
@ -39,7 +40,7 @@ export namespace State {
|
||||
onCancel: () => Promise<void>;
|
||||
list: ExchangeListItem[];
|
||||
currency: string;
|
||||
currentExchange: string;
|
||||
initialValue: string;
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,31 +65,35 @@ export function useSelectedExchange({
|
||||
|
||||
if (!list.length) {
|
||||
return {
|
||||
status: "no-exchange",
|
||||
status: "no-exchange-found",
|
||||
error: undefined,
|
||||
currency: undefined,
|
||||
currency,
|
||||
defaultExchange,
|
||||
};
|
||||
}
|
||||
|
||||
const listCurrency = list.filter((e) => e.currency === currency);
|
||||
if (!listCurrency.length) {
|
||||
const exchangesWithThisCurrency = list.filter((e) => e.currency === currency);
|
||||
if (!exchangesWithThisCurrency.length) {
|
||||
// there should be at least one exchange for this currency
|
||||
return {
|
||||
status: "no-exchange",
|
||||
status: "no-exchange-found",
|
||||
error: undefined,
|
||||
currency,
|
||||
defaultExchange,
|
||||
};
|
||||
}
|
||||
|
||||
if (isSelecting) {
|
||||
const currentExchange =
|
||||
selectedExchange ?? defaultExchange ?? listCurrency[0].exchangeBaseUrl;
|
||||
selectedExchange ??
|
||||
defaultExchange ??
|
||||
exchangesWithThisCurrency[0].exchangeBaseUrl;
|
||||
return {
|
||||
status: "selecting-exchange",
|
||||
error: undefined,
|
||||
list: listCurrency,
|
||||
list: exchangesWithThisCurrency,
|
||||
currency,
|
||||
currentExchange: currentExchange,
|
||||
initialValue: currentExchange,
|
||||
onSelection: async (exchangeBaseUrl: string) => {
|
||||
setIsSelecting(false);
|
||||
setSelectedExchange(exchangeBaseUrl);
|
||||
@ -131,6 +136,6 @@ export function useSelectedExchange({
|
||||
doSelect: {
|
||||
onClick: pushAlertOnError(async () => setIsSelecting(true)),
|
||||
},
|
||||
selected: listCurrency[0],
|
||||
selected: exchangesWithThisCurrency[0],
|
||||
};
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ import {
|
||||
|
||||
export interface Props {
|
||||
list: ExchangeListItem[];
|
||||
currentExchange: string;
|
||||
initialValue: string;
|
||||
onCancel: () => Promise<void>;
|
||||
onSelection: (exchange: string) => Promise<void>;
|
||||
}
|
||||
@ -50,7 +50,7 @@ export type State =
|
||||
| State.Comparing
|
||||
| State.ShowingTos
|
||||
| State.ShowingPrivacy
|
||||
| SelectExchangeState.NoExchange;
|
||||
| SelectExchangeState.NoExchangeFound;
|
||||
|
||||
export namespace State {
|
||||
export interface Loading {
|
||||
@ -102,7 +102,7 @@ const viewMapping: StateViewMap<State> = {
|
||||
loading: Loading,
|
||||
error: ErrorAlertView,
|
||||
comparing: ComparingView,
|
||||
"no-exchange": NoExchangesView,
|
||||
"no-exchange-found": NoExchangesView,
|
||||
"showing-tos": TosContentView,
|
||||
"showing-privacy": PrivacyContentView,
|
||||
ready: ReadyView,
|
||||
|
@ -30,37 +30,37 @@ export function useComponentState({
|
||||
onCancel,
|
||||
onSelection,
|
||||
list: exchanges,
|
||||
currentExchange,
|
||||
initialValue,
|
||||
}: Props): State {
|
||||
const api = useBackendContext();
|
||||
const { pushAlertOnError } = useAlertContext();
|
||||
const { i18n } = useTranslationContext();
|
||||
const initialValue = exchanges.findIndex(
|
||||
(e) => e.exchangeBaseUrl === currentExchange,
|
||||
const initialValueIdx = exchanges.findIndex(
|
||||
(e) => e.exchangeBaseUrl === initialValue,
|
||||
);
|
||||
if (initialValue === -1) {
|
||||
if (initialValueIdx === -1) {
|
||||
throw Error(
|
||||
`wrong usage of ExchangeSelection component, currentExchange '${currentExchange}' is not in the list of exchanges`,
|
||||
`wrong usage of ExchangeSelection component, currentExchange '${initialValue}' is not in the list of exchanges`,
|
||||
);
|
||||
}
|
||||
const [value, setValue] = useState(String(initialValue));
|
||||
const [value, setValue] = useState(String(initialValueIdx));
|
||||
|
||||
const selectedIdx = parseInt(value, 10);
|
||||
const selectedExchange =
|
||||
exchanges.length == 0 ? undefined : exchanges[selectedIdx];
|
||||
const selectedExchange = exchanges[selectedIdx];
|
||||
|
||||
const comparingExchanges = selectedIdx !== initialValue;
|
||||
const comparingExchanges = selectedIdx !== initialValueIdx;
|
||||
|
||||
const initialExchange = comparingExchanges
|
||||
? exchanges[initialValue]
|
||||
? exchanges[initialValueIdx]
|
||||
: undefined;
|
||||
|
||||
const hook = useAsyncAsHook(async () => {
|
||||
const selected = !selectedExchange
|
||||
? undefined
|
||||
: await api.wallet.call(WalletApiOperation.GetExchangeDetailedInfo, {
|
||||
exchangeBaseUrl: selectedExchange.exchangeBaseUrl,
|
||||
});
|
||||
const selected = await api.wallet.call(
|
||||
WalletApiOperation.GetExchangeDetailedInfo,
|
||||
{
|
||||
exchangeBaseUrl: selectedExchange.exchangeBaseUrl,
|
||||
},
|
||||
);
|
||||
|
||||
const original = !initialExchange
|
||||
? undefined
|
||||
@ -70,7 +70,7 @@ export function useComponentState({
|
||||
|
||||
return {
|
||||
exchanges,
|
||||
selected: selected?.exchange,
|
||||
selected: selected.exchange,
|
||||
original: original?.exchange,
|
||||
};
|
||||
}, [selectedExchange, initialExchange]);
|
||||
@ -98,14 +98,6 @@ export function useComponentState({
|
||||
|
||||
const { selected, original } = hook.response;
|
||||
|
||||
if (selectedExchange === undefined || !selected) {
|
||||
return {
|
||||
status: "no-exchange",
|
||||
error: undefined,
|
||||
currency: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
const exchangeMap = exchanges.reduce(
|
||||
(prev, cur, idx) => ({ ...prev, [String(idx)]: cur.exchangeBaseUrl }),
|
||||
{} as Record<string, string>,
|
||||
|
@ -20,12 +20,17 @@
|
||||
*/
|
||||
|
||||
import { tests } from "@gnu-taler/web-util/lib/index.browser";
|
||||
import { ComparingView, ReadyView } from "./views.js";
|
||||
import { ComparingView, ReadyView, NoExchangesView } from "./views.js";
|
||||
|
||||
export default {
|
||||
title: "select exchange",
|
||||
};
|
||||
|
||||
export const NoExchangeFound = tests.createExample(NoExchangesView, {
|
||||
currency: "USD",
|
||||
defaultExchange: "https://exchange.taler.ar",
|
||||
});
|
||||
|
||||
export const Bitcoin1 = tests.createExample(ReadyView, {
|
||||
exchanges: {
|
||||
list: { "0": "https://exchange.taler.ar" },
|
||||
|
@ -141,28 +141,33 @@ export function TosContentView({
|
||||
}
|
||||
|
||||
export function NoExchangesView({
|
||||
defaultExchange,
|
||||
currency,
|
||||
}: SelectExchangeState.NoExchange): VNode {
|
||||
}: SelectExchangeState.NoExchangeFound): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
if (!currency) {
|
||||
return (
|
||||
<AlertView
|
||||
alert={{
|
||||
type: "warning",
|
||||
message: i18n.str`Could not find any exchange `,
|
||||
description: i18n.str`You are trying to withdraw coins but there is no exchange and the bank didn't suggested one.`,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<AlertView
|
||||
alert={{
|
||||
type: "warning",
|
||||
message: i18n.str`Could not find any exchange `,
|
||||
description: i18n.str`You are trying to withdraw coins for the currency ${currency} but there is no exchange registered in this wallet and the bank didn't suggested one.`,
|
||||
}}
|
||||
/>
|
||||
<Fragment>
|
||||
<p>
|
||||
<AlertView
|
||||
alert={{
|
||||
type: "error",
|
||||
message: i18n.str`There is no exchange available for currency ${currency}`,
|
||||
description: i18n.str`You can add more exchanges from the settings.`,
|
||||
cause: undefined,
|
||||
context: undefined,
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
{defaultExchange && (
|
||||
<AlertView
|
||||
alert={{
|
||||
type: "warning",
|
||||
message: i18n.str`Exchange ${defaultExchange} is not available`,
|
||||
description: i18n.str`Exchange status can view accessed from the settings.`,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user