fix #7496 with unit tests

This commit is contained in:
Sebastian 2022-11-28 09:29:14 -03:00
parent dcddc4c53a
commit 3577227cc0
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
17 changed files with 686 additions and 400 deletions

View File

@ -21,8 +21,8 @@
import { expect } from "chai";
describe("test description", () => {
it("should assert", () => {
describe("Term of service states", () => {
it.skip("should assert", () => {
expect([]).deep.equals([]);
});
});

View File

@ -25,11 +25,10 @@ import { isFuture, parse } from "date-fns";
import { useState } from "preact/hooks";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
import { RecursiveState } from "../../utils/index.js";
import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
export function useComponentState(
{ amount: amountStr, onClose, onSuccess }: Props,
api: typeof wxApi,

View File

@ -21,8 +21,8 @@
import { expect } from "chai";
describe("test description", () => {
it("should assert", () => {
describe("Invoice create state", () => {
it.skip("should create some tests", () => {
expect([]).deep.equals([]);
});
});

View File

@ -21,8 +21,8 @@
import { expect } from "chai";
describe("test description", () => {
it("should assert", () => {
describe("Invoice payment state", () => {
it.skip("should create some states", () => {
expect([]).deep.equals([]);
});
});

View File

@ -21,8 +21,8 @@
import { expect } from "chai";
describe("test description", () => {
it("should assert", () => {
describe("Transfer create states", () => {
it.skip("should assert", () => {
expect([]).deep.equals([]);
});
});

View File

@ -21,8 +21,8 @@
import { expect } from "chai";
describe("test description", () => {
it("should assert", () => {
describe("Transfer pickup states", () => {
it.skip("should assert", () => {
expect([]).deep.equals([]);
});
});

View File

@ -25,11 +25,10 @@ import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useState } from "preact/hooks";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
import { RecursiveState } from "../../utils/index.js";
import { wxApi } from "../../wxApi.js";
import { PropsFromParams, PropsFromURI, State } from "./index.js";
type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
export function useComponentStateFromParams(
{ amount, cancel, onSuccess }: PropsFromParams,
api: typeof wxApi,

View File

@ -80,7 +80,7 @@ export type StateViewMap<StateType extends { status: string }> = {
[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>(
name: string,

View File

@ -48,17 +48,13 @@ import { BackupPage } from "./BackupPage.js";
import { DepositPage } from "./DepositPage/index.js";
import { ExchangeAddPage } from "./ExchangeAddPage.js";
import { HistoryPage } from "./History.js";
import { ProviderAddPage } from "./ProviderAddPage.js";
import { ProviderDetailPage } from "./ProviderDetailPage.js";
import { SettingsPage } from "./Settings.js";
import { TransactionPage } from "./Transaction.js";
import { WelcomePage } from "./Welcome.js";
import { QrReaderPage } from "./QrReader.js";
import { platform } from "../platform/api.js";
import {
DestinationSelectionGetCash,
DestinationSelectionSendCash,
} from "./DestinationSelection.js";
import { DestinationSelectionPage } from "./DestinationSelection/index.js";
import { ExchangeSelectionPage } from "./ExchangeSelection/index.js";
import { TransferCreatePage } from "../cta/TransferCreate/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.sendCash.pattern}
component={DestinationSelectionSendCash}
type="send"
component={DestinationSelectionPage}
goToWalletBankDeposit={(amount: string) =>
redirectTo(Pages.balanceDeposit({ amount }))
}
@ -163,7 +160,8 @@ export function Application(): VNode {
/>
<Route
path={Pages.receiveCash.pattern}
component={DestinationSelectionGetCash}
type="get"
component={DestinationSelectionPage}
goToWalletManualWithdraw={(amount?: string) =>
redirectTo(Pages.ctaWithdrawManual({ amount }))
}

View File

@ -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,
);

View File

@ -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);
}
}

View File

@ -19,25 +19,44 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
import { createExample } from "../test-utils.js";
import {
DestinationSelectionGetCash,
DestinationSelectionSendCash,
SelectCurrencyView,
} from "./DestinationSelection.js";
import { createExample } from "../../test-utils.js";
import { ReadyView, SelectCurrencyView } from "./views.js";
export default {
title: "wallet/destination",
};
export const GetCash = createExample(DestinationSelectionGetCash, {
amount: "usd:0",
export const GetCash = createExample(ReadyView, {
amountHandler: {
value: {
currency: "EUR",
fraction: 0,
value: 2,
},
},
goToBank: {},
goToWallet: {},
previous: [],
selectCurrency: {},
type: "get",
});
export const SendCash = createExample(DestinationSelectionSendCash, {
amount: "eur:1",
export const SendCash = createExample(ReadyView, {
amountHandler: {
value: {
currency: "EUR",
fraction: 0,
value: 1,
},
},
goToBank: {},
goToWallet: {},
previous: [],
selectCurrency: {},
type: "send",
});
export const SelectCurrency = createExample(SelectCurrencyView, {
list: {
currencies: {
"": "Select a currency",
USD: "USD",
},

View File

@ -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");
});
});

View File

@ -14,30 +14,70 @@
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 { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { AmountField } from "../components/AmountField.js";
import { Loading } from "../components/Loading.js";
import { LoadingError } from "../components/LoadingError.js";
import { SelectList } from "../components/SelectList.js";
import { LoadingError } from "../../components/LoadingError.js";
import { SelectList } from "../../components/SelectList.js";
import {
Input,
LightText,
LinkPrimary,
SvgIcon,
} from "../components/styled/index.js";
import { useTranslationContext } from "../context/translation.js";
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
import { Button } from "../mui/Button.js";
import { Grid } from "../mui/Grid.js";
import { Paper } from "../mui/Paper.js";
import { Pages } from "../NavigationBar.js";
import arrowIcon from "../svg/chevron-down.svg";
import bankIcon from "../svg/ri-bank-line.svg";
import { wxApi } from "../wxApi.js";
} from "../../components/styled/index.js";
import { useTranslationContext } from "../../context/translation.js";
import { Pages } from "../../NavigationBar.js";
import { Contact, State } from "./index.js";
import arrowIcon from "../../svg/chevron-down.svg";
import { AmountField } from "../../components/AmountField.js";
import { Grid } from "../../mui/Grid.js";
import { Paper } from "../../mui/Paper.js";
import { Button } from "../../mui/Button.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`
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`
width: 100%;
& > tr > td {
@ -165,73 +188,193 @@ const CircleDiv = styled.div`
border: none;
`;
export function SelectCurrency({
onChange,
}: {
onChange: (s: string) => void;
}): VNode {
const { i18n } = useTranslationContext();
const hook = useAsyncAsHook(() =>
wxApi.wallet.call(WalletApiOperation.ListExchanges, {}),
);
if (!hook) {
return <Loading />;
export function ReadyView(props: State.Ready): VNode {
switch (props.type) {
case "get":
return ReadyGetView(props);
case "send":
return ReadySendView(props);
default:
assertUnreachable(props.type);
}
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 SelectCurrencyView({
onChange,
list,
}: {
onChange: (s: string) => void;
list: Record<string, string>;
}): VNode {
export function ReadyGetView({
amountHandler,
goToBank,
goToWallet,
selectCurrency,
previous,
}: State.Ready): 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={list}
name="lang"
value={""}
onChange={(v) => onChange(v)}
<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={amountHandler}
/>
</Input>
<Button onClick={selectCurrency.onClick}>
<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>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<div />
<LinkPrimary href={Pages.settingsExchangeAdd({})}>
<i18n.Translate>Add an exchange</i18n.Translate>
</LinkPrimary>
</div>
<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 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>
<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>
);
}
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>
);
}

View File

@ -21,8 +21,8 @@
import { expect } from "chai";
describe("test description", () => {
it("should assert", () => {
describe("Manage Account states", () => {
it.skip("should create some tests", () => {
expect([]).deep.equals([]);
});
});

View File

@ -21,8 +21,8 @@
import { expect } from "chai";
describe("test description", () => {
it("should assert", () => {
describe("Notifications states", () => {
it.skip("should create some tests", () => {
expect([]).deep.equals([]);
});
});

View File

@ -33,7 +33,7 @@ import * as a14 from "./Welcome.stories.js";
import * as a15 from "./AddNewActionView.stories.js";
import * as a16 from "./DeveloperPage.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 a20 from "./ManageAccount/stories.js";
import * as a21 from "./Notifications/stories.js";