"use client"; import * as React from "react"; import { cn } from "@/lib/utils"; import { formatBusinessNumber, parseBusinessNumber, validateBusinessNumber } from "@/lib/formatters"; import { CheckCircle, XCircle } from "lucide-react"; export interface BusinessNumberInputProps extends Omit, "onChange" | "value" | "type"> { value: string; onChange: (value: string) => void; error?: boolean; showValidation?: boolean; } /** * BusinessNumberInput - 사업자번호 자동 포맷팅 입력 컴포넌트 * * 특징: * - 입력 시 자동 하이픈 삽입 (000-00-00000) * - 숫자만 입력 허용 (최대 10자리) * - onChange에는 숫자만 전달 (DB 저장용) * - 선택적 유효성 검사 표시 * * @example * */ const BusinessNumberInput = React.forwardRef( ({ className, value, onChange, error, showValidation = false, ...props }, ref) => { // 표시용 포맷된 값 const displayValue = React.useMemo(() => formatBusinessNumber(value || ""), [value]); // 유효성 검사 결과 const isValid = React.useMemo(() => { if (!showValidation || !value || value.length !== 10) return null; return validateBusinessNumber(value); }, [value, showValidation]); const handleChange = (e: React.ChangeEvent) => { const inputValue = e.target.value; // 숫자만 추출하여 전달 const numbersOnly = parseBusinessNumber(inputValue); onChange(numbersOnly); }; const handleKeyDown = (e: React.KeyboardEvent) => { // 숫자, 백스페이스, 탭, 화살표, 복사/붙여넣기 허용 const allowedKeys = [ "Backspace", "Delete", "Tab", "Escape", "Enter", "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End" ]; if (allowedKeys.includes(e.key)) return; // Ctrl/Cmd + A, C, V, X 허용 if ((e.ctrlKey || e.metaKey) && ["a", "c", "v", "x"].includes(e.key.toLowerCase())) { return; } // 숫자가 아니면 차단 if (!/^\d$/.test(e.key)) { e.preventDefault(); } }; const handlePaste = (e: React.ClipboardEvent) => { e.preventDefault(); const pastedText = e.clipboardData.getData("text"); const numbersOnly = parseBusinessNumber(pastedText); onChange(numbersOnly); }; return (
{showValidation && isValid !== null && (
{isValid ? ( ) : ( )}
)}
); } ); BusinessNumberInput.displayName = "BusinessNumberInput"; export { BusinessNumberInput };