"use client" import * as React from "react" import { zodResolver } from "@hookform/resolvers/zod" import { Loader, Save } from "lucide-react" import { useForm } from "react-hook-form" import { toast } from "sonner" import { z } from "zod" import { useRouter } from "next/navigation" import { Button } from "@/components/ui/button" import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form" import { Select, SelectContent, // SelectGroup, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, } from "@/components/ui/sheet" import { Input } from "@/components/ui/input" import { Textarea } from "@/components/ui/textarea" import { updatePqCriteria } from "../service" import { groupOptions } from "./add-pq-dialog" import { Checkbox } from "@/components/ui/checkbox" import { uploadPqCriteriaFileAction, getPqCriteriaAttachments } 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 updatePqSchema = 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"), description: z.string().optional(), remarks: z.string().optional(), inputFormat: z.string().default("TEXT"), subGroupName: z.string().optional(), type: z.string().optional(), }); type UpdatePqSchema = z.infer; // 입력 형식 옵션 const inputFormatOptions = [ { value: "TEXT", label: "텍스트" }, { value: "FILE", label: "파일" }, { value: "EMAIL", label: "이메일" }, { value: "PHONE", label: "전화번호" }, { value: "NUMBER", label: "숫자" }, { value: "NUMBER_WITH_UNIT", label: "숫자+단위" }, { value: "TEXT_FILE", label: "텍스트 + 파일" } ]; const typeOptions = [ { value: "내자", label: "내자" }, { value: "외자", label: "외자" }, { value: "내외자", label: "내외자" }, ]; interface UpdatePqSheetProps extends React.ComponentPropsWithRef { pq: { id: number; code: string; checkPoint: string; description: string | null; remarks: string | null; groupName: string | null; inputFormat: string; subGroupName: string | null; type?: string | null; } | null } export function UpdatePqSheet({ pq, ...props }: UpdatePqSheetProps) { const [isUpdatePending, startUpdateTransition] = React.useTransition() const [isUploading, setIsUploading] = React.useState(false) const [attachments, setAttachments] = React.useState< { fileName: string; url: string; size?: number; originalFileName?: string }[] >([]) const router = useRouter() const form = useForm({ resolver: zodResolver(updatePqSchema), defaultValues: { code: pq?.code ?? "", checkPoint: pq?.checkPoint ?? "", groupName: pq?.groupName ?? groupOptions[0], description: pq?.description ?? "", remarks: pq?.remarks ?? "", inputFormat: pq?.inputFormat ?? "TEXT", subGroupName: pq?.subGroupName ?? "", type: pq?.type ?? "내외자", }, }) // 폼 초기화 (pq가 변경될 때) React.useEffect(() => { if (pq) { form.reset({ code: pq.code, checkPoint: pq.checkPoint, groupName: pq.groupName ?? groupOptions[0], description: pq.description ?? "", remarks: pq.remarks ?? "", inputFormat: pq.inputFormat ?? "TEXT", subGroupName: pq.subGroupName ?? "", type: pq.type ?? "내외자", }); // 기존 첨부 로드 getPqCriteriaAttachments(pq.id).then((res) => { if (res.success && res.data) { setAttachments( res.data.map((a) => ({ fileName: a.fileName, url: a.filePath, size: a.fileSize ?? undefined, originalFileName: a.originalFileName || a.fileName, })) ) } else { setAttachments([]) } }) } }, [pq, form]); const handleUpload = async (files: File[]) => { try { setIsUploading(true) for (const file of files) { const uploaded = await uploadPqCriteriaFileAction(file) setAttachments((prev) => [...prev, uploaded]) } toast.success("첨부파일이 업로드되었습니다") } catch (error) { console.error(error) toast.error("첨부파일 업로드에 실패했습니다") } finally { setIsUploading(false) } } function onSubmit(input: UpdatePqSchema) { startUpdateTransition(async () => { if (!pq) return const result = await updatePqCriteria(pq.id, { ...input, attachments, }) if (!result.success) { toast.error(result.message || "PQ 항목 수정에 실패했습니다") return } toast.success(result.message || "PQ 항목이 성공적으로 수정되었습니다") form.reset() props.onOpenChange?.(false) router.refresh() }) } return ( Update PQ Criteria Update the PQ criteria details and save the changes
{/* Code 필드 */} ( Code * )} /> {/* Check Point 필드 */} ( Check Point * )} /> {/* Group Name 필드 (Select) */} ( Group * )} /> {/* Sub Group Name 필드 */} ( Sub Group Name )} /> {/* Type 필드 */} ( 내/외자 구분 미선택 시 기본값은 내외자입니다. )} /> {/* Input Format 필드 */} ( 입력 형식 )} /> {/* 첨부 파일 업로드 */}
첨부 파일 {isUploading && (
업로드 중...
)}
handleUpload(files)} onDropRejected={() => toast.error("파일 크기/형식을 확인하세요.") } disabled={isUploading} > {() => (
파일을 드래그하거나 클릭하여 업로드 PDF, 이미지, 문서 (최대 600MB)
기준 문서 첨부가 필요한 경우 업로드하세요.
)}
{attachments.length > 0 && (

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

{attachments.map((file, idx) => ( {file.originalFileName || file.fileName} {file.size && ( {`${file.size} bytes`} )} setAttachments((prev) => prev.filter((_, i) => i !== idx)) } > Remove ))}
)}
{/* Required 체크박스 */} {/* Description 필드 */} ( Description