/** * πŸ“„ VerticalTable Component * μ„Έλ‘œ λ°©ν–₯ ν…Œμ΄λΈ” μ»΄ν¬λ„ŒνŠΈ * * - μ„Έλ‘œ λ°©ν–₯ ν…Œμ΄λΈ” λ Œλ”λ§ 및 데이터 ν‘œμ‹œ * - νŽΈμ§‘ κ°€λŠ₯ ν•„λ“œ 지원 (select, input νƒ€μž…) * - μž…λ ₯ κ°’ 검증 및 μ—λŸ¬ λ©”μ‹œμ§€ ν‘œμ‹œ * - νŽ˜μ΄μ§€λ„€μ΄μ…˜ 및 데이터 νŽ˜μ΄μ§• 처리 * - 두 개의 ν…Œμ΄λΈ” λ™μ‹œ ν‘œμ‹œ 지원 * - 폼 데이터 λ³€κ²½ 콜백 및 μ €μž₯ κΈ°λŠ₯ */ import UiPageNations from "@common/business_components/ui/table/uiPageNations"; import { Button, Table, TableBody, TableCell, TableRow, } from "@common/components"; import { useEffect, useState } from "react"; type UiTableProps = { headName: React.ReactNode | undefined; tableName1?: React.ReactNode | undefined; tableData: { [key: string]: string | number | boolean | object }[]; headlist: UiHeadProps[]; pageSize: number; total: number; children?: Record | undefined; cellClick: ((index: number | undefined, headId: string) => void) | undefined; onPageChange: (page: number) => void; className?: string; resetPageNo?: boolean; isEditable?: boolean; tableName2?: React.ReactNode | undefined; tableData2?: { [key: string]: string | number | boolean | object }[]; headlist2?: UiHeadProps[]; pageSize2?: number; total2?: number; children2?: Record | undefined; cellClick2?: | ((index: number | undefined, headId: string) => void) | undefined; onPageChange2?: (page: number) => void; className2?: string; resetPageNo2?: boolean; isEditable2?: boolean; showSecondTable?: boolean; showSaveButton?: boolean; onSaveClick?: () => void; onFormDataChange?: (formData: { [key: string]: string | number | boolean; }) => void; // μΆ”κ°€ }; type UiSelectOption = | string | { value?: string | number; label?: string; val?: string | number; text?: string; hidden?: boolean; }; type UiHeadProps = { id: string; title: string; align?: string; type?: string; options?: UiSelectOption[]; placeholder?: string; isNumber?: boolean; length?: number; required?: boolean; }; const getSelectOptionValue = (option: UiSelectOption) => typeof option === "string" ? option : String(option.value ?? option.val ?? ""); const getSelectOptionLabel = (option: UiSelectOption) => typeof option === "string" ? option : String(option.label ?? option.text ?? getSelectOptionValue(option)); const isSelectOptionHidden = (option: UiSelectOption) => typeof option === "string" ? false : Boolean(option.hidden); export function VerticalTable({ headName, tableName1, tableData, headlist, pageSize, total, children, onPageChange, className = "", resetPageNo = false, isEditable = false, tableName2, headlist2, isEditable2 = false, showSecondTable = false, showSaveButton = false, onSaveClick, onFormDataChange, }: UiTableProps) { const [cur, setCur] = useState(1); const [formData, setFormData] = useState<{ [key: string]: string | number | boolean; }>({}); const [errors, setErrors] = useState<{ [key: string]: string }>({}); useEffect(() => { if (resetPageNo) { setCur(1); onPageChange(1); } }, [onPageChange, resetPageNo]); useEffect(() => { if (tableData.length > 0 && tableData[0]) { const newData = JSON.parse(JSON.stringify(tableData[0])); setFormData(newData); setErrors({}); } }, [tableData]); const handleInputChange = (id: string, value: string | number | boolean) => { const newFormData = { ...formData, [id]: value, }; setFormData(newFormData); if (errors[id]) { setErrors((prev) => { const newErrors = { ...prev }; delete newErrors[id]; return newErrors; }); } if (onFormDataChange) { onFormDataChange(newFormData); } }; const handlePageChange = (page: number) => { setCur(page); onPageChange(page); }; const showError = (fieldId: string, message: string) => { setErrors((prev) => ({ ...prev, [fieldId]: message, })); }; return ( <> {headName ? (

{headName}

{showSaveButton && onSaveClick && ( )}
) : null}
{tableName1 && ( // tableName prop이 있으면 ν‘œμ‹œ
{tableName1}
)} {headlist?.map((head) => ( {/* 컬럼 제λͺ© */} {head.title} {head.required ? ( * ) : null} {/* 데이터 κ°’ λ˜λŠ” μž…λ ₯ ν•„λ“œ */} {children && children[head.id] ? ( children[head.id] ) : isEditable ? ( head.type === "select" ? ( ) : head.type === "input" || head.type === "date" ? (
{ if (head.isNumber) { const newValue = e.target.value; if (newValue === "") { handleInputChange(head.id, newValue); return; } const isValidNumber = /^[0-9]+$/.test(newValue); if (!isValidNumber) { showError( head.id, `${head.title}λŠ” 숫자만 μž…λ ₯ κ°€λŠ₯ν•©λ‹ˆλ‹€.`, ); return; } if ( head.length && newValue.length > head.length ) { showError( head.id, `${head.title}λŠ” μ΅œλŒ€ ${head.length}μžκΉŒμ§€ μž…λ ₯ κ°€λŠ₯ν•©λ‹ˆλ‹€.`, ); return; } const numericValue = parseInt(newValue); if (isNaN(numericValue) || numericValue < 0) return; handleInputChange(head.id, numericValue); } else { const newValue = e.target.value; if ( head.length && newValue.length > head.length ) { showError( head.id, `${head.title}λŠ” μ΅œλŒ€ ${head.length}μžκΉŒμ§€ μž…λ ₯ κ°€λŠ₯ν•©λ‹ˆλ‹€.`, ); return; } handleInputChange(head.id, e.target.value); } }} className="border-radius-0 w-full rounded-sm border border-border px-2 py-1 text-xl" placeholder={head.placeholder} /> {errors[head.id] && (
{errors[head.id]}
)}
) : ( {formData[head.id] ?? "-"} ) ) : ( {formData[head.id] ?? "-"} )}
))}
{tableName2 && ( // tableName prop이 있으면 ν‘œμ‹œ
{tableName2}
)} {showSecondTable && ( {headlist2?.map((head) => ( {/* 컬럼 제λͺ© */} {head.title} {head.required ? ( * ) : null} {/* 데이터 κ°’ λ˜λŠ” μž…λ ₯ ν•„λ“œ */} {children && children[head.id] ? ( children[head.id] ) : isEditable2 ? ( head.type === "select" ? ( ) : head.type === "input" || head.type === "date" ? (
{ if (head.isNumber) { const newValue = e.target.value; if (newValue === "") { handleInputChange(head.id, newValue); return; } const isValidNumber = /^[0-9]+$/.test(newValue); if (!isValidNumber) { showError( head.id, `${head.title}λŠ” 숫자만 μž…λ ₯ κ°€λŠ₯ν•©λ‹ˆλ‹€.`, ); return; } if ( head.length && newValue.length > head.length ) { showError( head.id, `${head.title}λŠ” μ΅œλŒ€ ${head.length}μžκΉŒμ§€ μž…λ ₯ κ°€λŠ₯ν•©λ‹ˆλ‹€.`, ); return; } const numericValue = parseInt(newValue); if (isNaN(numericValue) || numericValue < 0) return; handleInputChange(head.id, numericValue); } else { const newValue = e.target.value; if ( head.length && newValue.length > head.length ) { showError( head.id, `${head.title}λŠ” μ΅œλŒ€ ${head.length}μžκΉŒμ§€ μž…λ ₯ κ°€λŠ₯ν•©λ‹ˆλ‹€.`, ); return; } handleInputChange(head.id, e.target.value); } }} className="border-radius-0 w-full rounded-sm border border-border px-2 py-1 text-xl" placeholder={head.placeholder} /> {errors[head.id] && (
{errors[head.id]}
)}
) : ( {formData[head.id] ?? "-"} ) ) : ( {formData[head.id] ?? "-"} )}
))}
)} {total > 0 && ( )}
); }