/** * πŸ“„ EditableFormTable Component * νŽΈμ§‘ κ°€λŠ₯ν•œ 폼 ν…Œμ΄λΈ” μ»΄ν¬λ„ŒνŠΈ * * - react-hook-formκ³Ό ν†΅ν•©λœ νŽΈμ§‘ κ°€λŠ₯ν•œ ν…Œμ΄λΈ” λ Œλ”λ§ * - ν•„λ“œ λ°°μ—΄ 기반 동적 ν–‰ 생성 및 관리 * - 숫자 μž…λ ₯ 검증 (μ†Œμˆ˜μ  및 유효 문자 μ œν•œ) * - ν…Œμ΄λΈ” 헀더 및 μ…€ μŠ€νƒ€μΌλ§ 및 μ •λ ¬ 지원 * - Controllerλ₯Ό ν†΅ν•œ 폼 μƒνƒœ 관리 및 μœ νš¨μ„± 검사 * - μ»€μŠ€ν…€ μž…λ ₯ ν•„λ“œ 클래슀 및 속성 지원 */ import { Input, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@common/components/ui"; import type { UseFormReturn, FieldArrayWithId, Path, FieldValues } from "react-hook-form"; import { Controller } from "react-hook-form"; // νŽΈμ§‘ κ°€λŠ₯ν•œ ν…Œμ΄λΈ” 헀더 ν•­λͺ© μΈν„°νŽ˜μ΄μŠ€ export interface EditableTableHeadItem { id: keyof TItem | 'response'; // 'response'λŠ” 직접적인 ν‚€κ°€ 아닐 수 μžˆμ§€λ§Œ νŠΉλ³„νžˆ 처리될 수 있음 title: string; editable?: boolean; // νŽΈμ§‘ κ°€λŠ₯ μ—¬λΆ€ width?: string; // 컬럼 λ„ˆλΉ„ μΆ”κ°€ align?: 'left' | 'center' | 'right'; // μ •λ ¬ cellClassName?: string; // μ…€ 클래슀 이름 inputClassName?: string; // μž…λ ₯ ν•„λ“œ 클래슀 이름 inputProps?: React.ComponentProps; // Input μ»΄ν¬λ„ŒνŠΈμ— 전달할 props (예: type="number") } // EditableFormTable μ»΄ν¬λ„ŒνŠΈ props νƒ€μž… μ •μ˜ type EditableFormTableProps< TFormValues extends FieldValues, TFieldArrayName extends Path, TFieldArrayItem extends FieldValues = TFormValues[TFieldArrayName] extends (infer U)[] ? U extends FieldValues ? U : never : never > = { form: UseFormReturn; // react-hook-form의 form 객체 name: TFieldArrayName; // ν•„λ“œ λ°°μ—΄ 이름 (예: "unitFactors") fields: FieldArrayWithId[]; // useFieldArrayμ—μ„œ λ°˜ν™˜λœ ν•„λ“œ λ°°μ—΄ headlist: EditableTableHeadItem[]; // ν…Œμ΄λΈ” 헀더 μ„€μ • tableClassName?: string; // ν…Œμ΄λΈ” 클래슀 이름 headerClassName?: string; // 헀더 클래슀 이름 bodyClassName?: string; // λ°”λ”” 클래슀 이름 rowClassName?: string; // ν–‰ 클래슀 이름 }; // EditableFormTable μ»΄ν¬λ„ŒνŠΈ export function EditableFormTable< TFormValues extends FieldValues, TFieldArrayName extends Path, TFieldArrayItem extends FieldValues = TFormValues[TFieldArrayName] extends (infer U)[] ? U extends FieldValues ? U : never : never >({ form, name, fields, headlist, tableClassName = "w-full", headerClassName = "font-bold", bodyClassName = 'text-center', rowClassName = "", }: EditableFormTableProps) { return (
{headlist.map((head) => ( {head.title} ))} {fields.map((rowItem, rowIndex) => ( {headlist.map((head) => { const fieldName = `${name}.${rowIndex}.${String(head.id)}` as Path; const cellValue = (rowItem as any)[head.id as string]; return ( {head.editable ? ( { const handleChange = (e: React.ChangeEvent) => { const newValue = e.target.value; if (newValue === "") { field.onChange(""); // 빈 λ¬Έμžμ—΄ ν—ˆμš© return; } // μˆ«μžμ™€ '.'만 ν—ˆμš© (단일 '.' ν—ˆμš©) const isValidChars = /^[0-9]*\.?[0-9]*$/.test(newValue); if (!isValidChars) { return; // μœ νš¨ν•˜μ§€ μ•Šμ€ 문자 λ˜λŠ” μ—¬λŸ¬ 개의 '.' 포함 μ‹œ λ³€κ²½ λ¬΄μ‹œ } // '.' κΈ°ν˜Έκ°€ ν¬ν•¨λœ 경우, μ²˜μŒμ—λŠ” 올 수 μ—†μŒ (예: '.5' λ°©μ§€, '0.5' μœ λ„) // 이 쑰건은 μ‚¬μš©μžμ˜ μš”κ΅¬μ‚¬ν•­μ— 따라 쑰정될 수 μžˆμŠ΅λ‹ˆλ‹€. // ν˜„μž¬ λ‘œμ§μ€ '.5'와 같은 μž…λ ₯을 ν—ˆμš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. if (newValue.includes('.') && newValue.startsWith('.')) { // λ§Œμ•½ '.'만 μž…λ ₯된 경우 ν—ˆμš©ν•˜λ €λ©΄ μ•„λž˜ 주석 ν•΄μ œ // if (newValue === '.') { // field.onChange(newValue); // return; // } return; } field.onChange(newValue); }; return ( ); }} /> ) : ( {String(cellValue ?? '')} )} ); })} ))}
); }