This commit is contained in:
Sebastian 2023-02-28 07:41:51 -03:00
parent ed7aa0806d
commit 04eec324bf
No known key found for this signature in database
GPG Key ID: 173909D1A5F66069
2 changed files with 85 additions and 86 deletions

View File

@ -31,7 +31,11 @@ export default {
};
function RenderAmount(): VNode {
const [value, setValue] = useState<AmountJson | undefined>(undefined);
const [value, setValue] = useState<AmountJson | undefined>({
currency: "USD",
value: 1,
fraction: 0,
});
const error = value === undefined ? undefined : undefined;
@ -53,7 +57,10 @@ function RenderAmount(): VNode {
handler={handler}
/>
<p>
<pre>{JSON.stringify(value, undefined, 2)}</pre>
<pre>
value : {value?.value} <br />
fraction : {value?.fraction}
</pre>
</p>
</Fragment>
);

View File

@ -25,6 +25,7 @@ import {
} from "@gnu-taler/taler-util";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { useTranslationContext } from "../context/translation.js";
import { AmountFieldHandler } from "../mui/handlers.js";
import { TextField } from "../mui/TextField.js";
@ -47,80 +48,49 @@ export function AmountField({
required?: boolean;
handler: AmountFieldHandler;
}): VNode {
const { i18n } = useTranslationContext();
const [unit, setUnit] = useState(1);
const [decimalPlaces, setDecimalPlaces] = useState<number | undefined>(
undefined,
);
const [error, setError] = useState<string>("");
const normal = normalize(handler.value, unit);
const previousValue = Amounts.stringifyValue(normal);
const [textValue, setTextValue] = useState<string>(previousValue);
function updateUnit(newUnit: number) {
setUnit(newUnit);
const newNorm = normalize(handler.value, newUnit);
setTextValue(Amounts.stringifyValue(newNorm));
}
const currency = handler.value.currency;
let hd = Math.floor(Math.log10(highestDenom || 1) / 3);
let ld = Math.ceil((-1 * Math.log10(lowestDenom || 1)) / 3);
const currencyLabels: Array<{ name: string; unit: number }> = [
{
name: currency,
unit: 1,
},
];
while (hd > 0) {
currencyLabels.push({
name: `${HIGH_DENOM_SYMBOL[hd]}${currency}`,
unit: Math.pow(10, hd * 3),
});
hd--;
}
while (ld > 0) {
currencyLabels.push({
name: `${LOW_DENOM_SYMBOL[ld]}${currency}`,
unit: Math.pow(10, -1 * ld * 3),
});
ld--;
}
const previousValue = Amounts.stringifyValue(handler.value, decimalPlaces);
const normal = normalize(handler.value, unit) ?? handler.value;
let textValue = Amounts.stringifyValue(normal, decimalPlaces);
if (decimalPlaces === 0) {
textValue += ".";
}
const currencyLabels = buildLabelsForCurrency(
currency,
lowestDenom,
highestDenom,
);
function positiveAmount(value: string): string {
// setDotAtTheEnd(value.endsWith("."));
// const dotAtTheEnd = value.endsWith(".");
if (!value) {
if (handler.onInput) {
handler.onInput(Amounts.zeroOfCurrency(currency));
}
return "";
}
try {
//remove all but last dot
const withoutDots = value.replace(/(\.)(?=.*\1)/g, "");
const parts = withoutDots.split(".");
setDecimalPlaces(parts.length === 1 ? undefined : parts[1].length);
} else
try {
const parsed = Amounts.parseOrThrow(`${currency}:${value.trim()}`);
//FIXME: should normalize before parsing
//parsing first add some restriction on the rage of the values
const parsed = parseValue(currency, withoutDots);
const realValue = denormalize(parsed, unit);
if (!parsed || parsed.value < 0) {
return previousValue;
if (handler.onInput) {
handler.onInput(realValue);
}
setError("");
} catch (e) {
setError(i18n.str`Amount is not valid`);
}
const realValue = denormalize(parsed, unit);
// console.log(real, unit, normal);
if (realValue && handler.onInput) {
handler.onInput(realValue);
}
return withoutDots;
} catch (e) {
// do nothing
}
return previousValue;
setTextValue(value);
return value;
}
return (
@ -149,7 +119,7 @@ export function AmountField({
disabled={!handler.onInput}
onChange={(e) => {
const unit = Number.parseFloat(e.currentTarget.value);
setUnit(unit);
updateUnit(unit);
}}
value={String(unit)}
style={{
@ -171,29 +141,11 @@ export function AmountField({
disabled={!handler.onInput}
onInput={positiveAmount}
/>
{error && <div style={{ color: "red" }}>{error}</div>}
</Fragment>
);
}
function parseValue(currency: string, s: string): AmountJson | undefined {
const [intPart, fractPart] = s.split(".");
const tailPart = !fractPart
? "0"
: fractPart.substring(0, amountFractionalLength);
const value = Number.parseInt(intPart, 10);
const parsedTail = Number.parseFloat(`.${tailPart}`);
if (Number.isNaN(value) || Number.isNaN(parsedTail)) {
return undefined;
}
if (value > amountMaxValue) {
return undefined;
}
const fraction = Math.round(amountFractionalBase * parsedTail);
return { currency, fraction, value };
}
/**
* Return the real value of a normalized unit
* If the value is 20 and the unit is kilo == 1000 the returned value will be amount * 1000
@ -201,7 +153,7 @@ function parseValue(currency: string, s: string): AmountJson | undefined {
* @param unit
* @returns
*/
function denormalize(amount: AmountJson, unit: number): AmountJson | undefined {
function denormalize(amount: AmountJson, unit: number): AmountJson {
if (unit === 1 || Amounts.isZero(amount)) return amount;
const result =
unit < 1
@ -218,7 +170,7 @@ function denormalize(amount: AmountJson, unit: number): AmountJson | undefined {
* @param unit
* @returns
*/
function normalize(amount: AmountJson, unit: number): AmountJson | undefined {
function normalize(amount: AmountJson, unit: number): AmountJson {
if (unit === 1 || Amounts.isZero(amount)) return amount;
const result =
unit < 1
@ -226,3 +178,43 @@ function normalize(amount: AmountJson, unit: number): AmountJson | undefined {
: Amounts.divide(amount, unit);
return result;
}
/**
* Take every label in HIGH_DENOM_SYMBOL and LOW_DENOM_SYMBOL and create
* which create the corresponding unit multiplier
* @param currency
* @param lowestDenom
* @param highestDenom
* @returns
*/
function buildLabelsForCurrency(
currency: string,
lowestDenom: number,
highestDenom: number,
): Array<{ name: string; unit: number }> {
let hd = Math.floor(Math.log10(highestDenom || 1) / 3);
let ld = Math.ceil((-1 * Math.log10(lowestDenom || 1)) / 3);
const result: Array<{ name: string; unit: number }> = [
{
name: currency,
unit: 1,
},
];
while (hd > 0) {
result.push({
name: `${HIGH_DENOM_SYMBOL[hd]}${currency}`,
unit: Math.pow(10, hd * 3),
});
hd--;
}
while (ld > 0) {
result.push({
name: `${LOW_DENOM_SYMBOL[ld]}${currency}`,
unit: Math.pow(10, -1 * ld * 3),
});
ld--;
}
return result;
}