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 { h, JSX, VNode, ComponentChildren } from "preact";
|
||||
import { useCallback, useEffect, useRef, useState } from "preact/hooks";
|
||||
// eslint-disable-next-line import/extensions
|
||||
import { alpha } from "./colors/manipulation";
|
||||
import { ModalManager } from "./ModalManager";
|
||||
import { ModalManager } from "./ModalManager.js";
|
||||
import { Portal } from "./Portal.js";
|
||||
// eslint-disable-next-line import/extensions
|
||||
import { theme } from "./style";
|
||||
@ -22,12 +38,16 @@ interface Props {
|
||||
children: ComponentChildren;
|
||||
open?: boolean;
|
||||
exited?: boolean;
|
||||
container?: HTMLElement;
|
||||
container?: VNode;
|
||||
}
|
||||
|
||||
const defaultManager = new ModalManager();
|
||||
const manager = defaultManager;
|
||||
|
||||
function getModal(): any {
|
||||
return null; //TODO: fix
|
||||
}
|
||||
|
||||
export function Modal({
|
||||
open,
|
||||
// exited,
|
||||
@ -52,18 +72,18 @@ export function Modal({
|
||||
return;
|
||||
}
|
||||
|
||||
if (open && isTopModal()) {
|
||||
handleMounted();
|
||||
} else {
|
||||
ariaHidden(modalRef.current, true);
|
||||
}
|
||||
// if (open && isTopModal()) {
|
||||
// handleMounted();
|
||||
// } else {
|
||||
// ariaHidden(modalRef.current, true);
|
||||
// }
|
||||
});
|
||||
|
||||
return (
|
||||
<Portal
|
||||
ref={handlePortalRef}
|
||||
container={container}
|
||||
disablePortal={disablePortal}
|
||||
// disablePortal={disablePortal}
|
||||
>
|
||||
<div
|
||||
class={[_class, baseStyle].join(" ")}
|
||||
@ -105,7 +125,7 @@ function getOffsetLeft(rect: any, horizontal: any): number {
|
||||
return offset;
|
||||
}
|
||||
|
||||
function getTransformOriginValue(transformOrigin): string {
|
||||
function getTransformOriginValue(transformOrigin: any): string {
|
||||
return [transformOrigin.horizontal, transformOrigin.vertical]
|
||||
.map((n) => (typeof n === "number" ? `${n}px` : n))
|
||||
.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 {
|
||||
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 { h, JSX, VNode, ComponentChildren } from "preact";
|
||||
// eslint-disable-next-line import/extensions
|
||||
@ -48,7 +64,7 @@ function getOffsetLeft(rect: any, horizontal: any): number {
|
||||
return offset;
|
||||
}
|
||||
|
||||
function getTransformOriginValue(transformOrigin): string {
|
||||
function getTransformOriginValue(transformOrigin: any): string {
|
||||
return [transformOrigin.horizontal, transformOrigin.vertical]
|
||||
.map((n) => (typeof n === "number" ? `${n}px` : n))
|
||||
.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 { createPortal, forwardRef } from "preact/compat";
|
||||
import {
|
||||
@ -26,7 +42,7 @@ const baseStyle = css`
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
class: string;
|
||||
// class: string;
|
||||
children: ComponentChildren;
|
||||
disablePortal?: boolean;
|
||||
container?: VNode;
|
||||
@ -39,10 +55,11 @@ export const Portal = forwardRef(function Portal(
|
||||
const [mountNode, setMountNode] = useState<HTMLElement | undefined>(
|
||||
undefined,
|
||||
);
|
||||
const handleRef = useForkRef(
|
||||
isValidElement(children) ? children.ref : null,
|
||||
ref,
|
||||
);
|
||||
const handleRef = null;
|
||||
// useForkRef(
|
||||
// isValidElement(children) ? children.ref : null,
|
||||
// ref,
|
||||
// );
|
||||
|
||||
useEffect(() => {
|
||||
if (!disablePortal) {
|
||||
@ -81,25 +98,25 @@ function getContainer(container: any): any {
|
||||
return typeof container === "function" ? container() : container;
|
||||
}
|
||||
|
||||
function useForkRef<Instance>(
|
||||
refA: React.Ref<Instance> | null | undefined,
|
||||
refB: React.Ref<Instance> | null | undefined,
|
||||
): React.Ref<Instance> | null {
|
||||
/**
|
||||
* 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
|
||||
* with the ref. Cleanup naturally emerges from this behavior.
|
||||
*/
|
||||
return useMemo(() => {
|
||||
if (refA == null && refB == null) {
|
||||
return null;
|
||||
}
|
||||
return (refValue) => {
|
||||
setRef(refA, refValue);
|
||||
setRef(refB, refValue);
|
||||
};
|
||||
}, [refA, refB]);
|
||||
}
|
||||
// function useForkRef<Instance>(
|
||||
// refA: React.Ref<Instance> | null | undefined,
|
||||
// refB: React.Ref<Instance> | null | undefined,
|
||||
// ): React.Ref<Instance> | null {
|
||||
// /**
|
||||
// * 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
|
||||
// * with the ref. Cleanup naturally emerges from this behavior.
|
||||
// */
|
||||
// return useMemo(() => {
|
||||
// if (refA == null && refB == null) {
|
||||
// return null;
|
||||
// }
|
||||
// return (refValue) => {
|
||||
// setRef(refA, refValue);
|
||||
// setRef(refB, refValue);
|
||||
// };
|
||||
// }, [refA, refB]);
|
||||
// }
|
||||
|
||||
function setRef<T>(
|
||||
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 { Fragment, h, VNode } from "preact";
|
||||
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 {
|
||||
Input,
|
||||
InputWithLabel,
|
||||
LightText,
|
||||
LinkPrimary,
|
||||
SubTitle,
|
||||
SvgIcon,
|
||||
} from "../components/styled/index.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 { Grid } from "../mui/Grid.js";
|
||||
import { Paper } from "../mui/Paper.js";
|
||||
import { TextField } from "../mui/TextField.js";
|
||||
import { Pages } from "../NavigationBar.js";
|
||||
import arrowIcon from "../svg/chevron-down.svg";
|
||||
import bankIcon from "../svg/ri-bank-line.svg";
|
||||
import * as wxApi from "../wxApi.js";
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
@ -152,6 +163,57 @@ const CircleDiv = styled.div`
|
||||
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({
|
||||
info,
|
||||
disabled,
|
||||
@ -194,9 +256,9 @@ export function DestinationSelectionGetCash({
|
||||
? undefined
|
||||
: Amounts.parse(initialAmount);
|
||||
const parsedInitialAmountValue = !parsedInitialAmount
|
||||
? ""
|
||||
? "0"
|
||||
: Amounts.stringifyValue(parsedInitialAmount);
|
||||
const currency = parsedInitialAmount?.currency;
|
||||
const [currency, setCurrency] = useState(parsedInitialAmount?.currency);
|
||||
|
||||
const [amount, setAmount] = useState(parsedInitialAmountValue);
|
||||
const { i18n } = useTranslationContext();
|
||||
@ -220,7 +282,11 @@ export function DestinationSelectionGetCash({
|
||||
];
|
||||
|
||||
if (!currency) {
|
||||
return <div>currency not provided</div>;
|
||||
return (
|
||||
<div>
|
||||
<SelectCurrency onChange={(c) => setCurrency(c)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const currencyAndAmount = `${currency}:${amount}`;
|
||||
const parsedAmount = Amounts.parse(currencyAndAmount);
|
||||
@ -231,6 +297,7 @@ export function DestinationSelectionGetCash({
|
||||
<h1>
|
||||
<i18n.Translate>Specify the amount and the origin</i18n.Translate>
|
||||
</h1>
|
||||
<Grid container columns={2} justifyContent="space-between">
|
||||
<TextField
|
||||
label="Amount"
|
||||
type="number"
|
||||
@ -245,6 +312,10 @@ export function DestinationSelectionGetCash({
|
||||
setAmount(e);
|
||||
}}
|
||||
/>
|
||||
<Button onClick={async () => setCurrency(undefined)}>
|
||||
Change currency
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<Grid container spacing={1} columns={1}>
|
||||
{previous2.length > 0 ? (
|
||||
@ -350,6 +421,7 @@ export function DestinationSelectionSendCash({
|
||||
<i18n.Translate>Specify the amount and the destination</i18n.Translate>
|
||||
</h1>
|
||||
|
||||
<div>
|
||||
<TextField
|
||||
label="Amount"
|
||||
type="number"
|
||||
@ -364,6 +436,7 @@ export function DestinationSelectionSendCash({
|
||||
setAmount(e);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Grid container spacing={1} columns={1}>
|
||||
{previous2.length > 0 ? (
|
||||
|
Loading…
Reference in New Issue
Block a user