"use client" import * as React from "react" import { useState, useEffect } from "react" import { Plus, Trash2, Save, X } from "lucide-react" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, } from "@/components/ui/sheet" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" import { toast } from "sonner" import { getDocumentClassOptions, createDocumentClassOption, updateDocumentClassOption, deleteDocumentClassOption } from "../service" interface DocumentClassOptionsSheetProps { open: boolean onOpenChange: (open: boolean) => void comboBoxOption: { id: number code: string description: string } onSuccess: () => void } interface DocumentClassOption { id: number comboBoxSettingId: number optionValue: string optionCode: string | null sortOrder: number isActive: boolean createdAt: Date updatedAt: Date } interface NewOptionRow { id: string optionValue: string optionCode: string sortOrder: number } export function DocumentClassOptionsSheet({ open, onOpenChange, comboBoxOption, onSuccess }: DocumentClassOptionsSheetProps) { const [options, setOptions] = useState([]) const [loading, setLoading] = useState(true) const [newOptionRows, setNewOptionRows] = useState([]) const [editingOption, setEditingOption] = useState(null) // 하위 옵션 목록 로드 const loadOptions = async () => { try { setLoading(true) const result = await getDocumentClassOptions(comboBoxOption.id) if (result.success && result.data) { setOptions(result.data) } else { toast.error("하위 옵션 목록을 불러오는데 실패했습니다.") } } catch (error) { console.error("하위 옵션 로드 실패:", error) toast.error("하위 옵션 목록을 불러오는데 실패했습니다.") } finally { setLoading(false) } } useEffect(() => { if (open) { loadOptions() } }, [open, comboBoxOption.id]) // 새 행 추가 const addNewRow = () => { const newRow: NewOptionRow = { id: `new-${Date.now()}-${Math.random()}`, optionValue: "", optionCode: "", sortOrder: options.length + newOptionRows.length + 1, } setNewOptionRows(prev => [...prev, newRow]) } // 새 행 삭제 const removeNewRow = (id: string) => { setNewOptionRows(prev => prev.filter(row => row.id !== id)) } // 새 행 업데이트 const updateNewRow = (id: string, field: keyof NewOptionRow, value: string | number) => { setNewOptionRows(prev => prev.map(row => row.id === id ? { ...row, [field]: value } : row ) ) } // 새 하위 옵션 저장 const handleSaveNewOptions = async () => { const validRows = newOptionRows.filter(row => row.optionValue.trim()) if (validRows.length === 0) { toast.error("최소 하나의 옵션 값을 입력해주세요.") return } try { let successCount = 0 let errorCount = 0 for (const row of validRows) { try { const result = await createDocumentClassOption({ comboBoxSettingId: comboBoxOption.id, optionValue: row.optionValue.trim(), optionCode: row.optionCode.trim() || undefined, sortOrder: row.sortOrder, }) if (result.success) { successCount++ } else { errorCount++ } } catch (error) { console.error("하위 옵션 추가 실패:", error) errorCount++ } } if (successCount > 0) { toast.success(`${successCount}개의 하위 옵션이 추가되었습니다.${errorCount > 0 ? ` (${errorCount}개 실패)` : ''}`) setNewOptionRows([]) await loadOptions() onSuccess() } else { toast.error("모든 하위 옵션 추가에 실패했습니다.") } } catch (error) { console.error("하위 옵션 추가 실패:", error) toast.error("하위 옵션 추가에 실패했습니다.") } } // 기존 하위 옵션 수정 const handleUpdateOption = async (option: DocumentClassOption) => { if (!option.optionValue.trim()) { toast.error("옵션 값은 필수 입력 항목입니다.") return } try { const result = await updateDocumentClassOption({ id: option.id, optionValue: option.optionValue.trim(), optionCode: option.optionCode || undefined, sortOrder: option.sortOrder, isActive: option.isActive, }) if (result.success) { await loadOptions() setEditingOption(null) toast.success("하위 옵션이 수정되었습니다.") } else { toast.error("하위 옵션 수정에 실패했습니다.") } } catch (error) { console.error("하위 옵션 수정 실패:", error) toast.error("하위 옵션 수정에 실패했습니다.") } } // 하위 옵션 삭제 const handleDeleteOption = async (optionId: number) => { if (!confirm("정말로 이 하위 옵션을 삭제하시겠습니까?")) { return } try { const result = await deleteDocumentClassOption(optionId) if (result.success) { await loadOptions() toast.success("하위 옵션이 삭제되었습니다.") } else { toast.error("하위 옵션 삭제에 실패했습니다.") } } catch (error) { console.error("하위 옵션 삭제 실패:", error) toast.error("하위 옵션 삭제에 실패했습니다.") } } return ( 하위 옵션 관리 {comboBoxOption.description} ({comboBoxOption.code})의 하위 옵션을 관리합니다.
{/* 새 하위 옵션 추가 */}

새 하위 옵션 추가

{newOptionRows.length > 0 && (
옵션 값 * 옵션 코드 순서 {newOptionRows.map((row) => ( updateNewRow(row.id, "optionValue", e.target.value)} placeholder="옵션 값" className="border-0 focus-visible:ring-1 bg-transparent h-8" /> updateNewRow(row.id, "optionCode", e.target.value)} placeholder="옵션 코드 (선택)" className="border-0 focus-visible:ring-1 bg-transparent h-8" /> updateNewRow(row.id, "sortOrder", parseInt(e.target.value) || 0)} className="border-0 focus-visible:ring-1 bg-transparent h-8" /> ))}
)}
{/* 기존 하위 옵션 목록 */}

기존 하위 옵션

옵션 값 옵션 코드 순서 상태 작업 {loading ? ( 로딩 중... ) : options.length === 0 ? ( 등록된 하위 옵션이 없습니다. ) : ( options.map((option) => ( {editingOption?.id === option.id ? ( setEditingOption(prev => prev ? { ...prev, optionValue: e.target.value } : null)} placeholder="옵션 값" className="border-0 focus-visible:ring-1 bg-transparent h-8" /> ) : ( option.optionValue )} {editingOption?.id === option.id ? ( setEditingOption(prev => prev ? { ...prev, optionCode: e.target.value } : null)} placeholder="옵션 코드" className="border-0 focus-visible:ring-1 bg-transparent h-8" /> ) : ( option.optionCode || "-" )} {editingOption?.id === option.id ? ( setEditingOption(prev => prev ? { ...prev, sortOrder: parseInt(e.target.value) || 0 } : null)} className="border-0 focus-visible:ring-1 bg-transparent h-8" /> ) : ( option.sortOrder )} {option.isActive ? "활성" : "비활성"} {editingOption?.id === option.id ? (
) : (
)}
)) )}
) }