"use client"; import React, { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Switch } from "@/components/ui/switch"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Separator } from "@/components/ui/separator"; import { Plus, Trash2, Database, Layers } from "lucide-react"; import { cn } from "@/lib/utils"; import { SaveConfig, SubTableSaveConfig, SubTableFieldMapping, FormSectionConfig, FormFieldConfig } from "../types"; // 도움말 텍스트 컴포넌트 const HelpText = ({ children }: { children: React.ReactNode }) => (

{children}

); interface SaveSettingsModalProps { open: boolean; onOpenChange: (open: boolean) => void; saveConfig: SaveConfig; sections: FormSectionConfig[]; onSave: (updates: SaveConfig) => void; tables: { name: string; label: string }[]; tableColumns: { [tableName: string]: { name: string; type: string; label: string }[] }; onLoadTableColumns: (tableName: string) => void; } export function SaveSettingsModal({ open, onOpenChange, saveConfig, sections, onSave, tables, tableColumns, onLoadTableColumns, }: SaveSettingsModalProps) { // 로컬 상태로 저장 설정 관리 const [localSaveConfig, setLocalSaveConfig] = useState(saveConfig); // 저장 모드 (단일 테이블 vs 다중 테이블) const [saveMode, setSaveMode] = useState<"single" | "multi">( saveConfig.customApiSave?.enabled && saveConfig.customApiSave?.multiTable?.enabled ? "multi" : "single" ); // open이 변경될 때마다 데이터 동기화 useEffect(() => { if (open) { setLocalSaveConfig(saveConfig); setSaveMode(saveConfig.customApiSave?.enabled && saveConfig.customApiSave?.multiTable?.enabled ? "multi" : "single"); } }, [open, saveConfig]); // 저장 설정 업데이트 함수 const updateSaveConfig = (updates: Partial) => { setLocalSaveConfig((prev) => ({ ...prev, ...updates })); }; // 저장 함수 const handleSave = () => { // 저장 모드에 따라 설정 조정 let finalConfig = { ...localSaveConfig }; if (saveMode === "single") { // 단일 테이블 모드: customApiSave 비활성화 finalConfig = { ...finalConfig, customApiSave: { enabled: false, apiType: "custom", }, }; } else { // 다중 테이블 모드: customApiSave 활성화 finalConfig = { ...finalConfig, customApiSave: { ...finalConfig.customApiSave, enabled: true, apiType: "multi-table", multiTable: { ...finalConfig.customApiSave?.multiTable, enabled: true, }, }, }; } onSave(finalConfig); onOpenChange(false); }; // 서브 테이블 추가 const addSubTable = () => { const newSubTable: SubTableSaveConfig = { enabled: true, tableName: "", repeatSectionId: "", linkColumn: { mainField: "", subColumn: "", }, fieldMappings: [], }; const subTables = [...(localSaveConfig.customApiSave?.multiTable?.subTables || []), newSubTable]; updateSaveConfig({ customApiSave: { ...localSaveConfig.customApiSave, apiType: "multi-table", multiTable: { ...localSaveConfig.customApiSave?.multiTable, enabled: true, subTables, }, }, }); }; // 서브 테이블 삭제 const removeSubTable = (index: number) => { const subTables = [...(localSaveConfig.customApiSave?.multiTable?.subTables || [])]; subTables.splice(index, 1); updateSaveConfig({ customApiSave: { ...localSaveConfig.customApiSave, multiTable: { ...localSaveConfig.customApiSave?.multiTable, subTables, }, }, }); }; // 서브 테이블 업데이트 const updateSubTable = (index: number, updates: Partial) => { const subTables = [...(localSaveConfig.customApiSave?.multiTable?.subTables || [])]; subTables[index] = { ...subTables[index], ...updates }; updateSaveConfig({ customApiSave: { ...localSaveConfig.customApiSave, multiTable: { ...localSaveConfig.customApiSave?.multiTable, subTables, }, }, }); }; // 필드 매핑 추가 const addFieldMapping = (subTableIndex: number) => { const newMapping: SubTableFieldMapping = { formField: "", targetColumn: "", }; const subTables = [...(localSaveConfig.customApiSave?.multiTable?.subTables || [])]; const fieldMappings = [...(subTables[subTableIndex].fieldMappings || []), newMapping]; subTables[subTableIndex] = { ...subTables[subTableIndex], fieldMappings }; updateSaveConfig({ customApiSave: { ...localSaveConfig.customApiSave, multiTable: { ...localSaveConfig.customApiSave?.multiTable, subTables, }, }, }); }; // 필드 매핑 삭제 const removeFieldMapping = (subTableIndex: number, mappingIndex: number) => { const subTables = [...(localSaveConfig.customApiSave?.multiTable?.subTables || [])]; const fieldMappings = [...(subTables[subTableIndex].fieldMappings || [])]; fieldMappings.splice(mappingIndex, 1); subTables[subTableIndex] = { ...subTables[subTableIndex], fieldMappings }; updateSaveConfig({ customApiSave: { ...localSaveConfig.customApiSave, multiTable: { ...localSaveConfig.customApiSave?.multiTable, subTables, }, }, }); }; // 필드 매핑 업데이트 const updateFieldMapping = (subTableIndex: number, mappingIndex: number, updates: Partial) => { const subTables = [...(localSaveConfig.customApiSave?.multiTable?.subTables || [])]; const fieldMappings = [...(subTables[subTableIndex].fieldMappings || [])]; fieldMappings[mappingIndex] = { ...fieldMappings[mappingIndex], ...updates }; subTables[subTableIndex] = { ...subTables[subTableIndex], fieldMappings }; updateSaveConfig({ customApiSave: { ...localSaveConfig.customApiSave, multiTable: { ...localSaveConfig.customApiSave?.multiTable, subTables, }, }, }); }; // 메인 테이블 컬럼 목록 const mainTableColumns = localSaveConfig.customApiSave?.multiTable?.mainTable?.tableName ? tableColumns[localSaveConfig.customApiSave.multiTable.mainTable.tableName] || [] : []; // 반복 섹션 목록 const repeatSections = sections.filter((s) => s.repeatable); // 모든 필드 목록 (반복 섹션 포함) const getAllFields = (): { columnName: string; label: string; sectionTitle: string }[] => { const fields: { columnName: string; label: string; sectionTitle: string }[] = []; sections.forEach((section) => { section.fields.forEach((field) => { fields.push({ columnName: field.columnName, label: field.label, sectionTitle: section.title, }); }); }); return fields; }; const allFields = getAllFields(); return ( 저장 설정 폼 데이터를 데이터베이스에 저장하는 방식을 설정합니다.
{/* 저장 모드 선택 */}
setSaveMode(value as "single" | "multi")}>
모든 필드를 하나의 테이블에 저장합니다 (기본 방식)
메인 테이블 + 서브 테이블에 트랜잭션으로 저장합니다
예: 주문(orders) + 주문상세(order_items), 사원(user_info) + 부서(user_dept)
{/* 단일 테이블 저장 설정 */} {saveMode === "single" && (

단일 테이블 설정

폼 데이터를 저장할 테이블을 선택하세요
updateSaveConfig({ primaryKeyColumn: e.target.value })} placeholder="id" className="h-7 text-xs mt-1" /> 수정 모드에서 사용할 기본키 컬럼명
예: id, user_id, order_id
)} {/* 다중 테이블 저장 설정 */} {saveMode === "multi" && (
{/* 메인 테이블 설정 */}

메인 테이블 설정

주요 데이터를 저장할 메인 테이블 (예: orders, user_info)
{mainTableColumns.length > 0 ? ( ) : ( updateSaveConfig({ customApiSave: { ...localSaveConfig.customApiSave, multiTable: { ...localSaveConfig.customApiSave?.multiTable, mainTable: { ...localSaveConfig.customApiSave?.multiTable?.mainTable, primaryKeyColumn: e.target.value, }, }, }, }) } placeholder="id" className="h-7 text-xs mt-1" /> )} 메인 테이블의 기본키 컬럼 (예: order_id, user_id)
{/* 서브 테이블 목록 */}

서브 테이블 설정

({(localSaveConfig.customApiSave?.multiTable?.subTables || []).length}개)
반복 섹션 데이터를 별도 테이블에 저장합니다.
예: 주문상세(order_items), 겸직부서(user_dept)
{(localSaveConfig.customApiSave?.multiTable?.subTables || []).length === 0 ? (

서브 테이블이 없습니다

위의 "서브 테이블 추가" 버튼을 클릭하세요

) : (
{(localSaveConfig.customApiSave?.multiTable?.subTables || []).map((subTable, subIndex) => { const subTableColumns = subTable.tableName ? tableColumns[subTable.tableName] || [] : []; return (
서브 테이블 {subIndex + 1}: {subTable.tableName || "(미설정)"} ({subTable.fieldMappings?.length || 0}개 매핑)
반복 데이터를 저장할 서브 테이블
이 서브 테이블에 저장할 반복 섹션을 선택하세요
메인 테이블과 서브 테이블을 연결하는 키 컬럼
{mainTableColumns.length > 0 ? ( ) : ( updateSubTable(subIndex, { linkColumn: { ...subTable.linkColumn, mainField: e.target.value }, }) } placeholder="order_id" className="h-6 text-[9px] mt-0.5" /> )}
{subTableColumns.length > 0 ? ( ) : ( updateSubTable(subIndex, { linkColumn: { ...subTable.linkColumn, subColumn: e.target.value }, }) } placeholder="order_id" className="h-6 text-[9px] mt-0.5" /> )}
폼 필드를 서브 테이블 컬럼에 매핑합니다 {(subTable.fieldMappings || []).length === 0 ? (

매핑이 없습니다

) : (
{(subTable.fieldMappings || []).map((mapping, mapIndex) => (
매핑 {mapIndex + 1}
{subTableColumns.length > 0 ? ( ) : ( updateFieldMapping(subIndex, mapIndex, { targetColumn: e.target.value, }) } placeholder="item_name" className="h-5 text-[8px] mt-0.5" /> )}
))}
)}
); })}
)}
)} {/* 저장 후 동작 */}

저장 후 동작

토스트 메시지 표시 updateSaveConfig({ afterSave: { ...localSaveConfig.afterSave, showToast: checked, }, }) } />
저장 성공 시 "저장되었습니다" 메시지를 표시합니다
모달 자동 닫기 updateSaveConfig({ afterSave: { ...localSaveConfig.afterSave, closeModal: checked, }, }) } />
저장 성공 시 모달을 자동으로 닫습니다
부모 화면 새로고침 updateSaveConfig({ afterSave: { ...localSaveConfig.afterSave, refreshParent: checked, }, }) } />
저장 후 부모 화면의 데이터를 새로고침합니다
); }