fix: respect number format in currency input (#18469)

Fixed #18355 

Currency fields ignored the workspace number format when editing:
display showed e.g. 5 982,77 € (French style) but the input forced US
style (5,982.77) and rejected comma as decimal.
Fix: CurrencyInput now uses useNumberFormat() and passes the correct
thousandsSeparator and radix to the IMask input so edit mode matches the
chosen format (comma/space, dot/comma, etc.).
Files: CurrencyInput.tsx (use format for mask), new
CurrencyInput.test.tsx .

---------

Co-authored-by: root <root@dragon.second>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
kpdev
2026-03-10 09:59:31 -07:00
committed by GitHub
parent 6e628bb751
commit 25d9f2fcce
4 changed files with 94 additions and 3 deletions
@@ -54,7 +54,8 @@ export const CurrencyFieldInput = () => {
amountText: string;
currencyCode: string;
}) => {
const amount = parseFloat(amountText);
const normalizedAmountText = amountText.replace(',', '.');
const amount = parseFloat(normalizedAmountText);
const newCurrencyValue = {
amountMicros: isNaN(amount)
@@ -3,12 +3,14 @@ import { styled } from '@linaria/react';
import { useContext, useEffect, useRef, useState } from 'react';
import { useRegisterInputEvents } from '@/object-record/record-field/ui/meta-types/input/hooks/useRegisterInputEvents';
import { useNumberFormat } from '@/localization/hooks/useNumberFormat';
import { CURRENCIES } from '@/settings/data-model/constants/Currencies';
import { CurrencyPickerDropdownButton } from '@/ui/input/components/internal/currency/components/CurrencyPickerDropdownButton';
import { type Currency } from '@/ui/input/components/internal/types/Currency';
import { IMaskInput } from 'react-imask';
import { type IconComponent } from 'twenty-ui/display';
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
import { getSeparatorsForNumberFormat } from '~/utils/format/getSeparatorsForNumberFormat';
export const StyledIMaskInput = styled.div`
display: contents;
@@ -87,9 +89,13 @@ export const CurrencyInput = ({
}: CurrencyInputProps) => {
const { theme } = useContext(ThemeContext);
const [internalText, setInternalText] = useState(value);
const { numberFormat } = useNumberFormat();
const wrapperRef = useRef<HTMLInputElement>(null);
const { thousandsSeparator, radix } =
getSeparatorsForNumberFormat(numberFormat);
const handleChange = (value: string) => {
setInternalText(value);
onChange?.(value);
@@ -132,8 +138,8 @@ export const CurrencyInput = ({
<StyledIMaskInput>
<IMaskInput
mask={Number}
thousandsSeparator=","
radix="."
thousandsSeparator={thousandsSeparator}
radix={radix}
scale={decimals}
onAccept={(value: string) => handleChange(value)}
inputRef={wrapperRef}
@@ -0,0 +1,49 @@
import { NumberFormat } from '@/localization/constants/NumberFormat';
import {
getSeparatorsForNumberFormat,
type NumberFormatSeparators,
} from '~/utils/format/getSeparatorsForNumberFormat';
const expectSeparators = (
format: NumberFormat,
expected: NumberFormatSeparators,
) => {
expect(getSeparatorsForNumberFormat(format)).toEqual(expected);
};
describe('getSeparatorsForNumberFormat', () => {
it('returns comma thousands and dot radix for COMMAS_AND_DOT', () => {
expectSeparators(NumberFormat.COMMAS_AND_DOT, {
thousandsSeparator: ',',
radix: '.',
});
});
it('returns space thousands and comma radix for SPACES_AND_COMMA', () => {
expectSeparators(NumberFormat.SPACES_AND_COMMA, {
thousandsSeparator: ' ',
radix: ',',
});
});
it('returns dot thousands and comma radix for DOTS_AND_COMMA', () => {
expectSeparators(NumberFormat.DOTS_AND_COMMA, {
thousandsSeparator: '.',
radix: ',',
});
});
it('returns apostrophe thousands and dot radix for APOSTROPHE_AND_DOT', () => {
expectSeparators(NumberFormat.APOSTROPHE_AND_DOT, {
thousandsSeparator: "'",
radix: '.',
});
});
it('falls back to COMMAS_AND_DOT separators for SYSTEM', () => {
expectSeparators(NumberFormat.SYSTEM, {
thousandsSeparator: ',',
radix: '.',
});
});
});
@@ -0,0 +1,35 @@
import { NumberFormat } from '@/localization/constants/NumberFormat';
export type NumberFormatSeparators = {
thousandsSeparator: string;
radix: string;
};
export const getSeparatorsForNumberFormat = (
format: NumberFormat,
): NumberFormatSeparators => {
switch (format) {
case NumberFormat.SPACES_AND_COMMA:
return {
thousandsSeparator: ' ',
radix: ',',
};
case NumberFormat.DOTS_AND_COMMA:
return {
thousandsSeparator: '.',
radix: ',',
};
case NumberFormat.APOSTROPHE_AND_DOT:
return {
thousandsSeparator: "'",
radix: '.',
};
case NumberFormat.SYSTEM:
case NumberFormat.COMMAS_AND_DOT:
default:
return {
thousandsSeparator: ',',
radix: '.',
};
}
};