/** * 통화 금액 입력 필드 * 천단위 콤마 포맷, 통화 기호 prefix 지원 * * properties: { currency, precision, showSymbol, allowNegative } * 저장값: number (포맷 없이) */ 'use client'; import { useState, useCallback } from 'react'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import type { DynamicFieldRendererProps, CurrencyConfig } from '../types'; const CURRENCY_SYMBOLS: Record = { KRW: '\u20A9', USD: '$', EUR: '\u20AC', JPY: '\u00A5', CNY: '\u00A5', GBP: '\u00A3', }; function formatCurrency(num: number, precision: number): string { const fixed = num.toFixed(precision); const [intPart, decPart] = fixed.split('.'); const formatted = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ','); return decPart !== undefined ? `${formatted}.${decPart}` : formatted; } function parseCurrency(str: string): number { const cleaned = str.replace(/[^0-9.\-]/g, ''); const num = parseFloat(cleaned); return isNaN(num) ? 0 : num; } export function CurrencyField({ field, value, onChange, error, disabled, }: DynamicFieldRendererProps) { const fieldKey = field.field_key || `field_${field.id}`; const config = (field.properties || {}) as CurrencyConfig; const currency = config.currency || 'KRW'; const precision = config.precision ?? 0; const showSymbol = config.showSymbol !== false; const allowNegative = config.allowNegative === true; const symbol = CURRENCY_SYMBOLS[currency] || currency; const numericValue = value !== null && value !== undefined ? Number(value) : null; const [isFocused, setIsFocused] = useState(false); const [inputValue, setInputValue] = useState( numericValue !== null ? String(numericValue) : '' ); const handleFocus = useCallback(() => { setIsFocused(true); setInputValue(numericValue !== null ? String(numericValue) : ''); }, [numericValue]); const handleBlur = useCallback(() => { setIsFocused(false); if (inputValue === '' || inputValue === '-') { onChange(null); return; } const parsed = parseCurrency(inputValue); const final = allowNegative ? parsed : Math.abs(parsed); onChange(final); }, [inputValue, onChange, allowNegative]); const handleChange = useCallback((e: React.ChangeEvent) => { const raw = e.target.value; // 숫자, 점, 마이너스만 허용 const pattern = allowNegative ? /[^0-9.\-]/g : /[^0-9.]/g; const cleaned = raw.replace(pattern, ''); setInputValue(cleaned); }, [allowNegative]); const displayValue = isFocused ? inputValue : numericValue !== null ? formatCurrency(numericValue, precision) : ''; return (
{showSymbol && ( {symbol} )}
{error && (

{error}

)} {!error && field.description && (

* {field.description}

)}
); }