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 ?? '')} )} ); })} ))}
); }