feat: implement CurrencyService for formatting and parsing currency values, update InputCurrency component, and add tests
This commit is contained in:
@@ -1,40 +1,55 @@
|
||||
import { CurrencyService } from '@repo/utils';
|
||||
import { InputCurrencyProps } from '../types';
|
||||
import { InputNumber } from './input-number.component';
|
||||
|
||||
/**
|
||||
* InputCurrency
|
||||
*
|
||||
* A controlled InputNumber component with currency formatting.
|
||||
* Delegates all formatting/parsing to CurrencyService.
|
||||
*
|
||||
* Features:
|
||||
* - Display currency prefix (e.g., Rp, $)
|
||||
* - Thousand separator formatting
|
||||
* - Optional decimal rounding
|
||||
* - Global prefix support via CurrencyService
|
||||
*/
|
||||
export const InputCurrency = (props: InputCurrencyProps) => {
|
||||
const { prefix = 'Rp ', ...restProps } = props;
|
||||
const {
|
||||
prefix, // Optional override for instance prefix
|
||||
decimalSeparator, // Optional override for separator
|
||||
decimalScale, // Optional rounding
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
// Change format from 10000 to "Rp 10.000"
|
||||
const formatCurrency = (value: number | string | undefined) => {
|
||||
if (value === undefined || value === null || value === '') {
|
||||
return '';
|
||||
}
|
||||
// Convert value to string for processing
|
||||
const valStr = `${value}`;
|
||||
const formatted = valStr.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
|
||||
return `${prefix}${formatted}`;
|
||||
// Create a CurrencyService instance for this input
|
||||
const currencyService = new CurrencyService({
|
||||
prefix,
|
||||
decimalSeparator,
|
||||
decimalScale,
|
||||
});
|
||||
|
||||
/**
|
||||
* Formatter: converts numeric value to formatted string for display
|
||||
*/
|
||||
const formatter = (value: number | string | undefined) => {
|
||||
return currencyService.format(value);
|
||||
};
|
||||
|
||||
// Change parse from "Rp 10.000" to 10000
|
||||
const parseCurrency = (displayValue: string | undefined) => {
|
||||
if (!displayValue) return '';
|
||||
|
||||
// Remove prefix and all non-digit characters (except comma if decimal support is needed)
|
||||
// Here we assume pure integer input, so dots (.) are removed.
|
||||
const cleanValue = displayValue.replace(prefix, '').replace(/\./g, '');
|
||||
|
||||
// If you need decimal support (comma), use this regex instead:
|
||||
// return displayValue.replace(prefix, '').replace(/\./g, '').replace(/,/g, '.');
|
||||
|
||||
return cleanValue;
|
||||
/**
|
||||
* Parser: converts formatted string back to raw numeric string
|
||||
* Note: never rounds or modifies the underlying value
|
||||
*/
|
||||
const parser = (displayValue: string | undefined) => {
|
||||
return currencyService.parse(displayValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<InputNumber
|
||||
{...restProps}
|
||||
formatter={formatCurrency}
|
||||
parser={parseCurrency}
|
||||
// Ensure minimum value is 0 for currency input
|
||||
formatter={formatter}
|
||||
parser={parser}
|
||||
// Default min value to 0 for currency
|
||||
min={props.min !== undefined ? props.min : 0}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -53,6 +53,8 @@ export interface InputPasswordProps extends InputProps {
|
||||
export interface InputNumberProps extends RcInputNumberProps, BaseComponentProps {}
|
||||
export interface InputCurrencyProps extends InputNumberProps, BaseComponentProps {
|
||||
prefix?: string; // Optional: Custom prefix, default 'Rp '
|
||||
decimalSeparator?: ',' | '.';
|
||||
decimalScale?: number; // optional
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user