From 50ae0b8f02c034e60d4cbb504620dfa1575a836f Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 28 Jul 2025 09:19:42 +0000 Subject: (박서영) 설계 document Numbering Rule 개발-최겸 업로드 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../table/combo-box-options-expandable-row.tsx | 263 +++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 lib/docu-list-rule/combo-box-settings/table/combo-box-options-expandable-row.tsx (limited to 'lib/docu-list-rule/combo-box-settings/table/combo-box-options-expandable-row.tsx') diff --git a/lib/docu-list-rule/combo-box-settings/table/combo-box-options-expandable-row.tsx b/lib/docu-list-rule/combo-box-settings/table/combo-box-options-expandable-row.tsx new file mode 100644 index 00000000..07b63de5 --- /dev/null +++ b/lib/docu-list-rule/combo-box-settings/table/combo-box-options-expandable-row.tsx @@ -0,0 +1,263 @@ +"use client" + +import * as React from "react" +import { useState, useEffect } from "react" +import { MoreHorizontal, Settings } from "lucide-react" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" +import { toast } from "sonner" +import { codeGroups } from "@/db/schema/codeGroups" +import { getComboBoxOptions, updateComboBoxOption, deleteComboBoxOption } from "../service" +import { DocumentClassOptionsSheet } from "./document-class-options-sheet" + + +interface ComboBoxOptionsExpandableRowProps { + codeGroup: typeof codeGroups.$inferSelect +} + +interface ComboBoxOption { + id: number + codeGroupId: number + code: string + description: string + remark: string | null + createdAt: Date + updatedAt: Date +} + +export function ComboBoxOptionsExpandableRow({ codeGroup }: ComboBoxOptionsExpandableRowProps) { + const [options, setOptions] = useState([]) + const [loading, setLoading] = useState(true) + const [editingOption, setEditingOption] = useState(null) + const [selectedOptionForSubOptions, setSelectedOptionForSubOptions] = useState(null) + + // 옵션 목록 로드 + const loadOptions = async () => { + try { + setLoading(true) + const result = await getComboBoxOptions(codeGroup.id) + if (result.success && result.data) { + setOptions(result.data as ComboBoxOption[]) + } else { + toast.error("옵션 목록을 불러오는데 실패했습니다.") + } + } catch (error) { + console.error("옵션 로드 실패:", error) + toast.error("옵션 목록을 불러오는데 실패했습니다.") + } finally { + setLoading(false) + } + } + + useEffect(() => { + loadOptions() + }, [codeGroup.id]) + + // 기존 옵션 수정 + const handleUpdateOption = async (option: ComboBoxOption) => { + if (!option.code.trim() || !option.description.trim()) { + toast.error("Code와 Description은 필수 입력 항목입니다.") + return + } + + try { + const result = await updateComboBoxOption({ + id: option.id, + code: option.code.trim(), + description: option.description.trim(), + remark: option.remark || undefined, + }) + + 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 deleteComboBoxOption(optionId) + if (result.success) { + await loadOptions() // 목록 새로고침 + toast.success("옵션이 삭제되었습니다.") + } else { + toast.error("옵션 삭제에 실패했습니다.") + } + } catch (error) { + console.error("옵션 삭제 실패:", error) + toast.error("옵션 삭제에 실패했습니다.") + } + } + + // Document Class인지 확인 (Description이 "Document Class"인 경우) + const isDocumentClass = codeGroup.description === "Document Class" + + return ( +
+
+ {/* 커스텀 테이블 */} +
+ + + + Code + Description + Remark + {isDocumentClass && ( + 하위 옵션 + )} + 작업 + + + + {/* 기존 옵션들 */} + {options.map((option) => ( + + + {editingOption?.id === option.id ? ( + setEditingOption(prev => prev ? { ...prev, code: e.target.value } : null)} + placeholder="Code (*)" + className="border-0 focus-visible:ring-1 bg-transparent h-8" + /> + ) : ( + option.code + )} + + + {editingOption?.id === option.id ? ( + setEditingOption(prev => prev ? { ...prev, description: e.target.value } : null)} + placeholder="Description (*)" + className="border-0 focus-visible:ring-1 bg-transparent h-8" + /> + ) : ( + option.description + )} + + + {editingOption?.id === option.id ? ( + setEditingOption(prev => prev ? { ...prev, remark: e.target.value } : null)} + placeholder="Remark" + className="border-0 focus-visible:ring-1 bg-transparent h-8" + /> + ) : ( + option.remark || "-" + )} + + {isDocumentClass && ( + + + + )} + + {editingOption?.id === option.id ? ( +
+ + +
+ ) : ( + + + + + + setEditingOption(option)}> + 수정 + + + handleDeleteOption(option.id)}> + 삭제 + + + + )} +
+
+ ))} + + {options.length === 0 && ( + + + 등록된 옵션이 없습니다. + + + )} +
+
+
+
+ + {/* Document Class 하위 옵션 관리 시트 */} + {selectedOptionForSubOptions && ( + !open && setSelectedOptionForSubOptions(null)} + comboBoxOption={selectedOptionForSubOptions} + onSuccess={() => { + setSelectedOptionForSubOptions(null) + // 필요시 하위 옵션 목록 새로고침 + }} + /> + )} +
+ ) +} \ No newline at end of file -- cgit v1.2.3