diff options
Diffstat (limited to 'lib/rfq-last/attachment/update-revision-dialog.tsx')
| -rw-r--r-- | lib/rfq-last/attachment/update-revision-dialog.tsx | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/lib/rfq-last/attachment/update-revision-dialog.tsx b/lib/rfq-last/attachment/update-revision-dialog.tsx new file mode 100644 index 00000000..ce31da64 --- /dev/null +++ b/lib/rfq-last/attachment/update-revision-dialog.tsx @@ -0,0 +1,216 @@ +"use client" + +import * as React from "react" +import { useForm } from "react-hook-form" +import { zodResolver } from "@hookform/resolvers/zod" +import { z } from "zod" +import { Upload } from "lucide-react" +import { toast } from "sonner" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form" +import { Button } from "@/components/ui/button" +import { Textarea } from "@/components/ui/textarea" +import { Input } from "@/components/ui/input" +import { Progress } from "@/components/ui/progress" + +const updateRevisionSchema = z.object({ + revisionComment: z.string().min(1, "리비전 설명을 입력해주세요"), + file: z.instanceof(File, { + message: "새 버전 파일을 선택해주세요", + }).refine((file) => file.size <= 100 * 1024 * 1024, { + message: "파일 크기는 100MB를 초과할 수 없습니다.", + }), +}) + +type UpdateRevisionFormData = z.infer<typeof updateRevisionSchema> + +interface UpdateRevisionDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + attachment: { + id: number; + originalFileName?: string | null; + currentRevision?: string | null; + }; + onSuccess?: () => void; +} + +export function UpdateRevisionDialog({ + open, + onOpenChange, + attachment, + onSuccess, +}: UpdateRevisionDialogProps) { + const [isSubmitting, setIsSubmitting] = React.useState(false) + const [uploadProgress, setUploadProgress] = React.useState(0) + + const form = useForm<UpdateRevisionFormData>({ + resolver: zodResolver(updateRevisionSchema), + defaultValues: { + revisionComment: "", + }, + }) + + const onSubmit = async (data: UpdateRevisionFormData) => { + setIsSubmitting(true); + setUploadProgress(0); + + try { + const formData = new FormData(); + formData.append("attachmentId", attachment.id.toString()); + formData.append("revisionComment", data.revisionComment); + formData.append("file", data.file); + + // 진행률 시뮬레이션 + setUploadProgress(30); + + const response = await fetch("/api/rfq-attachments/revision", { + method: "POST", + body: formData, + }); + + setUploadProgress(70); + + if (!response.ok) { + const error = await response.json(); + throw new Error(error.message || "리비전 업데이트 실패"); + } + + const result = await response.json(); + setUploadProgress(100); + + if (result.success) { + toast.success(result.message); + form.reset(); + onOpenChange(false); + onSuccess?.(); + } else { + toast.error(result.message); + } + } catch (error) { + toast.error(error instanceof Error ? error.message : "파일 업로드 중 오류가 발생했습니다"); + } finally { + setIsSubmitting(false); + setUploadProgress(0); + } + } + + return ( + <Dialog open={open} onOpenChange={onOpenChange}> + <DialogContent className="sm:max-w-[500px]"> + <DialogHeader> + <DialogTitle>새 버전 업로드</DialogTitle> + <DialogDescription> + {attachment.originalFileName && ( + <div className="mt-2"> + <div className="text-sm font-medium">현재 파일:</div> + <div className="text-sm text-muted-foreground"> + {attachment.originalFileName} + {attachment.currentRevision && ` (Rev. ${attachment.currentRevision})`} + </div> + </div> + )} + </DialogDescription> + </DialogHeader> + + <Form {...form}> + <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4"> + <FormField + control={form.control} + name="file" + render={({ field: { onChange, value, ...field } }) => ( + <FormItem> + <FormLabel>새 버전 파일</FormLabel> + <FormControl> + <Input + type="file" + accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.zip,.rar,.dwg,.dxf" + onChange={(e) => { + const file = e.target.files?.[0]; + if (file) { + onChange(file); + // 파일 크기 검증 + if (file.size > 100 * 1024 * 1024) { + form.setError("file", { + message: "파일 크기는 100MB를 초과할 수 없습니다." + }); + } + } + }} + disabled={isSubmitting} + {...field} + /> + </FormControl> + {value && ( + <p className="text-sm text-muted-foreground mt-1"> + 선택된 파일: {value.name} ({(value.size / 1024 / 1024).toFixed(2)}MB) + </p> + )} + <FormMessage /> + </FormItem> + )} + /> + + <FormField + control={form.control} + name="revisionComment" + render={({ field }) => ( + <FormItem> + <FormLabel>리비전 설명</FormLabel> + <FormControl> + <Textarea + placeholder="변경사항을 설명해주세요" + className="resize-none" + rows={3} + disabled={isSubmitting} + {...field} + /> + </FormControl> + <FormMessage /> + </FormItem> + )} + /> + + {isSubmitting && ( + <div className="space-y-2"> + <div className="flex justify-between text-sm"> + <span>업로드 진행중...</span> + <span>{uploadProgress}%</span> + </div> + <Progress value={uploadProgress} /> + </div> + )} + + <DialogFooter> + <Button + type="button" + variant="outline" + onClick={() => onOpenChange(false)} + disabled={isSubmitting} + > + 취소 + </Button> + <Button type="submit" disabled={isSubmitting}> + {isSubmitting ? "업로드 중..." : "업로드"} + </Button> + </DialogFooter> + </form> + </Form> + </DialogContent> + </Dialog> + ) +} |
