import { useCallback, useRef, useState } from 'react'; import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, } from '@/components/ui/input-group'; type NumberInputProps = { id?: string; name?: string; defaultValue?: number; value?: number; onValueChange?: (value: number) => void; placeholder?: string; disabled?: boolean; min?: number; max?: number; suffix?: string; className?: string; }; function formatDisplay(value: number): string { return value.toLocaleString('id-ID'); } function parseText(value: string): number { const cleaned = value.replace(/[^0-9]/g, ''); return cleaned === '' ? 0 : parseInt(cleaned, 10); } export function NumberInput({ id, name, defaultValue = 0, value, onValueChange, placeholder = '0', disabled = false, min, max, suffix, className, }: NumberInputProps) { const isControlled = value !== undefined; const [displayValue, setDisplayValue] = useState( formatDisplay(isControlled ? value : defaultValue), ); const lastValidRef = useRef(isControlled ? value : defaultValue); const [prevValue, setPrevValue] = useState(value); if (isControlled && value !== prevValue) { setPrevValue(value); setDisplayValue(formatDisplay(value)); } const handleChange = useCallback( (e: React.ChangeEvent) => { const raw = parseText(e.target.value); let clamped = raw; if (min !== undefined && raw < min) { clamped = min; } if (max !== undefined && raw > max) { clamped = max; } lastValidRef.current = clamped; setDisplayValue(formatDisplay(clamped)); onValueChange?.(clamped); }, [min, max, onValueChange], ); const handleBlur = useCallback(() => { setDisplayValue(formatDisplay(lastValidRef.current)); }, []); return ( {suffix && ( {suffix} )} ); }