summaryrefslogtreecommitdiff
path: root/lib/compliance/table
diff options
context:
space:
mode:
author0-Zz-ang <s1998319@gmail.com>2025-11-19 09:50:12 +0900
committer0-Zz-ang <s1998319@gmail.com>2025-11-19 09:50:12 +0900
commit2f1bef8eeff5d6cd30c4de808402893deb35335d (patch)
treeb3a286bca25df3a038ace20969855b8485878b7b /lib/compliance/table
parent84277bd79bd6a2bff0f6ef6840f1790db06036e6 (diff)
준법설문조사 리비전관리
Diffstat (limited to 'lib/compliance/table')
-rw-r--r--lib/compliance/table/compliance-survey-templates-toolbar.tsx7
-rw-r--r--lib/compliance/table/compliance-template-create-dialog.tsx103
-rw-r--r--lib/compliance/table/compliance-template-edit-sheet.tsx16
3 files changed, 90 insertions, 36 deletions
diff --git a/lib/compliance/table/compliance-survey-templates-toolbar.tsx b/lib/compliance/table/compliance-survey-templates-toolbar.tsx
index 6776b70a..3e5f7f4d 100644
--- a/lib/compliance/table/compliance-survey-templates-toolbar.tsx
+++ b/lib/compliance/table/compliance-survey-templates-toolbar.tsx
@@ -16,6 +16,11 @@ interface ComplianceSurveyTemplatesToolbarActionsProps {
}
export function ComplianceSurveyTemplatesToolbarActions({ table }: ComplianceSurveyTemplatesToolbarActionsProps) {
+ const templates = React.useMemo(
+ () => table.getPreFilteredRowModel().rows.map((row) => row.original),
+ [table],
+ );
+
return (
<div className="flex items-center gap-2">
{/** 1) 선택된 로우가 있으면 삭제 다이얼로그 */}
@@ -27,7 +32,7 @@ export function ComplianceSurveyTemplatesToolbarActions({ table }: ComplianceSur
/>
) : null}
- <ComplianceTemplateCreateDialog />
+ <ComplianceTemplateCreateDialog templates={templates} />
{/** 2) 레드플래그 담당자 관리 */}
<RedFlagManagersDialog />
diff --git a/lib/compliance/table/compliance-template-create-dialog.tsx b/lib/compliance/table/compliance-template-create-dialog.tsx
index 5b7e1092..db4ede4e 100644
--- a/lib/compliance/table/compliance-template-create-dialog.tsx
+++ b/lib/compliance/table/compliance-template-create-dialog.tsx
@@ -29,19 +29,33 @@ import { Switch } from "@/components/ui/switch"
import { Plus, Loader2 } from "lucide-react"
import { toast } from "sonner"
import { createComplianceSurveyTemplate } from "../services"
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select"
+import { complianceSurveyTemplates } from "@/db/schema/compliance"
const createTemplateSchema = z.object({
name: z.string().min(1, "템플릿명을 입력해주세요.").max(100, "템플릿명은 100자 이하여야 합니다."),
description: z.string().min(1, "설명을 입력해주세요.").max(500, "설명은 500자 이하여야 합니다."),
- version: z.string().min(1, "버전을 입력해주세요.").max(20, "버전은 20자 이하여야 합니다."),
isActive: z.boolean().default(true),
})
type CreateTemplateFormValues = z.infer<typeof createTemplateSchema>
-export function ComplianceTemplateCreateDialog() {
+interface ComplianceTemplateCreateDialogProps {
+ templates?: typeof complianceSurveyTemplates.$inferSelect[]
+}
+
+export function ComplianceTemplateCreateDialog({
+ templates = [],
+}: ComplianceTemplateCreateDialogProps) {
const [open, setOpen] = React.useState(false)
const [isSubmitting, setIsSubmitting] = React.useState(false)
+ const [selectedTemplateId, setSelectedTemplateId] = React.useState<string>("none")
// react-hook-form 세팅
const form = useForm<CreateTemplateFormValues>({
@@ -49,19 +63,54 @@ export function ComplianceTemplateCreateDialog() {
defaultValues: {
name: "",
description: "",
- version: "1.0",
isActive: true,
},
mode: "onChange",
})
+ const selectedTemplate = React.useMemo(() => {
+ if (selectedTemplateId === "none") {
+ return undefined
+ }
+ return templates.find((template) => String(template.id) === selectedTemplateId)
+ }, [selectedTemplateId, templates])
+
+ const nextVersionLabel = React.useMemo(() => {
+ if (!selectedTemplate) {
+ return null
+ }
+ const baseVersion = selectedTemplate.version || "1.0"
+ const numericValue = Number(baseVersion)
+ if (!Number.isNaN(numericValue)) {
+ const hasDecimal = baseVersion.includes(".")
+ const decimalDigits = hasDecimal ? baseVersion.split(".")[1]?.length ?? 0 : 0
+ const incremented = numericValue + 1
+ return hasDecimal ? incremented.toFixed(decimalDigits) : String(incremented)
+ }
+ return "1.0"
+ }, [selectedTemplate])
+
+ React.useEffect(() => {
+ if (selectedTemplate) {
+ form.setValue("name", selectedTemplate.name ?? "")
+ form.setValue("description", selectedTemplate.description ?? "")
+ }
+ }, [selectedTemplate, form])
+
async function onSubmit(data: CreateTemplateFormValues) {
setIsSubmitting(true)
try {
- const result = await createComplianceSurveyTemplate(data)
+ const baseTemplateNumericId =
+ selectedTemplateId !== "none" ? Number(selectedTemplateId) : undefined
+
+ const result = await createComplianceSurveyTemplate({
+ ...data,
+ baseTemplateId: baseTemplateNumericId,
+ })
if (result) {
toast.success("새로운 설문조사 템플릿이 생성되었습니다.")
form.reset()
+ setSelectedTemplateId("none")
setOpen(false)
// 페이지 새로고침으로 데이터 업데이트
window.location.reload()
@@ -77,6 +126,7 @@ export function ComplianceTemplateCreateDialog() {
function handleDialogOpenChange(nextOpen: boolean) {
if (!nextOpen) {
form.reset()
+ setSelectedTemplateId("none")
}
setOpen(nextOpen)
}
@@ -133,22 +183,37 @@ export function ComplianceTemplateCreateDialog() {
)}
/>
- <FormField
- control={form.control}
- name="version"
- render={({ field }) => (
- <FormItem>
- <FormLabel>버전 *</FormLabel>
- <FormControl>
- <Input
- placeholder="예: 1.0"
- {...field}
- />
- </FormControl>
- <FormMessage />
- </FormItem>
+ <div className="space-y-2">
+ <FormLabel>기존 템플릿 불러오기 (선택)</FormLabel>
+ <Select
+ value={selectedTemplateId}
+ onValueChange={(value) => setSelectedTemplateId(value)}
+ >
+ <FormControl>
+ <SelectTrigger>
+ <SelectValue placeholder="불러올 템플릿을 선택하세요" />
+ </SelectTrigger>
+ </FormControl>
+ <SelectContent>
+ <SelectItem value="none">선택하지 않음</SelectItem>
+ {templates.map((template) => (
+ <SelectItem key={template.id} value={String(template.id)}>
+ {template.name} (v{template.version})
+ </SelectItem>
+ ))}
+ </SelectContent>
+ </Select>
+ {selectedTemplate ? (
+ <p className="text-sm text-muted-foreground">
+ 선택한 템플릿을 기반으로 새 버전(v{nextVersionLabel})이 생성되며,
+ 기존 템플릿은 자동으로 비활성화됩니다.
+ </p>
+ ) : (
+ <p className="text-sm text-muted-foreground">
+ 템플릿을 선택하지 않으면 새 템플릿이 기본 버전(v1.0)으로 생성됩니다.
+ </p>
)}
- />
+ </div>
<FormField
control={form.control}
diff --git a/lib/compliance/table/compliance-template-edit-sheet.tsx b/lib/compliance/table/compliance-template-edit-sheet.tsx
index 3ac4870a..96ffa8f5 100644
--- a/lib/compliance/table/compliance-template-edit-sheet.tsx
+++ b/lib/compliance/table/compliance-template-edit-sheet.tsx
@@ -33,7 +33,6 @@ import { useRouter } from "next/navigation";
const templateSchema = z.object({
name: z.string().min(1, "템플릿명을 입력하세요"),
description: z.string().min(1, "설명을 입력하세요"),
- version: z.string().min(1, "버전을 입력하세요"),
isActive: z.boolean(),
});
@@ -58,7 +57,6 @@ export function ComplianceTemplateEditSheet({
defaultValues: {
name: template.name,
description: template.description,
- version: template.version,
isActive: template.isActive,
},
});
@@ -128,20 +126,6 @@ export function ComplianceTemplateEditSheet({
<FormField
control={form.control}
- name="version"
- render={({ field }) => (
- <FormItem>
- <FormLabel>버전</FormLabel>
- <FormControl>
- <Input placeholder="버전을 입력하세요" {...field} />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
-
- <FormField
- control={form.control}
name="isActive"
render={({ field }) => (
<FormItem className="flex flex-row items-start space-x-3 space-y-0">