/** * πŸ“„ VerticalTable Component * μ„Έλ‘œ λ°©ν–₯ ν…Œμ΄λΈ” μ»΄ν¬λ„ŒνŠΈ * * - μ„Έλ‘œ λ°©ν–₯ ν…Œμ΄λΈ” λ Œλ”λ§ 및 데이터 ν‘œμ‹œ * - νŽΈμ§‘ κ°€λŠ₯ ν•„λ“œ 지원 (select, input νƒ€μž…) * - μž…λ ₯ κ°’ 검증 및 μ—λŸ¬ λ©”μ‹œμ§€ ν‘œμ‹œ * - νŽ˜μ΄μ§€λ„€μ΄μ…˜ 및 데이터 νŽ˜μ΄μ§• 처리 * - 두 개의 ν…Œμ΄λΈ” λ™μ‹œ ν‘œμ‹œ 지원 * - 폼 데이터 λ³€κ²½ 콜백 및 μ €μž₯ κΈ°λŠ₯ */ import UiPageNations from "@common/business_components/ui/table/uiPageNations"; import { Table, TableBody, TableCell, TableRow, Button } from "@common/components"; import { useEffect, useState } from "react"; import { confirmToast, showConfirmToast } from '@/components/ui/toast' import { toast, Toaster } from "react-hot-toast"; 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 UiHeadProps = { id: string; title: string; align?: string; type?: string; options?: string[]; placeholder?: string; isNumber?: boolean; length?: number; }; 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} {/* 데이터 κ°’ λ˜λŠ” μž…λ ₯ ν•„λ“œ */} {children && children[head.id] ? children[head.id] : isEditable ? ( head.type === "select" ? ( ) : head.type === "input" ? (
{ 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="w-full text-xl border-radius-0 border border-gray-300 rounded-sm px-2 py-1" 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} {/* 데이터 κ°’ λ˜λŠ” μž…λ ₯ ν•„λ“œ */} {children && children[head.id] ? children[head.id] : isEditable2 ? ( head.type === "select" ? ( ) : head.type === "input" ? (
{ 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="w-full text-xl border-radius-0 border border-gray-300 rounded-sm px-2 py-1" placeholder={head.placeholder} /> {errors[head.id] && (
{errors[head.id]}
)}
) : ( {formData[head.id] ?? "-"} ) ) : ( {formData[head.id] ?? "-"} )}
))}
)} {total > 0 && ( )}
); }