summaryrefslogtreecommitdiff
path: root/lib/docu-list-rule/combo-box-settings/table/combo-box-options-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/docu-list-rule/combo-box-settings/table/combo-box-options-dialog.tsx')
-rw-r--r--lib/docu-list-rule/combo-box-settings/table/combo-box-options-dialog.tsx234
1 files changed, 234 insertions, 0 deletions
diff --git a/lib/docu-list-rule/combo-box-settings/table/combo-box-options-dialog.tsx b/lib/docu-list-rule/combo-box-settings/table/combo-box-options-dialog.tsx
new file mode 100644
index 00000000..6459ae14
--- /dev/null
+++ b/lib/docu-list-rule/combo-box-settings/table/combo-box-options-dialog.tsx
@@ -0,0 +1,234 @@
+"use client"
+
+import * as React from "react"
+import { useState } from "react"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Plus, Trash2 } from "lucide-react"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table"
+import { toast } from "sonner"
+import { codeGroups } from "@/db/schema/codeGroups"
+import { createComboBoxOption } from "../service"
+
+interface ComboBoxOptionsDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ codeGroup: typeof codeGroups.$inferSelect | null
+ onSuccess: () => void
+}
+
+interface OptionRow {
+ id: string
+ description: string
+ remark: string
+}
+
+export function ComboBoxOptionsDialog({
+ open,
+ onOpenChange,
+ codeGroup,
+ onSuccess
+}: ComboBoxOptionsDialogProps) {
+ const [optionRows, setOptionRows] = useState<OptionRow[]>([])
+ const [loading, setLoading] = useState(false)
+
+ // 다이얼로그가 열릴 때 초기 행 생성
+ React.useEffect(() => {
+ if (open && optionRows.length === 0) {
+ addRow()
+ }
+ }, [open])
+
+ // 새 행 추가
+ const addRow = () => {
+ const newRow: OptionRow = {
+ id: `row-${Date.now()}-${Math.random()}`,
+ description: "",
+ remark: "",
+ }
+ setOptionRows(prev => [...prev, newRow])
+ }
+
+ // 행 삭제
+ const removeRow = (id: string) => {
+ setOptionRows(prev => prev.filter(row => row.id !== id))
+ }
+
+ // 행 업데이트
+ const updateRow = (id: string, field: keyof OptionRow, value: string) => {
+ setOptionRows(prev =>
+ prev.map(row =>
+ row.id === id ? { ...row, [field]: value } : row
+ )
+ )
+ }
+
+ // 일괄 저장
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault()
+
+ if (!codeGroup) return
+
+ // 유효한 행들만 필터링 (Description이 있는 것만)
+ const validRows = optionRows.filter(row => row.description.trim())
+
+ if (validRows.length === 0) {
+ toast.error("최소 하나의 Description을 입력해주세요.")
+ return
+ }
+
+ setLoading(true)
+ try {
+ let successCount = 0
+ let errorCount = 0
+
+ // 각 행을 순차적으로 저장
+ for (const row of validRows) {
+ try {
+ const result = await createComboBoxOption({
+ codeGroupId: codeGroup.id,
+ code: "", // 서비스에서 자동 생성
+ description: row.description.trim(),
+ remark: row.remark.trim() || undefined,
+ })
+
+ if (result.success) {
+ successCount++
+ } else {
+ errorCount++
+ }
+ } catch (error) {
+ console.error("옵션 추가 실패:", error)
+ errorCount++
+ }
+ }
+
+ if (successCount > 0) {
+ toast.success(`${successCount}개의 옵션이 추가되었습니다.${errorCount > 0 ? ` (${errorCount}개 실패)` : ''}`)
+ // 폼 초기화
+ setOptionRows([])
+ onSuccess()
+ } else {
+ toast.error("모든 옵션 추가에 실패했습니다.")
+ }
+ } catch (error) {
+ console.error("옵션 추가 실패:", error)
+ toast.error("옵션 추가에 실패했습니다.")
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ const handleCancel = () => {
+ // 폼 초기화
+ setOptionRows([])
+ onOpenChange(false)
+ }
+
+ return (
+ <Dialog open={open} onOpenChange={onOpenChange}>
+ <DialogContent className="sm:max-w-[600px] max-h-[80vh] overflow-y-auto">
+ <DialogHeader>
+ <DialogTitle>Combo Box 옵션 추가</DialogTitle>
+ <DialogDescription>
+ {codeGroup?.description}에 새로운 옵션들을 추가합니다. Code는 자동으로 생성됩니다.
+ </DialogDescription>
+ </DialogHeader>
+
+ <div className="space-y-4">
+ {/* 테이블 헤더와 추가 버튼 */}
+ <div className="flex items-center justify-between">
+ <h4 className="text-sm font-medium">옵션 목록</h4>
+ <Button
+ type="button"
+ variant="outline"
+ size="sm"
+ onClick={addRow}
+ className="h-8"
+ >
+ <Plus className="h-4 w-4 mr-1" />
+ 행 추가
+ </Button>
+ </div>
+
+ {/* 옵션 테이블 - 항상 표시 */}
+ <div className="border rounded-lg overflow-hidden">
+ <Table>
+ <TableHeader>
+ <TableRow className="bg-muted/30">
+ <TableHead className="w-[50%]">Description *</TableHead>
+ <TableHead className="w-[40%]">Remark</TableHead>
+ <TableHead className="w-[10%]"></TableHead>
+ </TableRow>
+ </TableHeader>
+ <TableBody>
+ {optionRows.map((row) => (
+ <TableRow key={row.id} className="hover:bg-muted/30">
+ <TableCell>
+ <Input
+ value={row.description}
+ onChange={(e) => updateRow(row.id, "description", e.target.value)}
+ className="border-0 focus-visible:ring-1 bg-transparent h-8"
+ />
+ </TableCell>
+ <TableCell>
+ <Input
+ value={row.remark}
+ onChange={(e) => updateRow(row.id, "remark", e.target.value)}
+ className="border-0 focus-visible:ring-1 bg-transparent h-8"
+ />
+ </TableCell>
+ <TableCell>
+ <Button
+ type="button"
+ variant="ghost"
+ size="sm"
+ onClick={() => removeRow(row.id)}
+ className="h-6 w-6 p-0"
+ >
+ <Trash2 className="h-3 w-3" />
+ </Button>
+ </TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
+ </div>
+ </div>
+
+ <DialogFooter>
+ <Button
+ type="button"
+ variant="outline"
+ onClick={handleCancel}
+ disabled={loading}
+ >
+ 취소
+ </Button>
+ <Button
+ type="submit"
+ onClick={handleSubmit}
+ disabled={loading}
+ >
+ {loading ? "저장 중..." : "저장"}
+ </Button>
+ </DialogFooter>
+ </DialogContent>
+ </Dialog>
+ )
+} \ No newline at end of file