render amount and limit input
This commit is contained in:
parent
1708d49a2d
commit
372ddff917
@ -19,6 +19,7 @@ import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
|||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Amounts } from "@gnu-taler/taler-util";
|
import { Amounts } from "@gnu-taler/taler-util";
|
||||||
|
import { RenderAmount } from "../../pages/PaytoWireTransferForm.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
@ -62,8 +63,8 @@ export function ReadyView({ cashouts, onSelected }: State.Ready): VNode {
|
|||||||
? format(item.confirmation_time, "dd/MM/yyyy HH:mm:ss")
|
? format(item.confirmation_time, "dd/MM/yyyy HH:mm:ss")
|
||||||
: "-"}
|
: "-"}
|
||||||
</td>
|
</td>
|
||||||
<td>{Amounts.stringifyValue(item.amount_debit)}</td>
|
<td><RenderAmount value={Amounts.parseOrThrow(item.amount_debit)} /></td>
|
||||||
<td>{Amounts.stringifyValue(item.amount_credit)}</td>
|
<td><RenderAmount value={Amounts.parseOrThrow(item.amount_credit)} /></td>
|
||||||
<td>{item.status}</td>
|
<td>{item.status}</td>
|
||||||
<td>
|
<td>
|
||||||
<a
|
<a
|
||||||
|
@ -20,6 +20,7 @@ import { State } from "./index.js";
|
|||||||
import { format, isToday } from "date-fns";
|
import { format, isToday } from "date-fns";
|
||||||
import { Amounts } from "@gnu-taler/taler-util";
|
import { Amounts } from "@gnu-taler/taler-util";
|
||||||
import { useEffect, useRef } from "preact/hooks";
|
import { useEffect, useRef } from "preact/hooks";
|
||||||
|
import { RenderAmount } from "../../pages/PaytoWireTransferForm.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
@ -72,13 +73,7 @@ export function ReadyView({ transactions, onNext, onPrev }: State.Ready): VNode
|
|||||||
{txs.map(item => {
|
{txs.map(item => {
|
||||||
const time = item.when.t_ms === "never" ? "" : format(item.when.t_ms, "HH:mm:ss")
|
const time = item.when.t_ms === "never" ? "" : format(item.when.t_ms, "HH:mm:ss")
|
||||||
const amount = <Fragment>
|
const amount = <Fragment>
|
||||||
{item.negative ? "-" : ""}
|
{ }
|
||||||
{item.amount ? (
|
|
||||||
`${Amounts.stringifyValue(item.amount)} ${item.amount.currency
|
|
||||||
}`
|
|
||||||
) : (
|
|
||||||
<span style={{ color: "grey" }}><{i18n.str`invalid value`}></span>
|
|
||||||
)}
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
return (<tr key={idx}>
|
return (<tr key={idx}>
|
||||||
<td class="relative py-2 pl-2 pr-2 text-sm ">
|
<td class="relative py-2 pl-2 pr-2 text-sm ">
|
||||||
@ -86,11 +81,14 @@ export function ReadyView({ transactions, onNext, onPrev }: State.Ready): VNode
|
|||||||
<dl class="font-normal sm:hidden">
|
<dl class="font-normal sm:hidden">
|
||||||
<dt class="sr-only sm:hidden"><i18n.Translate>Amount</i18n.Translate></dt>
|
<dt class="sr-only sm:hidden"><i18n.Translate>Amount</i18n.Translate></dt>
|
||||||
<dd class="mt-1 truncate text-gray-700">
|
<dd class="mt-1 truncate text-gray-700">
|
||||||
{item.negative ? i18n.str`sent` : i18n.str`received`} {item.amount ? (
|
{item.negative ? i18n.str`sent` : i18n.str`received`}
|
||||||
`${Amounts.stringifyValue(item.amount)}`
|
|
||||||
|
{item.amount ? (
|
||||||
|
<RenderAmount value={item.amount} />
|
||||||
) : (
|
) : (
|
||||||
<span style={{ color: "grey" }}><{i18n.str`invalid value`}></span>
|
<span style={{ color: "grey" }}><{i18n.str`invalid value`}></span>
|
||||||
)}</dd>
|
)}</dd>
|
||||||
|
|
||||||
<dt class="sr-only sm:hidden"><i18n.Translate>Counterpart</i18n.Translate></dt>
|
<dt class="sr-only sm:hidden"><i18n.Translate>Counterpart</i18n.Translate></dt>
|
||||||
<dd class="mt-1 truncate text-gray-500 sm:hidden">
|
<dd class="mt-1 truncate text-gray-500 sm:hidden">
|
||||||
{item.negative ? i18n.str`to` : i18n.str`from`} {item.counterpart}
|
{item.negative ? i18n.str`to` : i18n.str`from`} {item.counterpart}
|
||||||
@ -99,7 +97,10 @@ export function ReadyView({ transactions, onNext, onPrev }: State.Ready): VNode
|
|||||||
</td>
|
</td>
|
||||||
<td data-negative={item.negative ? "true" : "false"}
|
<td data-negative={item.negative ? "true" : "false"}
|
||||||
class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 data-[negative=false]:text-green-600 data-[negative=true]:text-red-600">
|
class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 data-[negative=false]:text-green-600 data-[negative=true]:text-red-600">
|
||||||
{amount}
|
{item.amount ? (<RenderAmount value={item.amount} negative={item.negative} />
|
||||||
|
) : (
|
||||||
|
<span style={{ color: "grey" }}><{i18n.str`invalid value`}></span>
|
||||||
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500">{item.counterpart}</td>
|
<td class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500">{item.counterpart}</td>
|
||||||
<td class="px-3 py-3.5 text-sm text-gray-500 break-all min-w-md">{item.subject}</td>
|
<td class="px-3 py-3.5 text-sm text-gray-500 break-all min-w-md">{item.subject}</td>
|
||||||
|
@ -31,6 +31,7 @@ import { getInitialBackendBaseURL } from "../hooks/backend.js";
|
|||||||
import { BANK_INTEGRATION_PROTOCOL_VERSION, useConfigState } from "../hooks/config.js";
|
import { BANK_INTEGRATION_PROTOCOL_VERSION, useConfigState } from "../hooks/config.js";
|
||||||
import { ErrorLoading } from "./ErrorLoading.js";
|
import { ErrorLoading } from "./ErrorLoading.js";
|
||||||
import { BankFrame } from "../pages/BankFrame.js";
|
import { BankFrame } from "../pages/BankFrame.js";
|
||||||
|
import { ConfigStateProvider } from "../context/config.js";
|
||||||
const WITH_LOCAL_STORAGE_CACHE = false;
|
const WITH_LOCAL_STORAGE_CACHE = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,11 +85,11 @@ function VersionCheck({ children }: { children: ComponentChildren }): VNode {
|
|||||||
</BankFrame>
|
</BankFrame>
|
||||||
}
|
}
|
||||||
if (checked.type === "ok") {
|
if (checked.type === "ok") {
|
||||||
return <Fragment>{children}</Fragment>
|
return <ConfigStateProvider value={checked.result}>{children}</ConfigStateProvider>
|
||||||
}
|
}
|
||||||
|
|
||||||
return <BankFrame>
|
return <BankFrame>
|
||||||
<ErrorLoading error={checked.result}/>
|
<ErrorLoading error={checked.result} />
|
||||||
</BankFrame>
|
</BankFrame>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
52
packages/demobank-ui/src/context/config.ts
Normal file
52
packages/demobank-ui/src/context/config.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
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 { ComponentChildren, createContext, h, VNode } from "preact";
|
||||||
|
import { useContext } from "preact/hooks";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Javier Marchano (sebasjm)
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type Type = Required<SandboxBackend.Config>;
|
||||||
|
|
||||||
|
const initial: Type = {
|
||||||
|
name: "",
|
||||||
|
version: "0:0:0",
|
||||||
|
currency_fraction_digits: 2,
|
||||||
|
currency_fraction_limit: 2,
|
||||||
|
fiat_currency: "",
|
||||||
|
have_cashout: false,
|
||||||
|
};
|
||||||
|
const Context = createContext<Type>(initial);
|
||||||
|
|
||||||
|
export const useConfigContext = (): Type => useContext(Context);
|
||||||
|
|
||||||
|
export const ConfigStateProvider = ({
|
||||||
|
value,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
value: Type,
|
||||||
|
children: ComponentChildren;
|
||||||
|
}): VNode => {
|
||||||
|
|
||||||
|
return h(Context.Provider, {
|
||||||
|
value,
|
||||||
|
children,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
24
packages/demobank-ui/src/declaration.d.ts
vendored
24
packages/demobank-ui/src/declaration.d.ts
vendored
@ -107,9 +107,27 @@ namespace SandboxBackend {
|
|||||||
name: string;
|
name: string;
|
||||||
// API version in the form $n:$n:$n
|
// API version in the form $n:$n:$n
|
||||||
version: string;
|
version: string;
|
||||||
// Contains ratios and fees related to buying
|
// If 'true', the server provides local currency
|
||||||
// and selling the circuit currency.
|
// conversion support.
|
||||||
ratios_and_fees: RatiosAndFees;
|
// If missing or false, some parts of the API
|
||||||
|
// are not supported and return 404.
|
||||||
|
have_cashout?: boolean;
|
||||||
|
|
||||||
|
// Fiat currency. That is the currency in which
|
||||||
|
// cash-out operations ultimately wire money.
|
||||||
|
// Only applicable if have_cashout=true.
|
||||||
|
fiat_currency?: string;
|
||||||
|
|
||||||
|
// How many digits should the amounts be rendered
|
||||||
|
// with by default. Small capitals should
|
||||||
|
// be used to render fractions beyond the number
|
||||||
|
// given here (like on gas stations).
|
||||||
|
currency_fraction_digits?: number;
|
||||||
|
|
||||||
|
// How many decimal digits an operation can
|
||||||
|
// have. Wire transfers with more decimal
|
||||||
|
// digits will not be accepted.
|
||||||
|
currency_fraction_limit?: number;
|
||||||
}
|
}
|
||||||
interface RatiosAndFees {
|
interface RatiosAndFees {
|
||||||
// Exchange rate to buy the circuit currency from fiat.
|
// Exchange rate to buy the circuit currency from fiat.
|
||||||
|
@ -18,13 +18,13 @@ async function getConfigState(
|
|||||||
return result.data;
|
return result.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Result = undefined
|
export type ConfigResult = undefined
|
||||||
| { type: "ok", result: SandboxBackend.Config }
|
| { type: "ok", result: Required<SandboxBackend.Config> }
|
||||||
| { type: "wrong", result: SandboxBackend.Config }
|
| { type: "wrong", result: SandboxBackend.Config }
|
||||||
| { type: "error", result: HttpError<SandboxBackend.SandboxError> }
|
| { type: "error", result: HttpError<SandboxBackend.SandboxError> }
|
||||||
|
|
||||||
export function useConfigState(): Result {
|
export function useConfigState(): ConfigResult {
|
||||||
const [checked, setChecked] = useState<Result>()
|
const [checked, setChecked] = useState<ConfigResult>()
|
||||||
const { request } = useApiContext();
|
const { request } = useApiContext();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -32,15 +32,23 @@ export function useConfigState(): Result {
|
|||||||
.then((result) => {
|
.then((result) => {
|
||||||
const r = LibtoolVersion.compare(BANK_INTEGRATION_PROTOCOL_VERSION, result.version)
|
const r = LibtoolVersion.compare(BANK_INTEGRATION_PROTOCOL_VERSION, result.version)
|
||||||
if (r?.compatible) {
|
if (r?.compatible) {
|
||||||
setChecked({ type: "ok",result });
|
const complete: Required<SandboxBackend.Config> = {
|
||||||
|
currency_fraction_digits: result.currency_fraction_digits ?? 2,
|
||||||
|
currency_fraction_limit: result.currency_fraction_limit ?? 2,
|
||||||
|
fiat_currency: "",
|
||||||
|
have_cashout: result.have_cashout ?? false,
|
||||||
|
name: result.name,
|
||||||
|
version: result.version,
|
||||||
|
}
|
||||||
|
setChecked({ type: "ok", result: complete });
|
||||||
} else {
|
} else {
|
||||||
setChecked({ type: "wrong",result })
|
setChecked({ type: "wrong", result })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error: unknown) => {
|
.catch((error: unknown) => {
|
||||||
if (error instanceof RequestError) {
|
if (error instanceof RequestError) {
|
||||||
const result = error.cause
|
const result = error.cause
|
||||||
setChecked({ type:"error", result });
|
setChecked({ type: "error", result });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
@ -27,6 +27,7 @@ import { CopyButton, CopyIcon } from "../components/CopyButton.js";
|
|||||||
import logo from "../assets/logo-2021.svg";
|
import logo from "../assets/logo-2021.svg";
|
||||||
import { useAccountDetails } from "../hooks/access.js";
|
import { useAccountDetails } from "../hooks/access.js";
|
||||||
import { Attention } from "../components/Attention.js";
|
import { Attention } from "../components/Attention.js";
|
||||||
|
import { RenderAmount } from "./PaytoWireTransferForm.js";
|
||||||
|
|
||||||
const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined;
|
const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined;
|
||||||
const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;
|
const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;
|
||||||
@ -87,7 +88,7 @@ export function BankFrame({
|
|||||||
class="h-8 w-auto"
|
class="h-8 w-auto"
|
||||||
src={logo}
|
src={logo}
|
||||||
alt="Taler"
|
alt="Taler"
|
||||||
style={{ height: 35, margin: 10 }}
|
style={{ height: "1.5rem", margin: ".5rem" }}
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -430,9 +431,8 @@ function AccountBalance({ account }: { account: string }): VNode {
|
|||||||
const result = useAccountDetails(account);
|
const result = useAccountDetails(account);
|
||||||
if (!result.ok) return <div />
|
if (!result.ok) return <div />
|
||||||
|
|
||||||
return <div>
|
return <RenderAmount
|
||||||
{Amounts.currencyOf(result.data.balance.amount)}
|
value={Amounts.parseOrThrow(result.data.balance.amount)}
|
||||||
{result.data.balance.credit_debit_indicator === "debit" ? "-" : ""}
|
negative={result.data.balance.credit_debit_indicator === "debit"}
|
||||||
{Amounts.stringifyValue(result.data.balance.amount)}
|
/>
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ export function PaymentOptions({ limit, goToConfirmOperation }: { limit: AmountJ
|
|||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
const [settings] = useSettings();
|
const [settings] = useSettings();
|
||||||
|
|
||||||
const [tab, setTab] = useState<"charge-wallet" | "wire-transfer" | undefined>("wire-transfer");
|
const [tab, setTab] = useState<"charge-wallet" | "wire-transfer" | undefined>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
@ -47,7 +47,7 @@ export function PaymentOptions({ limit, goToConfirmOperation }: { limit: AmountJ
|
|||||||
setTab("charge-wallet")
|
setTab("charge-wallet")
|
||||||
}} />
|
}} />
|
||||||
<span class="flex flex-1">
|
<span class="flex flex-1">
|
||||||
<div class="text-lg mr-2">💵</div>
|
<div class="text-4xl mr-4 my-auto">💵</div>
|
||||||
<span class="flex flex-col">
|
<span class="flex flex-col">
|
||||||
<span id="project-type-0-label" class="block text-sm font-medium text-gray-900">
|
<span id="project-type-0-label" class="block text-sm font-medium text-gray-900">
|
||||||
<i18n.Translate>a <b>Taler</b> wallet</i18n.Translate>
|
<i18n.Translate>a <b>Taler</b> wallet</i18n.Translate>
|
||||||
@ -76,7 +76,7 @@ export function PaymentOptions({ limit, goToConfirmOperation }: { limit: AmountJ
|
|||||||
setTab("wire-transfer")
|
setTab("wire-transfer")
|
||||||
}} />
|
}} />
|
||||||
<span class="flex flex-1">
|
<span class="flex flex-1">
|
||||||
<div class="text-lg mr-2">↔</div>
|
<div class="text-4xl mr-4 my-auto">↔</div>
|
||||||
<span class="flex flex-col">
|
<span class="flex flex-col">
|
||||||
<span id="project-type-1-label" class="block text-sm font-medium text-gray-900">
|
<span id="project-type-1-label" class="block text-sm font-medium text-gray-900">
|
||||||
<i18n.Translate>another bank account</i18n.Translate>
|
<i18n.Translate>another bank account</i18n.Translate>
|
||||||
|
@ -39,6 +39,8 @@ import {
|
|||||||
undefinedIfEmpty,
|
undefinedIfEmpty,
|
||||||
validateIBAN,
|
validateIBAN,
|
||||||
} from "../utils.js";
|
} from "../utils.js";
|
||||||
|
import { useConfigState } from "../hooks/config.js";
|
||||||
|
import { useConfigContext } from "../context/config.js";
|
||||||
|
|
||||||
const logger = new Logger("PaytoWireTransferForm");
|
const logger = new Logger("PaytoWireTransferForm");
|
||||||
|
|
||||||
@ -55,7 +57,7 @@ export function PaytoWireTransferForm({
|
|||||||
onCancel: (() => void) | undefined;
|
onCancel: (() => void) | undefined;
|
||||||
limit: AmountJson;
|
limit: AmountJson;
|
||||||
}): VNode {
|
}): VNode {
|
||||||
const [isRawPayto, setIsRawPayto] = useState(true);
|
const [isRawPayto, setIsRawPayto] = useState(false);
|
||||||
// FIXME: remove this
|
// FIXME: remove this
|
||||||
const [iban, setIban] = useState<string | undefined>("DE4745461198061");
|
const [iban, setIban] = useState<string | undefined>("DE4745461198061");
|
||||||
const [subject, setSubject] = useState<string | undefined>("ASD");
|
const [subject, setSubject] = useState<string | undefined>("ASD");
|
||||||
@ -285,7 +287,7 @@ export function PaytoWireTransferForm({
|
|||||||
|
|
||||||
<div class="sm:col-span-5">
|
<div class="sm:col-span-5">
|
||||||
<label for="amount" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Amount`}</label>
|
<label for="amount" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Amount`}</label>
|
||||||
<Amount
|
<InputAmount
|
||||||
name="amount"
|
name="amount"
|
||||||
left
|
left
|
||||||
currency={limit.currency}
|
currency={limit.currency}
|
||||||
@ -372,7 +374,9 @@ export function doAutoFocus(element: HTMLElement | null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Amount(
|
const FRAC_SEPARATOR = "."
|
||||||
|
|
||||||
|
export function InputAmount(
|
||||||
{
|
{
|
||||||
currency,
|
currency,
|
||||||
name,
|
name,
|
||||||
@ -390,6 +394,7 @@ export function Amount(
|
|||||||
},
|
},
|
||||||
ref: Ref<HTMLInputElement>,
|
ref: Ref<HTMLInputElement>,
|
||||||
): VNode {
|
): VNode {
|
||||||
|
const cfg = useConfigContext()
|
||||||
return (
|
return (
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<div class="flex rounded-md shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600">
|
<div class="flex rounded-md shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600">
|
||||||
@ -409,10 +414,14 @@ export function Amount(
|
|||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
value={value ?? ""}
|
value={value ?? ""}
|
||||||
disabled={!onChange}
|
disabled={!onChange}
|
||||||
onInput={(e): void => {
|
onInput={(e) => {
|
||||||
if (onChange) {
|
if (!onChange) return;
|
||||||
onChange(e.currentTarget.value);
|
const l = e.currentTarget.value.length
|
||||||
|
const sep_pos = e.currentTarget.value.indexOf(FRAC_SEPARATOR)
|
||||||
|
if (sep_pos !== -1 && l - sep_pos - 1 > cfg.currency_fraction_limit) {
|
||||||
|
e.currentTarget.value = e.currentTarget.value.substring(0, sep_pos + cfg.currency_fraction_limit + 1)
|
||||||
}
|
}
|
||||||
|
onChange(e.currentTarget.value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -421,3 +430,21 @@ export function Amount(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function RenderAmount({ value, negative }: { value: AmountJson, negative?: boolean }): VNode {
|
||||||
|
const cfg = useConfigContext()
|
||||||
|
const str = Amounts.stringifyValue(value)
|
||||||
|
const sep_pos = str.indexOf(FRAC_SEPARATOR)
|
||||||
|
if (sep_pos !== -1 && str.length - sep_pos - 1 > cfg.currency_fraction_digits) {
|
||||||
|
const limit = sep_pos + cfg.currency_fraction_digits + 1
|
||||||
|
const normal = str.substring(0, limit)
|
||||||
|
const small = str.substring(limit)
|
||||||
|
return <span class="whitespace-nowrap">
|
||||||
|
{negative ? "-" : undefined}
|
||||||
|
{value.currency} {normal} <sup class="-ml-2">{small}</sup>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
return <span class="whitespace-nowrap">
|
||||||
|
{negative ? "-" : undefined}
|
||||||
|
{value.currency} {str}
|
||||||
|
</span>
|
||||||
|
}
|
@ -34,13 +34,13 @@ import { forwardRef } from "preact/compat";
|
|||||||
import { useEffect, useRef, useState } from "preact/hooks";
|
import { useEffect, useRef, useState } from "preact/hooks";
|
||||||
import { useAccessAPI } from "../hooks/access.js";
|
import { useAccessAPI } from "../hooks/access.js";
|
||||||
import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js";
|
import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js";
|
||||||
import { Amount, doAutoFocus } from "./PaytoWireTransferForm.js";
|
import { InputAmount, doAutoFocus } from "./PaytoWireTransferForm.js";
|
||||||
import { useSettings } from "../hooks/settings.js";
|
import { useSettings } from "../hooks/settings.js";
|
||||||
import { OperationState } from "./OperationState/index.js";
|
import { OperationState } from "./OperationState/index.js";
|
||||||
import { Attention } from "../components/Attention.js";
|
import { Attention } from "../components/Attention.js";
|
||||||
|
|
||||||
const logger = new Logger("WalletWithdrawForm");
|
const logger = new Logger("WalletWithdrawForm");
|
||||||
const RefAmount = forwardRef(Amount);
|
const RefAmount = forwardRef(InputAmount);
|
||||||
|
|
||||||
|
|
||||||
function OldWithdrawalForm({ goToConfirmOperation, limit, onCancel, focus }: {
|
function OldWithdrawalForm({ goToConfirmOperation, limit, onCancel, focus }: {
|
||||||
|
@ -38,6 +38,7 @@ import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js";
|
|||||||
import { useAccessAnonAPI } from "../hooks/access.js";
|
import { useAccessAnonAPI } from "../hooks/access.js";
|
||||||
import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js";
|
import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js";
|
||||||
import { useSettings } from "../hooks/settings.js";
|
import { useSettings } from "../hooks/settings.js";
|
||||||
|
import { RenderAmount } from "./PaytoWireTransferForm.js";
|
||||||
|
|
||||||
const logger = new Logger("WithdrawalConfirmationQuestion");
|
const logger = new Logger("WithdrawalConfirmationQuestion");
|
||||||
|
|
||||||
@ -318,7 +319,7 @@ export function WithdrawalConfirmationQuestion({
|
|||||||
<div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
<div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
||||||
<dt class="text-sm font-medium leading-6 text-gray-900">Amount</dt>
|
<dt class="text-sm font-medium leading-6 text-gray-900">Amount</dt>
|
||||||
<dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
|
<dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
|
||||||
{Amounts.currencyOf(details.amount)} {Amounts.stringifyValue(details.amount)}
|
<RenderAmount value={details.amount} />
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
|
@ -4,6 +4,7 @@ import { handleNotOkResult } from "../HomePage.js";
|
|||||||
import { AccountAction } from "./Home.js";
|
import { AccountAction } from "./Home.js";
|
||||||
import { Amounts } from "@gnu-taler/taler-util";
|
import { Amounts } from "@gnu-taler/taler-util";
|
||||||
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
||||||
|
import { RenderAmount } from "../PaytoWireTransferForm.js";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onAction: (type: AccountAction, account: string) => void;
|
onAction: (type: AccountAction, account: string) => void;
|
||||||
@ -88,12 +89,7 @@ export function AccountList({ account, onAction, onCreateAccount }: Props): VNod
|
|||||||
i18n.str`unknown`
|
i18n.str`unknown`
|
||||||
) : (
|
) : (
|
||||||
<span class="amount">
|
<span class="amount">
|
||||||
{balanceIsDebit ? <b>-</b> : null}
|
<RenderAmount value={balance} negative={balanceIsDebit} />
|
||||||
<span class="value">{`${Amounts.stringifyValue(
|
|
||||||
balance,
|
|
||||||
)}`}</span>
|
|
||||||
|
|
||||||
<span class="currency">{`${balance.currency}`}</span>
|
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
|
@ -45,7 +45,7 @@ import {
|
|||||||
undefinedIfEmpty,
|
undefinedIfEmpty,
|
||||||
} from "../../utils.js";
|
} from "../../utils.js";
|
||||||
import { handleNotOkResult } from "../HomePage.js";
|
import { handleNotOkResult } from "../HomePage.js";
|
||||||
import { Amount } from "../PaytoWireTransferForm.js";
|
import { InputAmount } from "../PaytoWireTransferForm.js";
|
||||||
import { ShowAccountDetails } from "../ShowAccountDetails.js";
|
import { ShowAccountDetails } from "../ShowAccountDetails.js";
|
||||||
import { UpdateAccountPassword } from "../UpdateAccountPassword.js";
|
import { UpdateAccountPassword } from "../UpdateAccountPassword.js";
|
||||||
|
|
||||||
@ -342,7 +342,7 @@ function CreateCashout({
|
|||||||
|
|
||||||
</label>
|
</label>
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<Amount
|
<InputAmount
|
||||||
name="amount"
|
name="amount"
|
||||||
currency={amount.currency}
|
currency={amount.currency}
|
||||||
value={form.amount}
|
value={form.amount}
|
||||||
@ -372,7 +372,7 @@ function CreateCashout({
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="balance-now">{i18n.str`Balance now`}</label>
|
<label for="balance-now">{i18n.str`Balance now`}</label>
|
||||||
<Amount
|
<InputAmount
|
||||||
name="banace-now"
|
name="banace-now"
|
||||||
currency={balance.currency}
|
currency={balance.currency}
|
||||||
value={Amounts.stringifyValue(balance)}
|
value={Amounts.stringifyValue(balance)}
|
||||||
@ -382,7 +382,7 @@ function CreateCashout({
|
|||||||
<label for="total-cost"
|
<label for="total-cost"
|
||||||
style={{ fontWeight: "bold", color: "red" }}
|
style={{ fontWeight: "bold", color: "red" }}
|
||||||
>{i18n.str`Total cost`}</label>
|
>{i18n.str`Total cost`}</label>
|
||||||
<Amount
|
<InputAmount
|
||||||
name="total-cost"
|
name="total-cost"
|
||||||
currency={balance.currency}
|
currency={balance.currency}
|
||||||
value={Amounts.stringifyValue(calc.debit)}
|
value={Amounts.stringifyValue(calc.debit)}
|
||||||
@ -390,7 +390,7 @@ function CreateCashout({
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="balance-after">{i18n.str`Balance after`}</label>
|
<label for="balance-after">{i18n.str`Balance after`}</label>
|
||||||
<Amount
|
<InputAmount
|
||||||
name="balance-after"
|
name="balance-after"
|
||||||
currency={balance.currency}
|
currency={balance.currency}
|
||||||
value={balanceAfter ? Amounts.stringifyValue(balanceAfter) : ""}
|
value={balanceAfter ? Amounts.stringifyValue(balanceAfter) : ""}
|
||||||
@ -400,7 +400,7 @@ function CreateCashout({
|
|||||||
<Fragment>
|
<Fragment>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="amount-conversiojn">{i18n.str`Amount after conversion`}</label>
|
<label for="amount-conversiojn">{i18n.str`Amount after conversion`}</label>
|
||||||
<Amount
|
<InputAmount
|
||||||
name="amount-conversion"
|
name="amount-conversion"
|
||||||
currency={fiatCurrency}
|
currency={fiatCurrency}
|
||||||
value={Amounts.stringifyValue(calc.beforeFee)}
|
value={Amounts.stringifyValue(calc.beforeFee)}
|
||||||
@ -409,7 +409,7 @@ function CreateCashout({
|
|||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label form="cashout-fee">{i18n.str`Cashout fee`}</label>
|
<label form="cashout-fee">{i18n.str`Cashout fee`}</label>
|
||||||
<Amount
|
<InputAmount
|
||||||
name="cashout-fee"
|
name="cashout-fee"
|
||||||
currency={fiatCurrency}
|
currency={fiatCurrency}
|
||||||
value={Amounts.stringifyValue(sellFee)}
|
value={Amounts.stringifyValue(sellFee)}
|
||||||
@ -421,7 +421,7 @@ function CreateCashout({
|
|||||||
<label for="total"
|
<label for="total"
|
||||||
style={{ fontWeight: "bold", color: "green" }}
|
style={{ fontWeight: "bold", color: "green" }}
|
||||||
>{i18n.str`Total cashout transfer`}</label>
|
>{i18n.str`Total cashout transfer`}</label>
|
||||||
<Amount
|
<InputAmount
|
||||||
name="total"
|
name="total"
|
||||||
currency={fiatCurrency}
|
currency={fiatCurrency}
|
||||||
value={Amounts.stringifyValue(calc.credit)}
|
value={Amounts.stringifyValue(calc.credit)}
|
||||||
|
@ -62,9 +62,9 @@ export function HistoryItem(props: { tx: Transaction }): VNode {
|
|||||||
WithdrawalType.TalerBankIntegrationApi
|
WithdrawalType.TalerBankIntegrationApi
|
||||||
? !tx.withdrawalDetails.confirmed
|
? !tx.withdrawalDetails.confirmed
|
||||||
? i18n.str`Need approval in the Bank`
|
? i18n.str`Need approval in the Bank`
|
||||||
: i18n.str`Exchange is waiting the wire transfer`
|
: i18n.str`Waiting for wire transfer to complete`
|
||||||
: tx.withdrawalDetails.type === WithdrawalType.ManualTransfer
|
: tx.withdrawalDetails.type === WithdrawalType.ManualTransfer
|
||||||
? i18n.str`Exchange is waiting the wire transfer`
|
? i18n.str`Waiting for wire transfer to complete`
|
||||||
: "" //pending but no message
|
: "" //pending but no message
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user