use micros converters in FormCurrencyFieldInput (#16330)
Fixes: #15887 The currency fields were expecting values in micros (multiplied by 10^6), but this requirement was not indicated anywhere in the workflow UI. Users had to manually add a code node to multiply amounts by 10^6 before using the new currency value. This change integrates the micros conversion logic directly into FormCurrencyFieldInput by using convertCurrencyAmountToCurrencyMicros and convertCurrencyMicrosToCurrencyAmount utilities. This allows users to input human-readable decimal amounts (e.g., 3.21 for $3.21) in the form, which are automatically converted to micros internally for storage and processing. This eliminates the need for users to add separate code nodes for conversion and improves the user experience by making the expected input format clear.
This commit is contained in:
+32
-4
@@ -9,6 +9,34 @@ import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
import { useMemo } from 'react';
|
||||
import { type CurrencyCode } from 'twenty-shared/constants';
|
||||
import { IconCircleOff } from 'twenty-ui/display';
|
||||
import {
|
||||
convertCurrencyAmountToCurrencyMicros,
|
||||
convertCurrencyMicrosToCurrencyAmount,
|
||||
} from '~/utils/convertCurrencyToCurrencyMicros';
|
||||
|
||||
const formatMicrosToDisplayAmount = (
|
||||
amountMicros: string | number | null | undefined,
|
||||
): string | number => {
|
||||
if (amountMicros == null) {
|
||||
return '';
|
||||
}
|
||||
if (Number.isFinite(+amountMicros)) {
|
||||
return convertCurrencyMicrosToCurrencyAmount(+amountMicros);
|
||||
}
|
||||
return amountMicros;
|
||||
};
|
||||
|
||||
const parseDisplayAmountToMicros = (
|
||||
displayAmount: string | number | null,
|
||||
): number | null => {
|
||||
if (displayAmount == null) {
|
||||
return null;
|
||||
}
|
||||
if (Number.isFinite(+displayAmount)) {
|
||||
return convertCurrencyAmountToCurrencyMicros(Number(displayAmount));
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
type FormCurrencyFieldInputProps = {
|
||||
label?: string;
|
||||
@@ -41,7 +69,7 @@ export const FormCurrencyFieldInput = ({
|
||||
) => {
|
||||
onChange({
|
||||
currencyCode: defaultValue?.currencyCode ?? null,
|
||||
amountMicros: newAmountMicros ?? null,
|
||||
amountMicros: parseDisplayAmountToMicros(newAmountMicros),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -65,11 +93,11 @@ export const FormCurrencyFieldInput = ({
|
||||
readonly={readonly}
|
||||
/>
|
||||
<FormNumberFieldInput
|
||||
label="Amount Micros"
|
||||
defaultValue={defaultValue?.amountMicros ?? ''}
|
||||
label="Amount"
|
||||
defaultValue={formatMicrosToDisplayAmount(defaultValue?.amountMicros)}
|
||||
onChange={handleAmountMicrosChange}
|
||||
VariablePicker={VariablePicker}
|
||||
placeholder="Set 3210000 for $3.21"
|
||||
placeholder="Set 3.21 for $3.21"
|
||||
readonly={readonly}
|
||||
/>
|
||||
</FormNestedFieldInputContainer>
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@ export const Default: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await canvas.findByText('Currency Code');
|
||||
await canvas.findByText('Amount Micros');
|
||||
await canvas.findByText('Amount');
|
||||
},
|
||||
};
|
||||
|
||||
@@ -81,7 +81,7 @@ export const Disabled: Story = {
|
||||
const currency = await canvas.findByText(/USD/);
|
||||
expect(currency).toBeVisible();
|
||||
|
||||
const amountInput = await canvas.findByDisplayValue('44000000');
|
||||
const amountInput = await canvas.findByDisplayValue('44');
|
||||
expect(amountInput).toBeVisible();
|
||||
expect(amountInput).toBeDisabled();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user