From 021321f0d9228d0df16f8591bba85c697dfe99af Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Tue, 7 Nov 2023 20:17:32 +0000 Subject: [PATCH] handle number validation --- .../Web3/components/Conversion/Conversion.tsx | 2 +- src/features/Web3/components/Form/Form.tsx | 10 ++++++++-- .../Web3/components/Input/InputGroup.tsx | 10 ++++++++-- .../Web3/components/TokenSelect/Token.tsx | 5 +++-- src/features/Web3/lib/normalizeAmount/index.ts | 1 + .../lib/normalizeAmount/normalizeAmount.test.ts | 17 +++++++++++++++++ .../Web3/lib/normalizeAmount/normalizeAmount.ts | 9 +++++++++ src/features/Web3/stores/send.ts | 9 ++++++++- 8 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 src/features/Web3/lib/normalizeAmount/index.ts create mode 100644 src/features/Web3/lib/normalizeAmount/normalizeAmount.test.ts create mode 100644 src/features/Web3/lib/normalizeAmount/normalizeAmount.ts diff --git a/src/features/Web3/components/Conversion/Conversion.tsx b/src/features/Web3/components/Conversion/Conversion.tsx index 5f4b6f4c..4d233070 100644 --- a/src/features/Web3/components/Conversion/Conversion.tsx +++ b/src/features/Web3/components/Conversion/Conversion.tsx @@ -12,7 +12,7 @@ export function Conversion(): ReactElement { const [euro, setEuro] = useState('0.00') useEffect(() => { - if (!selectedToken?.price || !amount) { + if (!selectedToken?.price || !amount || amount === '') { setDollar('0.00') setEuro('0.00') return diff --git a/src/features/Web3/components/Form/Form.tsx b/src/features/Web3/components/Form/Form.tsx index 59eb8f60..7ed1d629 100644 --- a/src/features/Web3/components/Form/Form.tsx +++ b/src/features/Web3/components/Form/Form.tsx @@ -3,7 +3,12 @@ import { useAccount } from 'wagmi' import { InputGroup } from '../Input' import styles from './Form.module.css' import { useStore } from '@nanostores/react' -import { $selectedToken, $isInitSend, $amount } from '@features/Web3/stores' +import { + $selectedToken, + $isInitSend, + $amount, + $setAmount +} from '@features/Web3/stores' import siteConfig from '@config/blog.config' import { Send } from '../Send' import { RainbowKit } from '../RainbowKit/RainbowKit' @@ -18,6 +23,7 @@ export function Web3Form(): ReactElement { const [error, setError] = useState() + // Error Validation useEffect(() => { if (!amount || amount === '' || !selectedToken?.balance) { setError(undefined) @@ -34,7 +40,7 @@ export function Web3Form(): ReactElement { // reset amount whenever token changes useEffect(() => { if (!selectedToken) return - $amount.set('') + $setAmount('') }, [selectedToken]) return ( diff --git a/src/features/Web3/components/Input/InputGroup.tsx b/src/features/Web3/components/Input/InputGroup.tsx index 44067515..fb4d6405 100644 --- a/src/features/Web3/components/Input/InputGroup.tsx +++ b/src/features/Web3/components/Input/InputGroup.tsx @@ -3,7 +3,12 @@ import Input from '@components/Input' import { Conversion } from '../Conversion' import styles from './InputGroup.module.css' import { TokenSelect } from '../TokenSelect' -import { $amount, $isInitSend, $selectedToken } from '@features/Web3/stores' +import { + $amount, + $setAmount, + $isInitSend, + $selectedToken +} from '@features/Web3/stores' import { useStore } from '@nanostores/react' export function InputGroup({ @@ -19,7 +24,7 @@ export function InputGroup({ const [isFocus, setIsFocus] = useState(false) function handleChange(newAmount: string) { - $amount.set(newAmount) + $setAmount(newAmount) } return ( @@ -36,6 +41,7 @@ export function InputGroup({ type="text" inputMode="decimal" pattern="[0-9.]*" + lang="en-US" value={amount} placeholder="0.00" onChange={(e) => handleChange(e.target.value)} diff --git a/src/features/Web3/components/TokenSelect/Token.tsx b/src/features/Web3/components/TokenSelect/Token.tsx index 8e0326bd..356e3c24 100644 --- a/src/features/Web3/components/TokenSelect/Token.tsx +++ b/src/features/Web3/components/TokenSelect/Token.tsx @@ -11,9 +11,10 @@ interface SelectItemProps extends HTMLAttributes { export const Token = forwardRef( ({ className, token, ...props }, forwardedRef) => { + const locale = window?.navigator?.language || 'en' const balance = token?.balance && token?.symbol - ? formatCurrency(token.balance, token.symbol, 'en', false, { + ? formatCurrency(token.balance, token.symbol, locale, false, { decimalPlaces: 3, significantFigures: 3 }) @@ -23,7 +24,7 @@ export const Token = forwardRef( token?.balance && token?.price?.usd ? token?.balance * token?.price.usd : 0 - const valueInUsdFormatted = formatCurrency(valueInUsd, 'USD', 'en') + const valueInUsdFormatted = formatCurrency(valueInUsd, 'USD', locale) return balance && parseInt(balance) !== 0 && valueInUsd >= 1 ? ( { + const result = normalizeAmount('1,234') + expect(result).toBe('1.234') +}) + +test('normalizeAmount removes non-digit and non-decimal characters', () => { + const result = normalizeAmount('1234.56abc') + expect(result).toBe('1234.56') +}) + +test('normalizeAmount removes non-digit and non-decimal characters', () => { + const result = normalizeAmount('1234,56abc') + expect(result).toBe('1234.56') +}) diff --git a/src/features/Web3/lib/normalizeAmount/normalizeAmount.ts b/src/features/Web3/lib/normalizeAmount/normalizeAmount.ts new file mode 100644 index 00000000..c0986b1f --- /dev/null +++ b/src/features/Web3/lib/normalizeAmount/normalizeAmount.ts @@ -0,0 +1,9 @@ +export function normalizeAmount(amount: string): string { + // Replace comma used as a decimal separator with a period + amount = amount.replace(',', '.') + + // Remove any non-digit or non-decimal characters + amount = amount.replace(/[^\d.]/g, '') + + return amount +} diff --git a/src/features/Web3/stores/send.ts b/src/features/Web3/stores/send.ts index f05f0bf6..413410ec 100644 --- a/src/features/Web3/stores/send.ts +++ b/src/features/Web3/stores/send.ts @@ -1,5 +1,12 @@ -import { atom } from 'nanostores' +import { action, atom } from 'nanostores' +import { normalizeAmount } from '../lib/normalizeAmount' export const $isInitSend = atom(false) export const $amount = atom('') export const $txHash = atom() + +export const $setAmount = action($amount, 'setAmount', (store, amount) => { + const normalizedAmount = normalizeAmount(amount) + store.set(normalizedAmount) + return store.get() +})