"use client" import * as React from "react" import { useForm } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import { z } from "zod" import { Plus } from "lucide-react" import { useRouter } from "next/navigation" import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Textarea } from "@/components/ui/textarea" import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { useToast } from "@/hooks/use-toast" import { createPqCriteria } from "../service" import { uploadPqCriteriaFileAction } from "@/lib/pq/service" import { Dropzone, DropzoneInput, DropzoneZone, DropzoneUploadIcon, DropzoneTitle, DropzoneDescription } from "@/components/ui/dropzone" import { FileList, FileListHeader, FileListInfo, FileListItem, FileListName, FileListDescription, FileListAction } from "@/components/ui/file-list" import { X, Loader2 } from "lucide-react" // PQ 생성을 위한 Zod 스키마 정의 const createPqSchema = z.object({ code: z.string().min(1, "Code is required"), checkPoint: z.string().min(1, "Check point is required"), groupName: z.string().min(1, "Group is required"), subGroupName: z.string().optional(), description: z.string().optional(), remarks: z.string().optional(), inputFormat: z.string().default("TEXT"), type: z.string().optional(), }); type CreatePqFormType = z.infer; // 그룹 이름 옵션 export const groupOptions = [ "GENERAL", "QMS", "Warranty", "HSE+", "기타", ]; // 입력 형식 옵션 const inputFormatOptions = [ { value: "TEXT", label: "텍스트" }, { value: "FILE", label: "파일" }, { value: "EMAIL", label: "이메일" }, { value: "PHONE", label: "전화번호" }, { value: "FAX", label: "팩스번호" }, { value: "NUMBER", label: "숫자" }, { value: "NUMBER_WITH_UNIT", label: "숫자+단위" }, { value: "TEXT_FILE", label: "텍스트 + 파일" }, ]; const typeOptions = [ { value: "내자", label: "내자" }, { value: "외자", label: "외자" }, { value: "내외자", label: "내외자" }, ]; interface AddPqDialogProps { pqListId: number; } export function AddPqDialog({ pqListId }: AddPqDialogProps) { const [open, setOpen] = React.useState(false) const [isSubmitting, setIsSubmitting] = React.useState(false) const [isUploading, setIsUploading] = React.useState(false) const [uploadedFiles, setUploadedFiles] = React.useState< { fileName: string; url: string; size?: number; originalFileName?: string }[] >([]) const router = useRouter() const { toast } = useToast() // react-hook-form 설정 const form = useForm({ resolver: zodResolver(createPqSchema), defaultValues: { code: "", checkPoint: "", groupName: groupOptions[0], subGroupName: "", description: "", remarks: "", inputFormat: "TEXT", type: "내외자", }, }) const formState = form.formState async function onSubmit(data: CreatePqFormType) { try { setIsSubmitting(true) // 서버 액션 호출 const result = await createPqCriteria(pqListId, { ...data, attachments: uploadedFiles, }) if (!result.success) { toast({ title: "오류", description: result.message || "PQ 항목 생성에 실패했습니다", variant: "destructive", }) return } // 성공 시 처리 toast({ title: "성공", description: result.message || "PQ 항목이 성공적으로 생성되었습니다", }) // 모달 닫고 폼 리셋 form.reset() setUploadedFiles([]) setOpen(false) // 페이지 새로고침 router.refresh() } catch (error) { console.error('Error creating PQ criteria:', error) toast({ title: "오류", description: "예상치 못한 오류가 발생했습니다", variant: "destructive", }) } finally { setIsSubmitting(false) } } function handleDialogOpenChange(nextOpen: boolean) { if (!nextOpen) { form.reset() setUploadedFiles([]) } setOpen(nextOpen) } const handleUpload = async (files: File[]) => { try { setIsUploading(true) for (const file of files) { const uploaded = await uploadPqCriteriaFileAction(file) setUploadedFiles((prev) => [...prev, uploaded]) } toast({ title: "업로드 완료", description: "첨부파일이 업로드되었습니다.", }) } catch (error) { console.error(error) toast({ title: "업로드 실패", description: "첨부파일 업로드 중 오류가 발생했습니다.", variant: "destructive", }) } finally { setIsUploading(false) } } return ( PQ 항목 생성 새 PQ 항목을 추가합니다.
{/* Group Name 필드 */} ( 대분류 * )} /> {/* Sub Group Name 필드 */} ( 소분류 세부 분류를 위한 서브 그룹명을 입력하세요 (선택사항) )} /> {/* Code 필드 */} ( 일련번호 * PQ 항목의 고유 코드를 입력하세요 )} /> {/* Check Point 필드 */} ( PQ 항목 * )} /> {/* Type 필드 */} ( 내/외자 구분 미선택 시 기본값은 내외자입니다. )} /> {/* Input Format 필드 */} ( 협력업체 입력사항 * )} /> {/* 첨부 파일 업로드 */}
첨부 파일 {isUploading && (
업로드 중...
)}
handleUpload(files)} onDropRejected={() => toast({ title: "업로드 실패", description: "파일 크기/형식을 확인하세요.", variant: "destructive", }) } disabled={isUploading} > {() => (
파일을 드래그하거나 클릭하여 업로드 PDF, 이미지, 문서 (최대 600MB)
기준 문서 첨부가 필요한 경우 업로드하세요.
)}
{uploadedFiles.length > 0 && (

첨부된 파일 ({uploadedFiles.length})

{uploadedFiles.map((file, idx) => ( {file.originalFileName || file.fileName} {file.size && ( {`${file.size} bytes`} )} setUploadedFiles((prev) => prev.filter((_, i) => i !== idx)) } > Remove ))}
)}
{/* Description 필드 */} ( 설명