default exchange and select currency
This commit is contained in:
parent
0798aa5ced
commit
fb8372dfbf
@ -1,9 +1,25 @@
|
|||||||
|
/*
|
||||||
|
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 { css } from "@linaria/core";
|
import { css } from "@linaria/core";
|
||||||
import { h, JSX, VNode, ComponentChildren } from "preact";
|
import { h, JSX, VNode, ComponentChildren } from "preact";
|
||||||
import { useCallback, useEffect, useRef, useState } from "preact/hooks";
|
import { useCallback, useEffect, useRef, useState } from "preact/hooks";
|
||||||
// eslint-disable-next-line import/extensions
|
// eslint-disable-next-line import/extensions
|
||||||
import { alpha } from "./colors/manipulation";
|
import { alpha } from "./colors/manipulation";
|
||||||
import { ModalManager } from "./ModalManager";
|
import { ModalManager } from "./ModalManager.js";
|
||||||
import { Portal } from "./Portal.js";
|
import { Portal } from "./Portal.js";
|
||||||
// eslint-disable-next-line import/extensions
|
// eslint-disable-next-line import/extensions
|
||||||
import { theme } from "./style";
|
import { theme } from "./style";
|
||||||
@ -22,12 +38,16 @@ interface Props {
|
|||||||
children: ComponentChildren;
|
children: ComponentChildren;
|
||||||
open?: boolean;
|
open?: boolean;
|
||||||
exited?: boolean;
|
exited?: boolean;
|
||||||
container?: HTMLElement;
|
container?: VNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultManager = new ModalManager();
|
const defaultManager = new ModalManager();
|
||||||
const manager = defaultManager;
|
const manager = defaultManager;
|
||||||
|
|
||||||
|
function getModal(): any {
|
||||||
|
return null; //TODO: fix
|
||||||
|
}
|
||||||
|
|
||||||
export function Modal({
|
export function Modal({
|
||||||
open,
|
open,
|
||||||
// exited,
|
// exited,
|
||||||
@ -52,18 +72,18 @@ export function Modal({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (open && isTopModal()) {
|
// if (open && isTopModal()) {
|
||||||
handleMounted();
|
// handleMounted();
|
||||||
} else {
|
// } else {
|
||||||
ariaHidden(modalRef.current, true);
|
// ariaHidden(modalRef.current, true);
|
||||||
}
|
// }
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Portal
|
<Portal
|
||||||
ref={handlePortalRef}
|
ref={handlePortalRef}
|
||||||
container={container}
|
container={container}
|
||||||
disablePortal={disablePortal}
|
// disablePortal={disablePortal}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class={[_class, baseStyle].join(" ")}
|
class={[_class, baseStyle].join(" ")}
|
||||||
@ -105,7 +125,7 @@ function getOffsetLeft(rect: any, horizontal: any): number {
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTransformOriginValue(transformOrigin): string {
|
function getTransformOriginValue(transformOrigin: any): string {
|
||||||
return [transformOrigin.horizontal, transformOrigin.vertical]
|
return [transformOrigin.horizontal, transformOrigin.vertical]
|
||||||
.map((n) => (typeof n === "number" ? `${n}px` : n))
|
.map((n) => (typeof n === "number" ? `${n}px` : n))
|
||||||
.join(" ");
|
.join(" ");
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
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/>
|
||||||
|
*/
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
function ownerDocument(node: Node | null | undefined): Document {
|
function ownerDocument(node: Node | null | undefined): Document {
|
||||||
return (node && node.ownerDocument) || document;
|
return (node && node.ownerDocument) || document;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
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 { css } from "@linaria/core";
|
import { css } from "@linaria/core";
|
||||||
import { h, JSX, VNode, ComponentChildren } from "preact";
|
import { h, JSX, VNode, ComponentChildren } from "preact";
|
||||||
// eslint-disable-next-line import/extensions
|
// eslint-disable-next-line import/extensions
|
||||||
@ -48,7 +64,7 @@ function getOffsetLeft(rect: any, horizontal: any): number {
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTransformOriginValue(transformOrigin): string {
|
function getTransformOriginValue(transformOrigin: any): string {
|
||||||
return [transformOrigin.horizontal, transformOrigin.vertical]
|
return [transformOrigin.horizontal, transformOrigin.vertical]
|
||||||
.map((n) => (typeof n === "number" ? `${n}px` : n))
|
.map((n) => (typeof n === "number" ? `${n}px` : n))
|
||||||
.join(" ");
|
.join(" ");
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
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 { css } from "@linaria/core";
|
import { css } from "@linaria/core";
|
||||||
import { createPortal, forwardRef } from "preact/compat";
|
import { createPortal, forwardRef } from "preact/compat";
|
||||||
import {
|
import {
|
||||||
@ -26,7 +42,7 @@ const baseStyle = css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
class: string;
|
// class: string;
|
||||||
children: ComponentChildren;
|
children: ComponentChildren;
|
||||||
disablePortal?: boolean;
|
disablePortal?: boolean;
|
||||||
container?: VNode;
|
container?: VNode;
|
||||||
@ -39,10 +55,11 @@ export const Portal = forwardRef(function Portal(
|
|||||||
const [mountNode, setMountNode] = useState<HTMLElement | undefined>(
|
const [mountNode, setMountNode] = useState<HTMLElement | undefined>(
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
const handleRef = useForkRef(
|
const handleRef = null;
|
||||||
isValidElement(children) ? children.ref : null,
|
// useForkRef(
|
||||||
ref,
|
// isValidElement(children) ? children.ref : null,
|
||||||
);
|
// ref,
|
||||||
|
// );
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!disablePortal) {
|
if (!disablePortal) {
|
||||||
@ -81,25 +98,25 @@ function getContainer(container: any): any {
|
|||||||
return typeof container === "function" ? container() : container;
|
return typeof container === "function" ? container() : container;
|
||||||
}
|
}
|
||||||
|
|
||||||
function useForkRef<Instance>(
|
// function useForkRef<Instance>(
|
||||||
refA: React.Ref<Instance> | null | undefined,
|
// refA: React.Ref<Instance> | null | undefined,
|
||||||
refB: React.Ref<Instance> | null | undefined,
|
// refB: React.Ref<Instance> | null | undefined,
|
||||||
): React.Ref<Instance> | null {
|
// ): React.Ref<Instance> | null {
|
||||||
/**
|
// /**
|
||||||
* This will create a new function if the ref props change and are defined.
|
// * This will create a new function if the ref props change and are defined.
|
||||||
* This means react will call the old forkRef with `null` and the new forkRef
|
// * This means react will call the old forkRef with `null` and the new forkRef
|
||||||
* with the ref. Cleanup naturally emerges from this behavior.
|
// * with the ref. Cleanup naturally emerges from this behavior.
|
||||||
*/
|
// */
|
||||||
return useMemo(() => {
|
// return useMemo(() => {
|
||||||
if (refA == null && refB == null) {
|
// if (refA == null && refB == null) {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
return (refValue) => {
|
// return (refValue) => {
|
||||||
setRef(refA, refValue);
|
// setRef(refA, refValue);
|
||||||
setRef(refB, refValue);
|
// setRef(refB, refValue);
|
||||||
};
|
// };
|
||||||
}, [refA, refB]);
|
// }, [refA, refB]);
|
||||||
}
|
// }
|
||||||
|
|
||||||
function setRef<T>(
|
function setRef<T>(
|
||||||
ref: RefObject<T | null> | ((instance: T | null) => void) | null | undefined,
|
ref: RefObject<T | null> | ((instance: T | null) => void) | null | undefined,
|
||||||
|
@ -18,18 +18,29 @@ import { Amounts } from "@gnu-taler/taler-util";
|
|||||||
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 { useState } from "preact/hooks";
|
||||||
|
import { ErrorMessage } from "../components/ErrorMessage.js";
|
||||||
|
import { Loading } from "../components/Loading.js";
|
||||||
|
import { LoadingError } from "../components/LoadingError.js";
|
||||||
|
import { SelectList } from "../components/SelectList.js";
|
||||||
import {
|
import {
|
||||||
|
Input,
|
||||||
InputWithLabel,
|
InputWithLabel,
|
||||||
LightText,
|
LightText,
|
||||||
|
LinkPrimary,
|
||||||
|
SubTitle,
|
||||||
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 { Alert } from "../mui/Alert.js";
|
||||||
import { Button } from "../mui/Button.js";
|
import { Button } from "../mui/Button.js";
|
||||||
import { Grid } from "../mui/Grid.js";
|
import { Grid } from "../mui/Grid.js";
|
||||||
import { Paper } from "../mui/Paper.js";
|
import { Paper } from "../mui/Paper.js";
|
||||||
import { TextField } from "../mui/TextField.js";
|
import { TextField } from "../mui/TextField.js";
|
||||||
|
import { Pages } from "../NavigationBar.js";
|
||||||
import arrowIcon from "../svg/chevron-down.svg";
|
import arrowIcon from "../svg/chevron-down.svg";
|
||||||
import bankIcon from "../svg/ri-bank-line.svg";
|
import bankIcon from "../svg/ri-bank-line.svg";
|
||||||
|
import * as wxApi from "../wxApi.js";
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -152,6 +163,57 @@ const CircleDiv = styled.div`
|
|||||||
border: none;
|
border: none;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export function SelectCurrency({
|
||||||
|
onChange,
|
||||||
|
}: {
|
||||||
|
onChange: (s: string) => void;
|
||||||
|
}): VNode {
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
|
const hook = useAsyncAsHook(wxApi.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) => (list[e.currency] = e.currency));
|
||||||
|
list[""] = "Select a currency";
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<h1>
|
||||||
|
<i18n.Translate>Specify the amount and the origin</i18n.Translate>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<Alert severity="warning">
|
||||||
|
Choose a currency to proceed or add more exchanges in the settings tab
|
||||||
|
</Alert>
|
||||||
|
<Input>
|
||||||
|
<SelectList
|
||||||
|
label={<i18n.Translate>Known currencies</i18n.Translate>}
|
||||||
|
list={list}
|
||||||
|
name="lang"
|
||||||
|
value={""}
|
||||||
|
onChange={(v) => onChange(v)}
|
||||||
|
/>
|
||||||
|
</Input>
|
||||||
|
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
||||||
|
<div />
|
||||||
|
<LinkPrimary href={Pages.settingsExchangeAdd({})}>
|
||||||
|
<i18n.Translate>Add an exchange</i18n.Translate>
|
||||||
|
</LinkPrimary>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function RowExample({
|
function RowExample({
|
||||||
info,
|
info,
|
||||||
disabled,
|
disabled,
|
||||||
@ -194,9 +256,9 @@ export function DestinationSelectionGetCash({
|
|||||||
? undefined
|
? undefined
|
||||||
: Amounts.parse(initialAmount);
|
: Amounts.parse(initialAmount);
|
||||||
const parsedInitialAmountValue = !parsedInitialAmount
|
const parsedInitialAmountValue = !parsedInitialAmount
|
||||||
? ""
|
? "0"
|
||||||
: Amounts.stringifyValue(parsedInitialAmount);
|
: Amounts.stringifyValue(parsedInitialAmount);
|
||||||
const currency = parsedInitialAmount?.currency;
|
const [currency, setCurrency] = useState(parsedInitialAmount?.currency);
|
||||||
|
|
||||||
const [amount, setAmount] = useState(parsedInitialAmountValue);
|
const [amount, setAmount] = useState(parsedInitialAmountValue);
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
@ -220,7 +282,11 @@ export function DestinationSelectionGetCash({
|
|||||||
];
|
];
|
||||||
|
|
||||||
if (!currency) {
|
if (!currency) {
|
||||||
return <div>currency not provided</div>;
|
return (
|
||||||
|
<div>
|
||||||
|
<SelectCurrency onChange={(c) => setCurrency(c)} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const currencyAndAmount = `${currency}:${amount}`;
|
const currencyAndAmount = `${currency}:${amount}`;
|
||||||
const parsedAmount = Amounts.parse(currencyAndAmount);
|
const parsedAmount = Amounts.parse(currencyAndAmount);
|
||||||
@ -231,20 +297,25 @@ export function DestinationSelectionGetCash({
|
|||||||
<h1>
|
<h1>
|
||||||
<i18n.Translate>Specify the amount and the origin</i18n.Translate>
|
<i18n.Translate>Specify the amount and the origin</i18n.Translate>
|
||||||
</h1>
|
</h1>
|
||||||
<TextField
|
<Grid container columns={2} justifyContent="space-between">
|
||||||
label="Amount"
|
<TextField
|
||||||
type="number"
|
label="Amount"
|
||||||
variant="filled"
|
type="number"
|
||||||
error={invalid}
|
variant="filled"
|
||||||
required
|
error={invalid}
|
||||||
startAdornment={
|
required
|
||||||
<div style={{ padding: "25px 12px 8px 12px" }}>{currency}</div>
|
startAdornment={
|
||||||
}
|
<div style={{ padding: "25px 12px 8px 12px" }}>{currency}</div>
|
||||||
value={amount}
|
}
|
||||||
onChange={(e) => {
|
value={amount}
|
||||||
setAmount(e);
|
onChange={(e) => {
|
||||||
}}
|
setAmount(e);
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
<Button onClick={async () => setCurrency(undefined)}>
|
||||||
|
Change currency
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<Grid container spacing={1} columns={1}>
|
<Grid container spacing={1} columns={1}>
|
||||||
{previous2.length > 0 ? (
|
{previous2.length > 0 ? (
|
||||||
@ -350,20 +421,22 @@ export function DestinationSelectionSendCash({
|
|||||||
<i18n.Translate>Specify the amount and the destination</i18n.Translate>
|
<i18n.Translate>Specify the amount and the destination</i18n.Translate>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<TextField
|
<div>
|
||||||
label="Amount"
|
<TextField
|
||||||
type="number"
|
label="Amount"
|
||||||
variant="filled"
|
type="number"
|
||||||
required
|
variant="filled"
|
||||||
error={invalid}
|
required
|
||||||
startAdornment={
|
error={invalid}
|
||||||
<div style={{ padding: "25px 12px 8px 12px" }}>{currency}</div>
|
startAdornment={
|
||||||
}
|
<div style={{ padding: "25px 12px 8px 12px" }}>{currency}</div>
|
||||||
value={amount}
|
}
|
||||||
onChange={(e) => {
|
value={amount}
|
||||||
setAmount(e);
|
onChange={(e) => {
|
||||||
}}
|
setAmount(e);
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Grid container spacing={1} columns={1}>
|
<Grid container spacing={1} columns={1}>
|
||||||
{previous2.length > 0 ? (
|
{previous2.length > 0 ? (
|
||||||
|
Loading…
Reference in New Issue
Block a user