aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/taler-wallet-webextension/src/components/AmountField.stories.tsx11
-rw-r--r--packages/taler-wallet-webextension/src/components/AmountField.tsx152
2 files changed, 81 insertions, 82 deletions
diff --git a/packages/taler-wallet-webextension/src/components/AmountField.stories.tsx b/packages/taler-wallet-webextension/src/components/AmountField.stories.tsx
index f253d1996..9ac17155c 100644
--- a/packages/taler-wallet-webextension/src/components/AmountField.stories.tsx
+++ b/packages/taler-wallet-webextension/src/components/AmountField.stories.tsx
@@ -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>
);
diff --git a/packages/taler-wallet-webextension/src/components/AmountField.tsx b/packages/taler-wallet-webextension/src/components/AmountField.tsx
index 786244433..88ac71dd8 100644
--- a/packages/taler-wallet-webextension/src/components/AmountField.tsx
+++ b/packages/taler-wallet-webextension/src/components/AmountField.tsx
@@ -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 currency = handler.value.currency;
+ const [error, setError] = useState<string>("");
- let hd = Math.floor(Math.log10(highestDenom || 1) / 3);
- let ld = Math.ceil((-1 * Math.log10(lowestDenom || 1)) / 3);
+ const normal = normalize(handler.value, unit);
+ const previousValue = Amounts.stringifyValue(normal);
- const currencyLabels: Array<{ name: string; unit: number }> = [
- {
- name: currency,
- unit: 1,
- },
- ];
+ const [textValue, setTextValue] = useState<string>(previousValue);
- 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--;
+ function updateUnit(newUnit: number) {
+ setUnit(newUnit);
+ const newNorm = normalize(handler.value, newUnit);
+ setTextValue(Amounts.stringifyValue(newNorm));
}
- const previousValue = Amounts.stringifyValue(handler.value, decimalPlaces);
-
- const normal = normalize(handler.value, unit) ?? handler.value;
+ const currency = handler.value.currency;
- 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);
-
- //FIXME: should normalize before parsing
- //parsing first add some restriction on the rage of the values
- const parsed = parseValue(currency, withoutDots);
-
- if (!parsed || parsed.value < 0) {
- return previousValue;
- }
+ } else
+ try {
+ const parsed = Amounts.parseOrThrow(`${currency}:${value.trim()}`);
- const realValue = denormalize(parsed, unit);
+ const realValue = denormalize(parsed, unit);
- // console.log(real, unit, normal);
- if (realValue && handler.onInput) {
- handler.onInput(realValue);
+ if (handler.onInput) {
+ handler.onInput(realValue);
+ }
+ setError("");
+ } catch (e) {
+ setError(i18n.str`Amount is not valid`);
}
- 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;
+}