summaryrefslogtreecommitdiff
path: root/lib/b-rfq/vendor-response/upload-response-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/b-rfq/vendor-response/upload-response-dialog.tsx')
-rw-r--r--lib/b-rfq/vendor-response/upload-response-dialog.tsx325
1 files changed, 0 insertions, 325 deletions
diff --git a/lib/b-rfq/vendor-response/upload-response-dialog.tsx b/lib/b-rfq/vendor-response/upload-response-dialog.tsx
deleted file mode 100644
index b4b306d6..00000000
--- a/lib/b-rfq/vendor-response/upload-response-dialog.tsx
+++ /dev/null
@@ -1,325 +0,0 @@
-// components/rfq/upload-response-dialog.tsx
-"use client";
-
-import { useState } from "react";
-import { Button } from "@/components/ui/button";
-import { Badge } from "@/components/ui/badge";
-import {
- Dialog,
- DialogContent,
- DialogHeader,
- DialogTitle,
- DialogTrigger,
-} from "@/components/ui/dialog";
-import {
- Form,
- FormControl,
- FormField,
- FormItem,
- FormLabel,
- FormMessage,
-} from "@/components/ui/form";
-import { Input } from "@/components/ui/input";
-import { Textarea } from "@/components/ui/textarea";
-import { useForm } from "react-hook-form";
-import { zodResolver } from "@hookform/resolvers/zod";
-import * as z from "zod";
-import { Upload, FileText, X, Loader2 } from "lucide-react";
-import { useToast } from "@/hooks/use-toast"
-import { useRouter } from "next/navigation";
-
-const uploadFormSchema = z.object({
- files: z.array(z.instanceof(File)).min(1, "최소 1개의 파일을 선택해주세요"),
- responseComment: z.string().optional(),
- vendorComment: z.string().optional(),
-});
-
-type UploadFormData = z.infer<typeof uploadFormSchema>;
-
-interface UploadResponseDialogProps {
- responseId: number;
- attachmentType: string;
- serialNo: string;
- currentRevision: string;
- trigger?: React.ReactNode;
- onSuccess?: () => void;
-}
-
-export function UploadResponseDialog({
- responseId,
- attachmentType,
- serialNo,
- currentRevision,
- trigger,
- onSuccess,
-}: UploadResponseDialogProps) {
- const [open, setOpen] = useState(false);
- const [isUploading, setIsUploading] = useState(false);
- const { toast } = useToast();
- const router = useRouter();
-
- const form = useForm<UploadFormData>({
- resolver: zodResolver(uploadFormSchema),
- defaultValues: {
- files: [],
- responseComment: "",
- vendorComment: "",
- },
- });
-
- const selectedFiles = form.watch("files");
-
- const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
- const files = Array.from(e.target.files || []);
- if (files.length > 0) {
- form.setValue("files", files);
- }
- };
-
- const removeFile = (index: number) => {
- const currentFiles = form.getValues("files");
- const newFiles = currentFiles.filter((_, i) => i !== index);
- form.setValue("files", newFiles);
- };
-
- const formatFileSize = (bytes: number): string => {
- if (bytes === 0) return "0 Bytes";
- const k = 1024;
- const sizes = ["Bytes", "KB", "MB", "GB"];
- const i = Math.floor(Math.log(bytes) / Math.log(k));
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
- };
-
- const handleOpenChange = (newOpen: boolean) => {
- setOpen(newOpen);
- // 다이얼로그가 닫힐 때 form 리셋
- if (!newOpen) {
- form.reset();
- }
- };
-
- const handleCancel = () => {
- form.reset();
- setOpen(false);
- };
-
- const onSubmit = async (data: UploadFormData) => {
- setIsUploading(true);
-
- try {
- // 1. 각 파일을 업로드 API로 전송
- const uploadedFiles = [];
-
- for (const file of data.files) {
- const formData = new FormData();
- formData.append("file", file);
- formData.append("responseId", responseId.toString());
- formData.append("description", ""); // 필요시 파일별 설명 추가 가능
-
- const uploadResponse = await fetch("/api/vendor-responses/upload", {
- method: "POST",
- body: formData,
- });
-
- if (!uploadResponse.ok) {
- const error = await uploadResponse.json();
- throw new Error(error.message || "파일 업로드 실패");
- }
-
- const uploadResult = await uploadResponse.json();
- uploadedFiles.push(uploadResult);
- }
-
- // 2. vendor response 상태 업데이트 (서버에서 자동으로 리비전 증가)
- const updateResponse = await fetch("/api/vendor-responses/update", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({
- responseId,
- responseStatus: "RESPONDED",
- // respondedRevision 제거 - 서버에서 자동 처리
- responseComment: data.responseComment,
- vendorComment: data.vendorComment,
- respondedAt: new Date().toISOString(),
- }),
- });
-
- if (!updateResponse.ok) {
- const error = await updateResponse.json();
- throw new Error(error.message || "응답 상태 업데이트 실패");
- }
-
- const updateResult = await updateResponse.json();
-
- toast({
- title: "업로드 완료",
- description: `${data.files.length}개 파일이 성공적으로 업로드되었습니다. (${updateResult.newRevision})`,
- });
-
- setOpen(false);
- form.reset();
-
- router.refresh();
- onSuccess?.();
-
- } catch (error) {
- console.error("Upload error:", error);
- toast({
- title: "업로드 실패",
- description: error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다.",
- variant: "destructive",
- });
- } finally {
- setIsUploading(false);
- }
- };
-
- return (
- <Dialog open={open} onOpenChange={handleOpenChange}>
- <DialogTrigger asChild>
- {trigger || (
- <Button size="sm">
- <Upload className="h-3 w-3 mr-1" />
- 업로드
- </Button>
- )}
- </DialogTrigger>
- <DialogContent className="max-w-2xl max-h-[80vh] overflow-y-auto">
- <DialogHeader>
- <DialogTitle className="flex items-center gap-2">
- <Upload className="h-5 w-5" />
- 응답 파일 업로드
- </DialogTitle>
- <div className="flex items-center gap-2 text-sm text-muted-foreground">
- <Badge variant="outline">{serialNo}</Badge>
- <span>{attachmentType}</span>
- <Badge variant="secondary">{currentRevision}</Badge>
- <span className="text-xs text-blue-600">→ 벤더 응답 리비전 자동 증가</span>
- </div>
- </DialogHeader>
-
- <Form {...form}>
- <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
- {/* 파일 선택 */}
- <FormField
- control={form.control}
- name="files"
- render={({ field }) => (
- <FormItem>
- <FormLabel>파일 선택</FormLabel>
- <FormControl>
- <div className="space-y-4">
- <Input
- type="file"
- multiple
- onChange={handleFileSelect}
- accept=".pdf,.doc,.docx,.xls,.xlsx,.png,.jpg,.jpeg,.zip,.rar"
- className="cursor-pointer"
- />
- <div className="text-xs text-muted-foreground">
- 지원 파일: PDF, DOC, DOCX, XLS, XLSX, PNG, JPG, ZIP, RAR (최대 10MB)
- </div>
- </div>
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
-
- {/* 선택된 파일 목록 */}
- {selectedFiles.length > 0 && (
- <div className="space-y-2">
- <div className="text-sm font-medium">선택된 파일 ({selectedFiles.length}개)</div>
- <div className="space-y-2 max-h-40 overflow-y-auto">
- {selectedFiles.map((file, index) => (
- <div
- key={index}
- className="flex items-center justify-between p-3 bg-muted/50 rounded-lg"
- >
- <div className="flex items-center gap-2 flex-1 min-w-0">
- <FileText className="h-4 w-4 text-muted-foreground flex-shrink-0" />
- <div className="min-w-0 flex-1">
- <div className="text-sm font-medium truncate">{file.name}</div>
- <div className="text-xs text-muted-foreground">
- {formatFileSize(file.size)}
- </div>
- </div>
- </div>
- <Button
- type="button"
- variant="ghost"
- size="sm"
- onClick={() => removeFile(index)}
- className="flex-shrink-0 ml-2"
- >
- <X className="h-4 w-4" />
- </Button>
- </div>
- ))}
- </div>
- </div>
- )}
-
- {/* 응답 코멘트 */}
- <FormField
- control={form.control}
- name="responseComment"
- render={({ field }) => (
- <FormItem>
- <FormLabel>응답 코멘트</FormLabel>
- <FormControl>
- <Textarea
- placeholder="응답에 대한 설명을 입력하세요..."
- className="resize-none"
- rows={3}
- {...field}
- />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
-
- {/* 벤더 코멘트 */}
- <FormField
- control={form.control}
- name="vendorComment"
- render={({ field }) => (
- <FormItem>
- <FormLabel>벤더 코멘트 (내부용)</FormLabel>
- <FormControl>
- <Textarea
- placeholder="내부 참고용 코멘트를 입력하세요..."
- className="resize-none"
- rows={2}
- {...field}
- />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
-
- {/* 버튼 */}
- <div className="flex justify-end gap-2">
- <Button
- type="button"
- variant="outline"
- onClick={handleCancel}
- disabled={isUploading}
- >
- 취소
- </Button>
- <Button type="submit" disabled={isUploading || selectedFiles.length === 0}>
- {isUploading && <Loader2 className="h-4 w-4 mr-2 animate-spin" />}
- {isUploading ? "업로드 중..." : "업로드"}
- </Button>
- </div>
- </form>
- </Form>
- </DialogContent>
- </Dialog>
- );
-} \ No newline at end of file