summaryrefslogtreecommitdiff
path: root/lib/docu-list-rule/combo-box-settings/table/document-class-options-sheet.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/docu-list-rule/combo-box-settings/table/document-class-options-sheet.tsx')
-rw-r--r--lib/docu-list-rule/combo-box-settings/table/document-class-options-sheet.tsx436
1 files changed, 0 insertions, 436 deletions
diff --git a/lib/docu-list-rule/combo-box-settings/table/document-class-options-sheet.tsx b/lib/docu-list-rule/combo-box-settings/table/document-class-options-sheet.tsx
deleted file mode 100644
index 8585d9a3..00000000
--- a/lib/docu-list-rule/combo-box-settings/table/document-class-options-sheet.tsx
+++ /dev/null
@@ -1,436 +0,0 @@
-"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<DocumentClassOption[]>([])
- const [loading, setLoading] = useState(true)
- const [newOptionRows, setNewOptionRows] = useState<NewOptionRow[]>([])
- const [editingOption, setEditingOption] = useState<DocumentClassOption | null>(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 (
- <Sheet open={open} onOpenChange={onOpenChange}>
- <SheetContent className="w-[600px] sm:max-w-[600px] overflow-y-auto">
- <SheetHeader>
- <SheetTitle>하위 옵션 관리</SheetTitle>
- <SheetDescription>
- {comboBoxOption.description} ({comboBoxOption.code})의 하위 옵션을 관리합니다.
- </SheetDescription>
- </SheetHeader>
-
- <div className="space-y-4 mt-6">
- {/* 새 하위 옵션 추가 */}
- <div className="space-y-2">
- <div className="flex items-center justify-between">
- <h4 className="text-sm font-medium">새 하위 옵션 추가</h4>
- <Button
- type="button"
- variant="outline"
- size="sm"
- onClick={addNewRow}
- className="h-8"
- >
- <Plus className="h-4 w-4 mr-1" />
- 옵션 추가
- </Button>
- </div>
-
- {newOptionRows.length > 0 && (
- <div className="border rounded-lg overflow-hidden">
- <Table>
- <TableHeader>
- <TableRow className="bg-muted/30">
- <TableHead className="w-[40%]">옵션 값 *</TableHead>
- <TableHead className="w-[30%]">옵션 코드</TableHead>
- <TableHead className="w-[20%]">순서</TableHead>
- <TableHead className="w-[10%]"></TableHead>
- </TableRow>
- </TableHeader>
- <TableBody>
- {newOptionRows.map((row) => (
- <TableRow key={row.id} className="hover:bg-muted/30">
- <TableCell>
- <Input
- value={row.optionValue}
- onChange={(e) => updateNewRow(row.id, "optionValue", e.target.value)}
- placeholder="옵션 값"
- className="border-0 focus-visible:ring-1 bg-transparent h-8"
- />
- </TableCell>
- <TableCell>
- <Input
- value={row.optionCode}
- onChange={(e) => updateNewRow(row.id, "optionCode", e.target.value)}
- placeholder="옵션 코드 (선택)"
- className="border-0 focus-visible:ring-1 bg-transparent h-8"
- />
- </TableCell>
- <TableCell>
- <Input
- type="number"
- value={row.sortOrder}
- onChange={(e) => updateNewRow(row.id, "sortOrder", parseInt(e.target.value) || 0)}
- className="border-0 focus-visible:ring-1 bg-transparent h-8"
- />
- </TableCell>
- <TableCell>
- <Button
- onClick={() => removeNewRow(row.id)}
- size="sm"
- variant="ghost"
- className="h-6 w-6 p-0"
- >
- <X className="h-3 w-3" />
- </Button>
- </TableCell>
- </TableRow>
- ))}
- </TableBody>
- </Table>
- <div className="p-3 border-t">
- <Button
- onClick={handleSaveNewOptions}
- size="sm"
- className="h-8"
- >
- <Save className="h-4 w-4 mr-1" />
- 저장
- </Button>
- </div>
- </div>
- )}
- </div>
-
- {/* 기존 하위 옵션 목록 */}
- <div className="space-y-2">
- <h4 className="text-sm font-medium">기존 하위 옵션</h4>
- <div className="border rounded-lg overflow-hidden">
- <Table>
- <TableHeader>
- <TableRow className="bg-muted/30">
- <TableHead className="w-[35%]">옵션 값</TableHead>
- <TableHead className="w-[25%]">옵션 코드</TableHead>
- <TableHead className="w-[15%]">순서</TableHead>
- <TableHead className="w-[15%]">상태</TableHead>
- <TableHead className="w-[10%]">작업</TableHead>
- </TableRow>
- </TableHeader>
- <TableBody>
- {loading ? (
- <TableRow>
- <TableCell colSpan={5} className="text-center py-8">
- 로딩 중...
- </TableCell>
- </TableRow>
- ) : options.length === 0 ? (
- <TableRow>
- <TableCell colSpan={5} className="text-center text-muted-foreground py-8">
- 등록된 하위 옵션이 없습니다.
- </TableCell>
- </TableRow>
- ) : (
- options.map((option) => (
- <TableRow key={option.id} className="hover:bg-muted/30">
- <TableCell className="text-sm">
- {editingOption?.id === option.id ? (
- <Input
- value={editingOption.optionValue}
- onChange={(e) => setEditingOption(prev => prev ? { ...prev, optionValue: e.target.value } : null)}
- placeholder="옵션 값"
- className="border-0 focus-visible:ring-1 bg-transparent h-8"
- />
- ) : (
- option.optionValue
- )}
- </TableCell>
- <TableCell className="text-sm">
- {editingOption?.id === option.id ? (
- <Input
- value={editingOption.optionCode || ""}
- onChange={(e) => setEditingOption(prev => prev ? { ...prev, optionCode: e.target.value } : null)}
- placeholder="옵션 코드"
- className="border-0 focus-visible:ring-1 bg-transparent h-8"
- />
- ) : (
- option.optionCode || "-"
- )}
- </TableCell>
- <TableCell className="text-sm">
- {editingOption?.id === option.id ? (
- <Input
- type="number"
- value={editingOption.sortOrder}
- onChange={(e) => setEditingOption(prev => prev ? { ...prev, sortOrder: parseInt(e.target.value) || 0 } : null)}
- className="border-0 focus-visible:ring-1 bg-transparent h-8"
- />
- ) : (
- option.sortOrder
- )}
- </TableCell>
- <TableCell className="text-sm">
- <span className={`px-2 py-1 rounded text-xs ${
- option.isActive
- ? "bg-green-100 text-green-800"
- : "bg-red-100 text-red-800"
- }`}>
- {option.isActive ? "활성" : "비활성"}
- </span>
- </TableCell>
- <TableCell className="text-sm">
- {editingOption?.id === option.id ? (
- <div className="flex gap-1">
- <Button
- onClick={() => handleUpdateOption(editingOption)}
- size="sm"
- variant="outline"
- className="h-6 px-2 text-xs"
- >
- 저장
- </Button>
- <Button
- onClick={() => setEditingOption(null)}
- size="sm"
- variant="ghost"
- className="h-6 px-2 text-xs"
- >
- 취소
- </Button>
- </div>
- ) : (
- <div className="flex gap-1">
- <Button
- onClick={() => setEditingOption(option)}
- size="sm"
- variant="outline"
- className="h-6 px-2 text-xs"
- >
- 수정
- </Button>
- <Button
- onClick={() => handleDeleteOption(option.id)}
- size="sm"
- variant="ghost"
- className="h-6 px-2 text-xs text-red-600 hover:text-red-700"
- >
- <Trash2 className="h-3 w-3" />
- </Button>
- </div>
- )}
- </TableCell>
- </TableRow>
- ))
- )}
- </TableBody>
- </Table>
- </div>
- </div>
- </div>
- </SheetContent>
- </Sheet>
- )
-} \ No newline at end of file