fix #7496 with unit tests
This commit is contained in:
parent
dcddc4c53a
commit
3577227cc0
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
describe("test description", () => {
|
describe("Term of service states", () => {
|
||||||
it("should assert", () => {
|
it.skip("should assert", () => {
|
||||||
expect([]).deep.equals([]);
|
expect([]).deep.equals([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -25,11 +25,10 @@ import { isFuture, parse } from "date-fns";
|
|||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
|
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
|
||||||
|
import { RecursiveState } from "../../utils/index.js";
|
||||||
import { wxApi } from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
|
|
||||||
|
|
||||||
export function useComponentState(
|
export function useComponentState(
|
||||||
{ amount: amountStr, onClose, onSuccess }: Props,
|
{ amount: amountStr, onClose, onSuccess }: Props,
|
||||||
api: typeof wxApi,
|
api: typeof wxApi,
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
describe("test description", () => {
|
describe("Invoice create state", () => {
|
||||||
it("should assert", () => {
|
it.skip("should create some tests", () => {
|
||||||
expect([]).deep.equals([]);
|
expect([]).deep.equals([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
describe("test description", () => {
|
describe("Invoice payment state", () => {
|
||||||
it("should assert", () => {
|
it.skip("should create some states", () => {
|
||||||
expect([]).deep.equals([]);
|
expect([]).deep.equals([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
describe("test description", () => {
|
describe("Transfer create states", () => {
|
||||||
it("should assert", () => {
|
it.skip("should assert", () => {
|
||||||
expect([]).deep.equals([]);
|
expect([]).deep.equals([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
describe("test description", () => {
|
describe("Transfer pickup states", () => {
|
||||||
it("should assert", () => {
|
it.skip("should assert", () => {
|
||||||
expect([]).deep.equals([]);
|
expect([]).deep.equals([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -25,11 +25,10 @@ import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
|||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
|
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
|
||||||
|
import { RecursiveState } from "../../utils/index.js";
|
||||||
import { wxApi } from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { PropsFromParams, PropsFromURI, State } from "./index.js";
|
import { PropsFromParams, PropsFromURI, State } from "./index.js";
|
||||||
|
|
||||||
type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
|
|
||||||
|
|
||||||
export function useComponentStateFromParams(
|
export function useComponentStateFromParams(
|
||||||
{ amount, cancel, onSuccess }: PropsFromParams,
|
{ amount, cancel, onSuccess }: PropsFromParams,
|
||||||
api: typeof wxApi,
|
api: typeof wxApi,
|
||||||
|
@ -80,7 +80,7 @@ export type StateViewMap<StateType extends { status: string }> = {
|
|||||||
[S in StateType as S["status"]]: StateFunc<S>;
|
[S in StateType as S["status"]]: StateFunc<S>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
|
export type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
|
||||||
|
|
||||||
export function compose<SType extends { status: string }, PType>(
|
export function compose<SType extends { status: string }, PType>(
|
||||||
name: string,
|
name: string,
|
||||||
|
@ -48,17 +48,13 @@ import { BackupPage } from "./BackupPage.js";
|
|||||||
import { DepositPage } from "./DepositPage/index.js";
|
import { DepositPage } from "./DepositPage/index.js";
|
||||||
import { ExchangeAddPage } from "./ExchangeAddPage.js";
|
import { ExchangeAddPage } from "./ExchangeAddPage.js";
|
||||||
import { HistoryPage } from "./History.js";
|
import { HistoryPage } from "./History.js";
|
||||||
import { ProviderAddPage } from "./ProviderAddPage.js";
|
|
||||||
import { ProviderDetailPage } from "./ProviderDetailPage.js";
|
import { ProviderDetailPage } from "./ProviderDetailPage.js";
|
||||||
import { SettingsPage } from "./Settings.js";
|
import { SettingsPage } from "./Settings.js";
|
||||||
import { TransactionPage } from "./Transaction.js";
|
import { TransactionPage } from "./Transaction.js";
|
||||||
import { WelcomePage } from "./Welcome.js";
|
import { WelcomePage } from "./Welcome.js";
|
||||||
import { QrReaderPage } from "./QrReader.js";
|
import { QrReaderPage } from "./QrReader.js";
|
||||||
import { platform } from "../platform/api.js";
|
import { platform } from "../platform/api.js";
|
||||||
import {
|
import { DestinationSelectionPage } from "./DestinationSelection/index.js";
|
||||||
DestinationSelectionGetCash,
|
|
||||||
DestinationSelectionSendCash,
|
|
||||||
} from "./DestinationSelection.js";
|
|
||||||
import { ExchangeSelectionPage } from "./ExchangeSelection/index.js";
|
import { ExchangeSelectionPage } from "./ExchangeSelection/index.js";
|
||||||
import { TransferCreatePage } from "../cta/TransferCreate/index.js";
|
import { TransferCreatePage } from "../cta/TransferCreate/index.js";
|
||||||
import { InvoiceCreatePage } from "../cta/InvoiceCreate/index.js";
|
import { InvoiceCreatePage } from "../cta/InvoiceCreate/index.js";
|
||||||
@ -153,7 +149,8 @@ export function Application(): VNode {
|
|||||||
<Route path={Pages.exchanges} component={ExchangeSelectionPage} />
|
<Route path={Pages.exchanges} component={ExchangeSelectionPage} />
|
||||||
<Route
|
<Route
|
||||||
path={Pages.sendCash.pattern}
|
path={Pages.sendCash.pattern}
|
||||||
component={DestinationSelectionSendCash}
|
type="send"
|
||||||
|
component={DestinationSelectionPage}
|
||||||
goToWalletBankDeposit={(amount: string) =>
|
goToWalletBankDeposit={(amount: string) =>
|
||||||
redirectTo(Pages.balanceDeposit({ amount }))
|
redirectTo(Pages.balanceDeposit({ amount }))
|
||||||
}
|
}
|
||||||
@ -163,7 +160,8 @@ export function Application(): VNode {
|
|||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={Pages.receiveCash.pattern}
|
path={Pages.receiveCash.pattern}
|
||||||
component={DestinationSelectionGetCash}
|
type="get"
|
||||||
|
component={DestinationSelectionPage}
|
||||||
goToWalletManualWithdraw={(amount?: string) =>
|
goToWalletManualWithdraw={(amount?: string) =>
|
||||||
redirectTo(Pages.ctaWithdrawManual({ amount }))
|
redirectTo(Pages.ctaWithdrawManual({ amount }))
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2022 Taler Systems S.A.
|
||||||
|
|
||||||
|
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||||
|
terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 3, or (at your option) any later version.
|
||||||
|
|
||||||
|
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Loading } from "../../components/Loading.js";
|
||||||
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
|
import { AmountFieldHandler, ButtonHandler } from "../../mui/handlers.js";
|
||||||
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
|
import { wxApi } from "../../wxApi.js";
|
||||||
|
import { useComponentState } from "./state.js";
|
||||||
|
import { LoadingUriView, ReadyView, SelectCurrencyView } from "./views.js";
|
||||||
|
|
||||||
|
export type Props = PropsGet | PropsSend;
|
||||||
|
|
||||||
|
interface PropsGet {
|
||||||
|
type: "get";
|
||||||
|
amount?: string;
|
||||||
|
goToWalletManualWithdraw: (amount: string) => void;
|
||||||
|
goToWalletWalletInvoice: (amount: string) => void;
|
||||||
|
}
|
||||||
|
interface PropsSend {
|
||||||
|
type: "send";
|
||||||
|
amount?: string;
|
||||||
|
goToWalletBankDeposit: (amount: string) => void;
|
||||||
|
goToWalletWalletSend: (amount: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type State =
|
||||||
|
| State.Loading
|
||||||
|
| State.LoadingUriError
|
||||||
|
| State.Ready
|
||||||
|
| State.SelectCurrency;
|
||||||
|
|
||||||
|
export namespace State {
|
||||||
|
export interface Loading {
|
||||||
|
status: "loading";
|
||||||
|
error: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoadingUriError {
|
||||||
|
status: "loading-error";
|
||||||
|
error: HookError;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SelectCurrency {
|
||||||
|
status: "select-currency";
|
||||||
|
error: undefined;
|
||||||
|
currencies: Record<string, string>;
|
||||||
|
onCurrencySelected: (currency: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Ready {
|
||||||
|
status: "ready";
|
||||||
|
error: undefined;
|
||||||
|
type: Props["type"];
|
||||||
|
selectCurrency: ButtonHandler;
|
||||||
|
previous: Contact[];
|
||||||
|
goToBank: ButtonHandler;
|
||||||
|
goToWallet: ButtonHandler;
|
||||||
|
amountHandler: AmountFieldHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Contact = {
|
||||||
|
icon: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewMapping: StateViewMap<State> = {
|
||||||
|
loading: Loading,
|
||||||
|
"loading-error": LoadingUriView,
|
||||||
|
"select-currency": SelectCurrencyView,
|
||||||
|
ready: ReadyView,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DestinationSelectionPage = compose(
|
||||||
|
"DestinationSelectionPage",
|
||||||
|
(p: Props) => useComponentState(p, wxApi),
|
||||||
|
viewMapping,
|
||||||
|
);
|
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2022 Taler Systems S.A.
|
||||||
|
|
||||||
|
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||||
|
terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 3, or (at your option) any later version.
|
||||||
|
|
||||||
|
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Amounts } from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
|
import { useState } from "preact/hooks";
|
||||||
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
|
import { assertUnreachable, RecursiveState } from "../../utils/index.js";
|
||||||
|
import { wxApi } from "../../wxApi.js";
|
||||||
|
import { Contact, Props, State } from "./index.js";
|
||||||
|
import bankIcon from "../../svg/ri-bank-line.svg";
|
||||||
|
|
||||||
|
export function useComponentState(
|
||||||
|
props: Props,
|
||||||
|
api: typeof wxApi,
|
||||||
|
): RecursiveState<State> {
|
||||||
|
const parsedInitialAmount = !props.amount
|
||||||
|
? undefined
|
||||||
|
: Amounts.parse(props.amount);
|
||||||
|
|
||||||
|
// const initialCurrency = parsedInitialAmount?.currency;
|
||||||
|
|
||||||
|
const [amount, setAmount] = useState(
|
||||||
|
!parsedInitialAmount ? undefined : parsedInitialAmount,
|
||||||
|
);
|
||||||
|
|
||||||
|
//FIXME: get this information from wallet
|
||||||
|
// eslint-disable-next-line no-constant-condition
|
||||||
|
const previous: Contact[] = true
|
||||||
|
? []
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
name: "International Bank",
|
||||||
|
icon: bankIcon, //FIXME: should be decided in the view
|
||||||
|
description: "account ending with 3454",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Max",
|
||||||
|
icon: bankIcon,
|
||||||
|
description: "account ending with 3454",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Alex",
|
||||||
|
icon: bankIcon,
|
||||||
|
description: "account ending with 3454",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!amount) {
|
||||||
|
return () => {
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
const hook = useAsyncAsHook(() =>
|
||||||
|
api.wallet.call(WalletApiOperation.ListExchanges, {}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!hook) {
|
||||||
|
return {
|
||||||
|
status: "loading",
|
||||||
|
error: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (hook.hasError) {
|
||||||
|
return {
|
||||||
|
status: "loading-error",
|
||||||
|
error: hook,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const currencies: Record<string, string> = {};
|
||||||
|
hook.response.exchanges.forEach((e) => {
|
||||||
|
if (e.currency) {
|
||||||
|
currencies[e.currency] = e.currency;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
currencies[""] = "Select a currency";
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: "select-currency",
|
||||||
|
error: undefined,
|
||||||
|
onCurrencySelected: (c: string) => {
|
||||||
|
setAmount(Amounts.zeroOfCurrency(c));
|
||||||
|
},
|
||||||
|
currencies,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const currencyAndAmount = Amounts.stringify(amount);
|
||||||
|
const invalid = Amounts.isZero(amount);
|
||||||
|
|
||||||
|
switch (props.type) {
|
||||||
|
case "send":
|
||||||
|
return {
|
||||||
|
status: "ready",
|
||||||
|
error: undefined,
|
||||||
|
previous,
|
||||||
|
selectCurrency: {
|
||||||
|
onClick: async () => {
|
||||||
|
setAmount(undefined);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
goToBank: {
|
||||||
|
onClick: invalid
|
||||||
|
? undefined
|
||||||
|
: async () => {
|
||||||
|
props.goToWalletBankDeposit(currencyAndAmount);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
goToWallet: {
|
||||||
|
onClick: invalid
|
||||||
|
? undefined
|
||||||
|
: async () => {
|
||||||
|
props.goToWalletWalletSend(currencyAndAmount);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
amountHandler: {
|
||||||
|
onInput: async (s) => setAmount(s),
|
||||||
|
value: amount,
|
||||||
|
},
|
||||||
|
type: props.type,
|
||||||
|
};
|
||||||
|
case "get":
|
||||||
|
return {
|
||||||
|
status: "ready",
|
||||||
|
error: undefined,
|
||||||
|
previous,
|
||||||
|
selectCurrency: {
|
||||||
|
onClick: async () => {
|
||||||
|
setAmount(undefined);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
goToBank: {
|
||||||
|
onClick: invalid
|
||||||
|
? undefined
|
||||||
|
: async () => {
|
||||||
|
props.goToWalletManualWithdraw(currencyAndAmount);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
goToWallet: {
|
||||||
|
onClick: invalid
|
||||||
|
? undefined
|
||||||
|
: async () => {
|
||||||
|
props.goToWalletWalletInvoice(currencyAndAmount);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
amountHandler: {
|
||||||
|
onInput: async (s) => setAmount(s),
|
||||||
|
value: amount,
|
||||||
|
},
|
||||||
|
type: props.type,
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
assertUnreachable(props);
|
||||||
|
}
|
||||||
|
}
|
@ -19,25 +19,44 @@
|
|||||||
* @author Sebastian Javier Marchano (sebasjm)
|
* @author Sebastian Javier Marchano (sebasjm)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createExample } from "../test-utils.js";
|
import { createExample } from "../../test-utils.js";
|
||||||
import {
|
import { ReadyView, SelectCurrencyView } from "./views.js";
|
||||||
DestinationSelectionGetCash,
|
|
||||||
DestinationSelectionSendCash,
|
|
||||||
SelectCurrencyView,
|
|
||||||
} from "./DestinationSelection.js";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: "wallet/destination",
|
title: "wallet/destination",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GetCash = createExample(DestinationSelectionGetCash, {
|
export const GetCash = createExample(ReadyView, {
|
||||||
amount: "usd:0",
|
amountHandler: {
|
||||||
|
value: {
|
||||||
|
currency: "EUR",
|
||||||
|
fraction: 0,
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
goToBank: {},
|
||||||
|
goToWallet: {},
|
||||||
|
previous: [],
|
||||||
|
selectCurrency: {},
|
||||||
|
type: "get",
|
||||||
});
|
});
|
||||||
export const SendCash = createExample(DestinationSelectionSendCash, {
|
export const SendCash = createExample(ReadyView, {
|
||||||
amount: "eur:1",
|
amountHandler: {
|
||||||
|
value: {
|
||||||
|
currency: "EUR",
|
||||||
|
fraction: 0,
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
goToBank: {},
|
||||||
|
goToWallet: {},
|
||||||
|
previous: [],
|
||||||
|
selectCurrency: {},
|
||||||
|
type: "send",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const SelectCurrency = createExample(SelectCurrencyView, {
|
export const SelectCurrency = createExample(SelectCurrencyView, {
|
||||||
list: {
|
currencies: {
|
||||||
"": "Select a currency",
|
"": "Select a currency",
|
||||||
USD: "USD",
|
USD: "USD",
|
||||||
},
|
},
|
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2022 Taler Systems S.A.
|
||||||
|
|
||||||
|
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||||
|
terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 3, or (at your option) any later version.
|
||||||
|
|
||||||
|
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Javier Marchano (sebasjm)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
Amounts,
|
||||||
|
ExchangeEntryStatus,
|
||||||
|
ExchangeListItem,
|
||||||
|
ExchangeTosStatus,
|
||||||
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
|
import { expect } from "chai";
|
||||||
|
import { createWalletApiMock, mountHook } from "../../test-utils.js";
|
||||||
|
import { useComponentState } from "./state.js";
|
||||||
|
|
||||||
|
const exchangeArs: ExchangeListItem = {
|
||||||
|
currency: "ARS",
|
||||||
|
exchangeBaseUrl: "http://",
|
||||||
|
tosStatus: ExchangeTosStatus.Accepted,
|
||||||
|
exchangeStatus: ExchangeEntryStatus.Ok,
|
||||||
|
paytoUris: [],
|
||||||
|
permanent: true,
|
||||||
|
ageRestrictionOptions: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("Destination selection states", () => {
|
||||||
|
it("should select currency if no amount specified", async () => {
|
||||||
|
const { handler, mock } = createWalletApiMock();
|
||||||
|
|
||||||
|
handler.addWalletCallResponse(
|
||||||
|
WalletApiOperation.ListExchanges,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
exchanges: [exchangeArs],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
type: "get" as const,
|
||||||
|
goToWalletManualWithdraw: () => {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
goToWalletWalletInvoice: () => {
|
||||||
|
null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
|
mountHook(() => useComponentState(props, mock));
|
||||||
|
|
||||||
|
{
|
||||||
|
const state = pullLastResultOrThrow();
|
||||||
|
|
||||||
|
if (state.status !== "loading") expect.fail();
|
||||||
|
if (state.error) expect.fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
|
{
|
||||||
|
const state = pullLastResultOrThrow();
|
||||||
|
|
||||||
|
if (state.status !== "select-currency") expect.fail();
|
||||||
|
if (state.error) expect.fail();
|
||||||
|
expect(state.currencies).deep.eq({
|
||||||
|
ARS: "ARS",
|
||||||
|
"": "Select a currency",
|
||||||
|
});
|
||||||
|
|
||||||
|
state.onCurrencySelected(exchangeArs.currency!);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
|
{
|
||||||
|
const state = pullLastResultOrThrow();
|
||||||
|
|
||||||
|
if (state.status !== "ready") expect.fail();
|
||||||
|
if (state.error) expect.fail();
|
||||||
|
expect(state.goToBank.onClick).eq(undefined);
|
||||||
|
expect(state.goToWallet.onClick).eq(undefined);
|
||||||
|
|
||||||
|
expect(state.amountHandler.value).deep.eq(Amounts.parseOrThrow("ARS:0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be possible to start with an amount specified in request params", async () => {
|
||||||
|
const { handler, mock } = createWalletApiMock();
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
type: "get" as const,
|
||||||
|
goToWalletManualWithdraw: () => {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
goToWalletWalletInvoice: () => {
|
||||||
|
null;
|
||||||
|
},
|
||||||
|
amount: "ARS:2",
|
||||||
|
};
|
||||||
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
|
mountHook(() => useComponentState(props, mock));
|
||||||
|
|
||||||
|
{
|
||||||
|
const state = pullLastResultOrThrow();
|
||||||
|
|
||||||
|
if (state.status !== "ready") expect.fail();
|
||||||
|
if (state.error) expect.fail();
|
||||||
|
expect(state.goToBank.onClick).not.eq(undefined);
|
||||||
|
expect(state.goToWallet.onClick).not.eq(undefined);
|
||||||
|
|
||||||
|
expect(state.amountHandler.value).deep.eq(Amounts.parseOrThrow("ARS:2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty");
|
||||||
|
});
|
||||||
|
});
|
@ -14,30 +14,70 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Amounts } from "@gnu-taler/taler-util";
|
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
|
||||||
import { styled } from "@linaria/react";
|
import { styled } from "@linaria/react";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { LoadingError } from "../../components/LoadingError.js";
|
||||||
import { AmountField } from "../components/AmountField.js";
|
import { SelectList } from "../../components/SelectList.js";
|
||||||
import { Loading } from "../components/Loading.js";
|
|
||||||
import { LoadingError } from "../components/LoadingError.js";
|
|
||||||
import { SelectList } from "../components/SelectList.js";
|
|
||||||
import {
|
import {
|
||||||
Input,
|
Input,
|
||||||
LightText,
|
LightText,
|
||||||
LinkPrimary,
|
LinkPrimary,
|
||||||
SvgIcon,
|
SvgIcon,
|
||||||
} from "../components/styled/index.js";
|
} from "../../components/styled/index.js";
|
||||||
import { useTranslationContext } from "../context/translation.js";
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { Pages } from "../../NavigationBar.js";
|
||||||
import { Button } from "../mui/Button.js";
|
import { Contact, State } from "./index.js";
|
||||||
import { Grid } from "../mui/Grid.js";
|
import arrowIcon from "../../svg/chevron-down.svg";
|
||||||
import { Paper } from "../mui/Paper.js";
|
import { AmountField } from "../../components/AmountField.js";
|
||||||
import { Pages } from "../NavigationBar.js";
|
import { Grid } from "../../mui/Grid.js";
|
||||||
import arrowIcon from "../svg/chevron-down.svg";
|
import { Paper } from "../../mui/Paper.js";
|
||||||
import bankIcon from "../svg/ri-bank-line.svg";
|
import { Button } from "../../mui/Button.js";
|
||||||
import { wxApi } from "../wxApi.js";
|
import { assertUnreachable } from "../../utils/index.js";
|
||||||
|
|
||||||
|
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
|
return (
|
||||||
|
<LoadingError
|
||||||
|
title={<i18n.Translate>Could not load</i18n.Translate>}
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SelectCurrencyView({
|
||||||
|
currencies,
|
||||||
|
onCurrencySelected,
|
||||||
|
}: State.SelectCurrency): VNode {
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<h2>
|
||||||
|
<i18n.Translate>
|
||||||
|
Choose a currency to proceed or add another exchange
|
||||||
|
</i18n.Translate>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<Input>
|
||||||
|
<SelectList
|
||||||
|
label={<i18n.Translate>Known currencies</i18n.Translate>}
|
||||||
|
list={currencies}
|
||||||
|
name="lang"
|
||||||
|
value={""}
|
||||||
|
onChange={(v) => onCurrencySelected(v)}
|
||||||
|
/>
|
||||||
|
</Input>
|
||||||
|
</p>
|
||||||
|
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
||||||
|
<div />
|
||||||
|
<LinkPrimary href={Pages.settingsExchangeAdd({})}>
|
||||||
|
<i18n.Translate>Add an exchange</i18n.Translate>
|
||||||
|
</LinkPrimary>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -47,23 +87,6 @@ const Container = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
interface PropsGet {
|
|
||||||
amount?: string;
|
|
||||||
goToWalletManualWithdraw: (amount: string) => void;
|
|
||||||
goToWalletWalletInvoice: (amount: string) => void;
|
|
||||||
}
|
|
||||||
interface PropsSend {
|
|
||||||
amount?: string;
|
|
||||||
goToWalletBankDeposit: (amount: string) => void;
|
|
||||||
goToWalletWalletSend: (amount: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
type Contact = {
|
|
||||||
icon: string;
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ContactTable = styled.table`
|
const ContactTable = styled.table`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
& > tr > td {
|
& > tr > td {
|
||||||
@ -165,73 +188,193 @@ const CircleDiv = styled.div`
|
|||||||
border: none;
|
border: none;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function SelectCurrency({
|
export function ReadyView(props: State.Ready): VNode {
|
||||||
onChange,
|
switch (props.type) {
|
||||||
}: {
|
case "get":
|
||||||
onChange: (s: string) => void;
|
return ReadyGetView(props);
|
||||||
}): VNode {
|
case "send":
|
||||||
const { i18n } = useTranslationContext();
|
return ReadySendView(props);
|
||||||
|
default:
|
||||||
const hook = useAsyncAsHook(() =>
|
assertUnreachable(props.type);
|
||||||
wxApi.wallet.call(WalletApiOperation.ListExchanges, {}),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!hook) {
|
|
||||||
return <Loading />;
|
|
||||||
}
|
}
|
||||||
if (hook.hasError) {
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
error={hook}
|
|
||||||
title={<i18n.Translate>Could not load list of exchange</i18n.Translate>}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const list: Record<string, string> = {};
|
|
||||||
hook.response.exchanges.forEach((e) => {
|
|
||||||
if (e.currency) {
|
|
||||||
list[e.currency] = e.currency;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
list[""] = "Select a currency";
|
|
||||||
return <SelectCurrencyView onChange={onChange} list={list} />;
|
|
||||||
}
|
}
|
||||||
|
export function ReadyGetView({
|
||||||
export function SelectCurrencyView({
|
amountHandler,
|
||||||
onChange,
|
goToBank,
|
||||||
list,
|
goToWallet,
|
||||||
}: {
|
selectCurrency,
|
||||||
onChange: (s: string) => void;
|
previous,
|
||||||
list: Record<string, string>;
|
}: State.Ready): VNode {
|
||||||
}): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Container>
|
||||||
<h2>
|
<h1>
|
||||||
<i18n.Translate>
|
<i18n.Translate>Specify the amount and the origin</i18n.Translate>
|
||||||
Choose a currency to proceed or add another exchange
|
</h1>
|
||||||
</i18n.Translate>
|
<Grid container columns={2} justifyContent="space-between">
|
||||||
</h2>
|
<AmountField
|
||||||
|
label={<i18n.Translate>Amount</i18n.Translate>}
|
||||||
|
required
|
||||||
|
handler={amountHandler}
|
||||||
|
/>
|
||||||
|
<Button onClick={selectCurrency.onClick}>
|
||||||
|
<i18n.Translate>Change currency</i18n.Translate>
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<p>
|
<Grid container spacing={1} columns={1}>
|
||||||
<Input>
|
{previous.length > 0 ? (
|
||||||
<SelectList
|
<Fragment>
|
||||||
label={<i18n.Translate>Known currencies</i18n.Translate>}
|
<p>
|
||||||
list={list}
|
<i18n.Translate>Use previous origins:</i18n.Translate>
|
||||||
name="lang"
|
</p>
|
||||||
value={""}
|
<Grid item xs={1}>
|
||||||
onChange={(v) => onChange(v)}
|
<Paper style={{ padding: 8 }}>
|
||||||
/>
|
<ContactTable>
|
||||||
</Input>
|
{previous.map((info, i) => (
|
||||||
</p>
|
<tr key={i}>
|
||||||
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
<td>
|
||||||
<div />
|
<RowExample
|
||||||
<LinkPrimary href={Pages.settingsExchangeAdd({})}>
|
info={info}
|
||||||
<i18n.Translate>Add an exchange</i18n.Translate>
|
disabled={!amountHandler.onInput}
|
||||||
</LinkPrimary>
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</ContactTable>
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
</Fragment>
|
||||||
|
) : undefined}
|
||||||
|
{previous.length > 0 ? (
|
||||||
|
<Grid item>
|
||||||
|
<p>
|
||||||
|
<i18n.Translate>
|
||||||
|
Or specify the origin of the money
|
||||||
|
</i18n.Translate>
|
||||||
|
</p>
|
||||||
|
</Grid>
|
||||||
|
) : (
|
||||||
|
<Grid item>
|
||||||
|
<p>
|
||||||
|
<i18n.Translate>Specify the origin of the money</i18n.Translate>
|
||||||
|
</p>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
<Grid item container columns={2} spacing={1}>
|
||||||
|
<Grid item xs={1}>
|
||||||
|
<Paper style={{ padding: 8 }}>
|
||||||
|
<p>
|
||||||
|
<i18n.Translate>From my bank account</i18n.Translate>
|
||||||
|
</p>
|
||||||
|
<Button onClick={goToBank.onClick}>
|
||||||
|
<i18n.Translate>Withdraw</i18n.Translate>
|
||||||
|
</Button>
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={1}>
|
||||||
|
<Paper style={{ padding: 8 }}>
|
||||||
|
<p>
|
||||||
|
<i18n.Translate>From another wallet</i18n.Translate>
|
||||||
|
</p>
|
||||||
|
<Button onClick={goToWallet.onClick}>
|
||||||
|
<i18n.Translate>Invoice</i18n.Translate>
|
||||||
|
</Button>
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export function ReadySendView({
|
||||||
|
amountHandler,
|
||||||
|
goToBank,
|
||||||
|
goToWallet,
|
||||||
|
previous,
|
||||||
|
}: State.Ready): VNode {
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<h1>
|
||||||
|
<i18n.Translate>Specify the amount and the destination</i18n.Translate>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<AmountField
|
||||||
|
label={<i18n.Translate>Amount</i18n.Translate>}
|
||||||
|
required
|
||||||
|
handler={amountHandler}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Fragment>
|
|
||||||
|
<Grid container spacing={1} columns={1}>
|
||||||
|
{previous.length > 0 ? (
|
||||||
|
<Fragment>
|
||||||
|
<p>
|
||||||
|
<i18n.Translate>Use previous destinations:</i18n.Translate>
|
||||||
|
</p>
|
||||||
|
<Grid item xs={1}>
|
||||||
|
<Paper style={{ padding: 8 }}>
|
||||||
|
<ContactTable>
|
||||||
|
{previous.map((info, i) => (
|
||||||
|
<tr key={i}>
|
||||||
|
<td>
|
||||||
|
<RowExample
|
||||||
|
info={info}
|
||||||
|
disabled={!amountHandler.onInput}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</ContactTable>
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
</Fragment>
|
||||||
|
) : undefined}
|
||||||
|
{previous.length > 0 ? (
|
||||||
|
<Grid item>
|
||||||
|
<p>
|
||||||
|
<i18n.Translate>
|
||||||
|
Or specify the destination of the money
|
||||||
|
</i18n.Translate>
|
||||||
|
</p>
|
||||||
|
</Grid>
|
||||||
|
) : (
|
||||||
|
<Grid item>
|
||||||
|
<p>
|
||||||
|
<i18n.Translate>
|
||||||
|
Specify the destination of the money
|
||||||
|
</i18n.Translate>
|
||||||
|
</p>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
<Grid item container columns={2} spacing={1}>
|
||||||
|
<Grid item xs={1}>
|
||||||
|
<Paper style={{ padding: 8 }}>
|
||||||
|
<p>
|
||||||
|
<i18n.Translate>To my bank account</i18n.Translate>
|
||||||
|
</p>
|
||||||
|
<Button onClick={goToBank.onClick}>
|
||||||
|
<i18n.Translate>Deposit</i18n.Translate>
|
||||||
|
</Button>
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={1}>
|
||||||
|
<Paper style={{ padding: 8 }}>
|
||||||
|
<p>
|
||||||
|
<i18n.Translate>To another wallet</i18n.Translate>
|
||||||
|
</p>
|
||||||
|
<Button onClick={goToWallet.onClick}>
|
||||||
|
<i18n.Translate>Send</i18n.Translate>
|
||||||
|
</Button>
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,271 +411,3 @@ function RowExample({
|
|||||||
</MediaExample>
|
</MediaExample>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DestinationSelectionGetCash({
|
|
||||||
amount: initialAmount,
|
|
||||||
goToWalletManualWithdraw,
|
|
||||||
goToWalletWalletInvoice,
|
|
||||||
}: PropsGet): VNode {
|
|
||||||
const parsedInitialAmount = !initialAmount
|
|
||||||
? undefined
|
|
||||||
: Amounts.parse(initialAmount);
|
|
||||||
|
|
||||||
const [currency, setCurrency] = useState(parsedInitialAmount?.currency);
|
|
||||||
|
|
||||||
const [amount, setAmount] = useState(
|
|
||||||
parsedInitialAmount ?? Amounts.zeroOfCurrency(currency ?? "KUDOS"),
|
|
||||||
);
|
|
||||||
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
const previous1: Contact[] = [];
|
|
||||||
const previous2: Contact[] = [
|
|
||||||
{
|
|
||||||
name: "International Bank",
|
|
||||||
icon: bankIcon,
|
|
||||||
description: "account ending with 3454",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Max",
|
|
||||||
icon: bankIcon,
|
|
||||||
description: "account ending with 3454",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Alex",
|
|
||||||
icon: bankIcon,
|
|
||||||
description: "account ending with 3454",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const previous = previous1;
|
|
||||||
|
|
||||||
if (!currency) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SelectCurrency onChange={(c) => setCurrency(c)} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const currencyAndAmount = Amounts.stringify(amount);
|
|
||||||
const invalid = Amounts.isZero(amount);
|
|
||||||
return (
|
|
||||||
<Container>
|
|
||||||
<h1>
|
|
||||||
<i18n.Translate>Specify the amount and the origin</i18n.Translate>
|
|
||||||
</h1>
|
|
||||||
<Grid container columns={2} justifyContent="space-between">
|
|
||||||
<AmountField
|
|
||||||
label={<i18n.Translate>Amount</i18n.Translate>}
|
|
||||||
required
|
|
||||||
handler={{
|
|
||||||
onInput: async (s) => setAmount(s),
|
|
||||||
value: amount,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Button onClick={async () => setCurrency(undefined)}>
|
|
||||||
<i18n.Translate>Change currency</i18n.Translate>
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid container spacing={1} columns={1}>
|
|
||||||
{previous.length > 0 ? (
|
|
||||||
<Fragment>
|
|
||||||
<p>
|
|
||||||
<i18n.Translate>Use previous origins:</i18n.Translate>
|
|
||||||
</p>
|
|
||||||
<Grid item xs={1}>
|
|
||||||
<Paper style={{ padding: 8 }}>
|
|
||||||
<ContactTable>
|
|
||||||
{previous.map((info, i) => (
|
|
||||||
<tr key={i}>
|
|
||||||
<td>
|
|
||||||
<RowExample info={info} disabled={invalid} />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</ContactTable>
|
|
||||||
</Paper>
|
|
||||||
</Grid>
|
|
||||||
</Fragment>
|
|
||||||
) : undefined}
|
|
||||||
{previous.length > 0 ? (
|
|
||||||
<Grid item>
|
|
||||||
<p>
|
|
||||||
<i18n.Translate>
|
|
||||||
Or specify the origin of the money
|
|
||||||
</i18n.Translate>
|
|
||||||
</p>
|
|
||||||
</Grid>
|
|
||||||
) : (
|
|
||||||
<Grid item>
|
|
||||||
<p>
|
|
||||||
<i18n.Translate>Specify the origin of the money</i18n.Translate>
|
|
||||||
</p>
|
|
||||||
</Grid>
|
|
||||||
)}
|
|
||||||
<Grid item container columns={2} spacing={1}>
|
|
||||||
<Grid item xs={1}>
|
|
||||||
<Paper style={{ padding: 8 }}>
|
|
||||||
<p>
|
|
||||||
<i18n.Translate>From my bank account</i18n.Translate>
|
|
||||||
</p>
|
|
||||||
<Button
|
|
||||||
disabled={invalid}
|
|
||||||
onClick={async () =>
|
|
||||||
goToWalletManualWithdraw(currencyAndAmount)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<i18n.Translate>Withdraw</i18n.Translate>
|
|
||||||
</Button>
|
|
||||||
</Paper>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={1}>
|
|
||||||
<Paper style={{ padding: 8 }}>
|
|
||||||
<p>
|
|
||||||
<i18n.Translate>From another wallet</i18n.Translate>
|
|
||||||
</p>
|
|
||||||
<Button
|
|
||||||
disabled={invalid}
|
|
||||||
onClick={async () => goToWalletWalletInvoice(currencyAndAmount)}
|
|
||||||
>
|
|
||||||
<i18n.Translate>Invoice</i18n.Translate>
|
|
||||||
</Button>
|
|
||||||
</Paper>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function DestinationSelectionSendCash({
|
|
||||||
amount: initialAmount,
|
|
||||||
goToWalletBankDeposit,
|
|
||||||
goToWalletWalletSend,
|
|
||||||
}: PropsSend): VNode {
|
|
||||||
const parsedInitialAmount = !initialAmount
|
|
||||||
? undefined
|
|
||||||
: Amounts.parse(initialAmount);
|
|
||||||
|
|
||||||
const currency = parsedInitialAmount?.currency;
|
|
||||||
|
|
||||||
const [amount, setAmount] = useState(
|
|
||||||
parsedInitialAmount ?? Amounts.zeroOfCurrency(currency ?? "KUDOS"),
|
|
||||||
);
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
const previous1: Contact[] = [];
|
|
||||||
const previous2: Contact[] = [
|
|
||||||
{
|
|
||||||
name: "International Bank",
|
|
||||||
icon: bankIcon,
|
|
||||||
description: "account ending with 3454",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Max",
|
|
||||||
icon: bankIcon,
|
|
||||||
description: "account ending with 3454",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Alex",
|
|
||||||
icon: bankIcon,
|
|
||||||
description: "account ending with 3454",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const previous = previous1;
|
|
||||||
|
|
||||||
if (!currency) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<i18n.Translate>currency not provided</i18n.Translate>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const currencyAndAmount = Amounts.stringify(amount);
|
|
||||||
//const parsedAmount = Amounts.parse(currencyAndAmount);
|
|
||||||
const invalid = Amounts.isZero(amount);
|
|
||||||
return (
|
|
||||||
<Container>
|
|
||||||
<h1>
|
|
||||||
<i18n.Translate>Specify the amount and the destination</i18n.Translate>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<AmountField
|
|
||||||
label={<i18n.Translate>Amount</i18n.Translate>}
|
|
||||||
required
|
|
||||||
handler={{
|
|
||||||
onInput: async (s) => setAmount(s),
|
|
||||||
value: amount,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Grid container spacing={1} columns={1}>
|
|
||||||
{previous.length > 0 ? (
|
|
||||||
<Fragment>
|
|
||||||
<p>
|
|
||||||
<i18n.Translate>Use previous destinations:</i18n.Translate>
|
|
||||||
</p>
|
|
||||||
<Grid item xs={1}>
|
|
||||||
<Paper style={{ padding: 8 }}>
|
|
||||||
<ContactTable>
|
|
||||||
{previous.map((info, i) => (
|
|
||||||
<tr key={i}>
|
|
||||||
<td>
|
|
||||||
<RowExample info={info} disabled={invalid} />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</ContactTable>
|
|
||||||
</Paper>
|
|
||||||
</Grid>
|
|
||||||
</Fragment>
|
|
||||||
) : undefined}
|
|
||||||
{previous.length > 0 ? (
|
|
||||||
<Grid item>
|
|
||||||
<p>
|
|
||||||
<i18n.Translate>
|
|
||||||
Or specify the destination of the money
|
|
||||||
</i18n.Translate>
|
|
||||||
</p>
|
|
||||||
</Grid>
|
|
||||||
) : (
|
|
||||||
<Grid item>
|
|
||||||
<p>
|
|
||||||
<i18n.Translate>
|
|
||||||
Specify the destination of the money
|
|
||||||
</i18n.Translate>
|
|
||||||
</p>
|
|
||||||
</Grid>
|
|
||||||
)}
|
|
||||||
<Grid item container columns={2} spacing={1}>
|
|
||||||
<Grid item xs={1}>
|
|
||||||
<Paper style={{ padding: 8 }}>
|
|
||||||
<p>
|
|
||||||
<i18n.Translate>To my bank account</i18n.Translate>
|
|
||||||
</p>
|
|
||||||
<Button
|
|
||||||
disabled={invalid}
|
|
||||||
onClick={async () => goToWalletBankDeposit(currencyAndAmount)}
|
|
||||||
>
|
|
||||||
<i18n.Translate>Deposit</i18n.Translate>
|
|
||||||
</Button>
|
|
||||||
</Paper>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={1}>
|
|
||||||
<Paper style={{ padding: 8 }}>
|
|
||||||
<p>
|
|
||||||
<i18n.Translate>To another wallet</i18n.Translate>
|
|
||||||
</p>
|
|
||||||
<Button
|
|
||||||
disabled={invalid}
|
|
||||||
onClick={async () => goToWalletWalletSend(currencyAndAmount)}
|
|
||||||
>
|
|
||||||
<i18n.Translate>Send</i18n.Translate>
|
|
||||||
</Button>
|
|
||||||
</Paper>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
|
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
describe("test description", () => {
|
describe("Manage Account states", () => {
|
||||||
it("should assert", () => {
|
it.skip("should create some tests", () => {
|
||||||
expect([]).deep.equals([]);
|
expect([]).deep.equals([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
describe("test description", () => {
|
describe("Notifications states", () => {
|
||||||
it("should assert", () => {
|
it.skip("should create some tests", () => {
|
||||||
expect([]).deep.equals([]);
|
expect([]).deep.equals([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -33,7 +33,7 @@ import * as a14 from "./Welcome.stories.js";
|
|||||||
import * as a15 from "./AddNewActionView.stories.js";
|
import * as a15 from "./AddNewActionView.stories.js";
|
||||||
import * as a16 from "./DeveloperPage.stories.js";
|
import * as a16 from "./DeveloperPage.stories.js";
|
||||||
import * as a17 from "./QrReader.stories.js";
|
import * as a17 from "./QrReader.stories.js";
|
||||||
import * as a18 from "./DestinationSelection.stories.js";
|
import * as a18 from "./DestinationSelection/stories.js";
|
||||||
import * as a19 from "./ExchangeSelection/stories.js";
|
import * as a19 from "./ExchangeSelection/stories.js";
|
||||||
import * as a20 from "./ManageAccount/stories.js";
|
import * as a20 from "./ManageAccount/stories.js";
|
||||||
import * as a21 from "./Notifications/stories.js";
|
import * as a21 from "./Notifications/stories.js";
|
||||||
|
Loading…
Reference in New Issue
Block a user