summaryrefslogtreecommitdiff
path: root/lib/rfq-last/attachment/update-revision-dialog.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-09-04 08:31:31 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-09-04 08:31:31 +0000
commitb67e36df49f067cbd5ba899f9fbcc755f38d4b4f (patch)
tree5a71c5960f90d988cd509e3ef26bff497a277661 /lib/rfq-last/attachment/update-revision-dialog.tsx
parentb7f54b06c1ef9e619f5358fb0a5caad9703c8905 (diff)
(대표님, 최겸, 임수민) 작업사항 커밋
Diffstat (limited to 'lib/rfq-last/attachment/update-revision-dialog.tsx')
-rw-r--r--lib/rfq-last/attachment/update-revision-dialog.tsx216
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>
+ )
+}