summaryrefslogtreecommitdiff
path: root/lib/rfq-last/vendor-response/editor
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rfq-last/vendor-response/editor')
-rw-r--r--lib/rfq-last/vendor-response/editor/attachments-upload.tsx134
-rw-r--r--lib/rfq-last/vendor-response/editor/vendor-response-editor.tsx50
2 files changed, 169 insertions, 15 deletions
diff --git a/lib/rfq-last/vendor-response/editor/attachments-upload.tsx b/lib/rfq-last/vendor-response/editor/attachments-upload.tsx
index a2967767..ea7bb9c9 100644
--- a/lib/rfq-last/vendor-response/editor/attachments-upload.tsx
+++ b/lib/rfq-last/vendor-response/editor/attachments-upload.tsx
@@ -1,11 +1,20 @@
"use client"
import { useState, useRef } from "react"
+import { useSession } from "next-auth/react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Alert, AlertDescription } from "@/components/ui/alert"
import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import {
Table,
TableBody,
TableCell,
@@ -23,10 +32,13 @@ import {
Paperclip,
FileCheck,
Calculator,
- Wrench
+ Wrench,
+ X
} from "lucide-react"
import { formatBytes } from "@/lib/utils"
import { cn } from "@/lib/utils"
+import { toast } from "sonner"
+import { deleteVendorResponseAttachment } from "../../service"
interface FileWithType extends File {
attachmentType?: "구매" | "설계"
@@ -37,6 +49,9 @@ interface AttachmentsUploadProps {
attachments: FileWithType[]
onAttachmentsChange: (files: FileWithType[]) => void
existingAttachments?: any[]
+ onExistingAttachmentsChange?: (files: any[]) => void
+ responseId?: number
+ userId?: number
}
const acceptedFileTypes = {
@@ -49,13 +64,18 @@ const acceptedFileTypes = {
export default function AttachmentsUpload({
attachments,
onAttachmentsChange,
- existingAttachments = []
+ existingAttachments = [],
+ onExistingAttachmentsChange,
+ responseId,
+ userId
}: AttachmentsUploadProps) {
const purchaseInputRef = useRef<HTMLInputElement>(null)
const designInputRef = useRef<HTMLInputElement>(null)
const [purchaseDragActive, setPurchaseDragActive] = useState(false)
const [designDragActive, setDesignDragActive] = useState(false)
const [uploadErrors, setUploadErrors] = useState<string[]>([])
+ const [deleteDialogOpen, setDeleteDialogOpen] = useState(false)
+ const [fileToDelete, setFileToDelete] = useState<{file: any, isExisting: boolean, index: number} | null>(null)
// 파일 유효성 검사
const validateFile = (file: File): string | null => {
@@ -158,6 +178,57 @@ export default function AttachmentsUpload({
newFiles[index].attachmentType = newType
onAttachmentsChange(newFiles)
}
+
+ // 파일 삭제 확인
+ const handleDeleteClick = (file: any, isExisting: boolean, index: number) => {
+ setFileToDelete({ file, isExisting, index })
+ setDeleteDialogOpen(true)
+ }
+
+ // 파일 삭제 실행
+ const handleDeleteConfirm = async () => {
+ if (!fileToDelete) return
+
+ const { isExisting, index } = fileToDelete
+
+ if (isExisting) {
+ // 기존 첨부파일 삭제 - 서버액션 호출
+ if (responseId && userId && fileToDelete.file.id) {
+ try {
+ const result = await deleteVendorResponseAttachment({
+ attachmentId: fileToDelete.file.id,
+ responseId,
+ userId
+ })
+ if (result.success) {
+ // 클라이언트 상태 업데이트
+ const newExistingAttachments = existingAttachments.filter((_, i) => i !== index)
+ onExistingAttachmentsChange?.(newExistingAttachments)
+ } else {
+ toast.error(`삭제 실패: ${result.error}`)
+ return
+ }
+ } catch (error) {
+ console.error('삭제 API 호출 실패:', error)
+ toast.error('삭제 중 오류가 발생했습니다.')
+ return
+ }
+ }
+ } else {
+ // 새 첨부파일 삭제 (클라이언트에서만)
+ const newFiles = attachments.filter((_, i) => i !== index)
+ onAttachmentsChange(newFiles)
+ }
+
+ setDeleteDialogOpen(false)
+ setFileToDelete(null)
+ }
+
+ // 파일 삭제 취소
+ const handleDeleteCancel = () => {
+ setDeleteDialogOpen(false)
+ setFileToDelete(null)
+ }
// 파일 아이콘 가져오기
const getFileIcon = (fileName: string) => {
@@ -388,14 +459,24 @@ export default function AttachmentsUpload({
</Badge>
</TableCell>
<TableCell>
- <Button
- type="button"
- variant="ghost"
- size="sm"
- onClick={() => window.open(file.filePath, '_blank')}
- >
- <Download className="h-4 w-4" />
- </Button>
+ <div className="flex items-center gap-1">
+ <Button
+ type="button"
+ variant="ghost"
+ size="sm"
+ onClick={() => window.open(file.filePath, '_blank')}
+ >
+ <Download className="h-4 w-4" />
+ </Button>
+ <Button
+ type="button"
+ variant="ghost"
+ size="sm"
+ onClick={() => handleDeleteClick(file, true, index)}
+ >
+ <Trash2 className="h-4 w-4 text-red-500" />
+ </Button>
+ </div>
</TableCell>
</TableRow>
))}
@@ -449,7 +530,7 @@ export default function AttachmentsUpload({
type="button"
variant="ghost"
size="sm"
- onClick={() => handleFileRemove(index)}
+ onClick={() => handleDeleteClick(file, false, index)}
>
<Trash2 className="h-4 w-4 text-red-500" />
</Button>
@@ -461,6 +542,37 @@ export default function AttachmentsUpload({
</CardContent>
</Card>
)}
+
+ {/* 파일 삭제 확인 다이얼로그 */}
+ <Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
+ <DialogContent>
+ <DialogHeader>
+ <DialogTitle>파일 삭제</DialogTitle>
+ <DialogDescription>
+ {fileToDelete?.isExisting ? '기존 첨부파일' : '새로 업로드한 파일'} "{fileToDelete?.file.originalFileName || fileToDelete?.file.name}"을(를) 삭제하시겠습니까?
+ <br />
+ <strong>삭제된 파일은 복구할 수 없습니다.</strong>
+ </DialogDescription>
+ </DialogHeader>
+ <DialogFooter>
+ <Button
+ type="button"
+ variant="outline"
+ onClick={handleDeleteCancel}
+ >
+ 취소
+ </Button>
+ <Button
+ type="button"
+ variant="destructive"
+ onClick={handleDeleteConfirm}
+ >
+ <Trash2 className="h-4 w-4 mr-2" />
+ 삭제
+ </Button>
+ </DialogFooter>
+ </DialogContent>
+ </Dialog>
</div>
)
} \ No newline at end of file
diff --git a/lib/rfq-last/vendor-response/editor/vendor-response-editor.tsx b/lib/rfq-last/vendor-response/editor/vendor-response-editor.tsx
index 569546dd..fec9a2b9 100644
--- a/lib/rfq-last/vendor-response/editor/vendor-response-editor.tsx
+++ b/lib/rfq-last/vendor-response/editor/vendor-response-editor.tsx
@@ -14,6 +14,11 @@ import RfqInfoHeader from "./rfq-info-header"
import CommercialTermsForm from "./commercial-terms-form"
import QuotationItemsTable from "./quotation-items-table"
import AttachmentsUpload from "./attachments-upload"
+
+interface FileWithType extends File {
+ attachmentType?: "구매" | "설계"
+ description?: string
+}
import { formatDate, formatCurrency } from "@/lib/utils"
import { Shield, FileText, CheckCircle, XCircle, Clock, Download, Eye, Save, Send, AlertCircle, Upload, } from "lucide-react"
import { Progress } from "@/components/ui/progress"
@@ -103,11 +108,34 @@ export default function VendorResponseEditor({
const router = useRouter()
const [loading, setLoading] = useState(false)
const [activeTab, setActiveTab] = useState("info")
- const [attachments, setAttachments] = useState<File[]>([])
+ const [attachments, setAttachments] = useState<FileWithType[]>([])
+ const [existingAttachments, setExistingAttachments] = useState<any[]>([])
+ const [deletedAttachments, setDeletedAttachments] = useState<any[]>([])
const [uploadProgress, setUploadProgress] = useState(0) // 추가
console.log(existingResponse,"existingResponse")
+ // existingResponse가 변경될 때 existingAttachments 초기화
+ useEffect(() => {
+ if (existingResponse?.attachments) {
+ setExistingAttachments([...existingResponse.attachments])
+ setDeletedAttachments([]) // 삭제 목록 초기화
+ } else {
+ setExistingAttachments([])
+ setDeletedAttachments([])
+ }
+ }, [existingResponse?.attachments])
+
+ // 기존 첨부파일 삭제 처리
+ const handleExistingAttachmentsChange = (files: any[]) => {
+ const currentAttachments = existingResponse?.attachments || []
+ const deleted = currentAttachments.filter(
+ curr => !files.some(f => f.id === curr.id)
+ )
+ setExistingAttachments(files)
+ setDeletedAttachments(prev => [...prev, ...deleted])
+ }
+
// Form 초기값 설정
const defaultValues: VendorResponseFormData = {
@@ -229,10 +257,20 @@ export default function VendorResponseEditor({
try {
const formData = new FormData()
- const fileMetadata = attachments.map((file: any) => ({
+ const fileMetadata = attachments.map((file: FileWithType) => ({
attachmentType: file.attachmentType || "기타",
description: file.description || ""
}))
+
+ // 삭제된 첨부파일 ID 목록
+ const deletedAttachmentIds = deletedAttachments.map(file => file.id)
+
+ // 디버그: 첨부파일 attachmentType 확인
+ console.log('Attachments with types:', attachments.map(f => ({
+ name: f.name,
+ attachmentType: f.attachmentType,
+ size: f.size
+ })))
// 기본 데이터 추가
@@ -246,7 +284,8 @@ export default function VendorResponseEditor({
submittedBy: isSubmit ? userId : null,
totalAmount: data.quotationItems.reduce((sum, item) => sum + item.totalPrice, 0),
updatedBy: userId,
- fileMetadata
+ fileMetadata,
+ deletedAttachmentIds
}
console.log('Submitting data:', submitData) // 디버깅용
@@ -468,7 +507,10 @@ export default function VendorResponseEditor({
<AttachmentsUpload
attachments={attachments}
onAttachmentsChange={setAttachments}
- existingAttachments={existingResponse?.attachments}
+ existingAttachments={existingAttachments}
+ onExistingAttachmentsChange={handleExistingAttachmentsChange}
+ responseId={existingResponse?.id}
+ userId={userId}
/>
</TabsContent>
</Tabs>