"use client" import * as React from "react" import { useForm } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import { toast } from "sonner" import { Plus, Loader2 } from "lucide-react" import { Button } from "@/components/ui/button" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog" import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form" import { Input } from "@/components/ui/input" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { createCodeGroup } from "@/lib/docu-list-rule/code-groups/service" import { getProjectLists } from "@/lib/projects/service" import { z } from "zod" const createCodeGroupSchema = z.object({ projectId: z.string().min(1, "프로젝트는 필수입니다."), description: z.string().min(1, "Description은 필수입니다."), codeFormat: z.string().optional().refine((val) => { if (!val) return true; // 빈 값은 허용 return /^[ANX]*$/.test(val); }, "Code Format은 A(영어 대문자), N(숫자), X(영어/숫자)만 입력 가능합니다."), controlType: z.string().min(1, "Control Type은 필수입니다."), }) type CreateCodeGroupFormValues = z.infer interface CodeGroupsAddDialogProps { onSuccess?: () => void } export function CodeGroupsAddDialog({ onSuccess }: CodeGroupsAddDialogProps) { const [open, setOpen] = React.useState(false) const [isLoading, setIsLoading] = React.useState(false) const [projects, setProjects] = React.useState>([]) const form = useForm({ resolver: zodResolver(createCodeGroupSchema), defaultValues: { projectId: "", description: "", codeFormat: "", controlType: "", }, }) // 프로젝트 목록 로드 React.useEffect(() => { if (open) { const loadProjects = async () => { try { const result = await getProjectLists({ page: 1, perPage: 1000, search: "", sort: [], filters: [], joinOperator: "and", flags: [] }) if (result.data) { setProjects(result.data) } } catch (error) { console.error("Failed to load projects:", error) toast.error("프로젝트 목록을 불러오는데 실패했습니다.") } } loadProjects() } }, [open]) // Code Format을 기반으로 정규식 자동 생성 함수 const generateExpression = (codeFormat: string): string => { if (!codeFormat) return '' let expression = '^' let currentChar = codeFormat[0] let count = 1 for (let i = 1; i < codeFormat.length; i++) { if (codeFormat[i] === currentChar) { count++ } else { // 이전 문자에 대한 정규식 추가 if (currentChar === 'A') { expression += `[A-Z]{${count}}` } else if (currentChar === 'N') { expression += `[0-9]{${count}}` } else if (currentChar === 'X') { expression += `[A-Z0-9]{${count}}` } currentChar = codeFormat[i] count = 1 } } // 마지막 문자 처리 if (currentChar === 'A') { expression += `[A-Z]{${count}}` } else if (currentChar === 'N') { expression += `[0-9]{${count}}` } else if (currentChar === 'X') { expression += `[A-Z0-9]{${count}}` } expression += '$' return expression } const handleOpenChange = (newOpen: boolean) => { setOpen(newOpen) if (!newOpen) { form.reset() } } const handleCancel = () => { form.reset() setOpen(false) } const onSubmit = async (data: CreateCodeGroupFormValues) => { setIsLoading(true) try { // Expression 자동 생성 const expressions = generateExpression(data.codeFormat || "") const result = await createCodeGroup({ projectId: parseInt(data.projectId), description: data.description, codeFormat: data.codeFormat, expressions: expressions, controlType: data.controlType, }) if (result.success) { toast.success("Code Group이 성공적으로 생성되었습니다.") form.reset() setOpen(false) onSuccess?.() } else { toast.error(result.error || "생성 중 오류가 발생했습니다.") } } catch (error) { console.error("Code Group 생성 오류:", error) toast.error("Code Group 생성에 실패했습니다.") } finally { setIsLoading(false) } } return ( Code Group 생성 새로운 Code Group을 생성합니다. * 표시된 항목은 필수 입력사항입니다.
( 프로젝트 * )} /> ( Description * )} /> ( Code Format form.trigger('codeFormat')} /> A: 영어 대문자, N: 숫자, X: 영어 대문자 또는 숫자 )} /> ( Control Type )} />
) }