default exchange and select currency

This commit is contained in:
Sebastian 2022-08-15 23:01:05 -03:00
parent 0798aa5ced
commit fb8372dfbf
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
5 changed files with 207 additions and 65 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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 ? (