diff options
Diffstat (limited to 'lib/b-rfq/vendor-response/upload-response-dialog.tsx')
| -rw-r--r-- | lib/b-rfq/vendor-response/upload-response-dialog.tsx | 325 |
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 |
