import React, { useRef, useState } from 'react'; import { Button } from './ui/button'; import { Upload, File, X, FileText, Presentation, CloudUpload } from 'lucide-react'; import { Card } from './ui/card'; import { Badge } from './ui/badge'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from './ui/dialog'; import type { UploadedFile, FileType } from '../App'; interface FileUploadAreaProps { uploadedFiles: UploadedFile[]; onFileUpload: (files: File[]) => void; onRemoveFile: (index: number) => void; onFileTypeChange: (index: number, type: FileType) => void; // ✅ 新增:真正触发后端上传(App 里实现) onUploadFile?: (index: number) => void; onUploadAll?: () => void; disabled?: boolean; } interface PendingFile { file: File; type: FileType; } export function FileUploadArea({ uploadedFiles, onFileUpload, onRemoveFile, onFileTypeChange, onUploadFile, onUploadAll, disabled = false, }: FileUploadAreaProps) { const [isDragging, setIsDragging] = useState(false); const fileInputRef = useRef(null); const [pendingFiles, setPendingFiles] = useState([]); const [showTypeDialog, setShowTypeDialog] = useState(false); const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); if (!disabled) setIsDragging(true); }; const handleDragLeave = () => { setIsDragging(false); }; const handleDrop = (e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); if (disabled) return; const files = Array.from(e.dataTransfer.files).filter((file) => ['.pdf', '.docx', '.pptx'].some((ext) => file.name.toLowerCase().endsWith(ext)) ); if (files.length > 0) { setPendingFiles(files.map((file) => ({ file, type: 'other' as FileType }))); setShowTypeDialog(true); } }; const handleFileSelect = (e: React.ChangeEvent) => { const files = Array.from(e.target.files || []); if (files.length > 0) { setPendingFiles(files.map((file) => ({ file, type: 'other' as FileType }))); setShowTypeDialog(true); } e.target.value = ''; }; const handleConfirmUpload = () => { // 这里只“入库”,不触发后端上传(符合你现在的逻辑) onFileUpload(pendingFiles.map((pf) => pf.file)); // 把用户在弹窗里选的 type 同步到父组件列表(通过 index 偏移) const startIndex = uploadedFiles.length; pendingFiles.forEach((pf, idx) => { setTimeout(() => { onFileTypeChange(startIndex + idx, pf.type); }, 0); }); setPendingFiles([]); setShowTypeDialog(false); }; const handleCancelUpload = () => { setPendingFiles([]); setShowTypeDialog(false); }; const handlePendingFileTypeChange = (index: number, type: FileType) => { setPendingFiles((prev) => prev.map((pf, i) => (i === index ? { ...pf, type } : pf))); }; const getFileIcon = (filename: string) => { const lower = filename.toLowerCase(); if (lower.endsWith('.pdf')) return FileText; if (lower.endsWith('.docx')) return File; if (lower.endsWith('.pptx')) return Presentation; return File; }; const formatFileSize = (bytes: number) => { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; }; const hasPendingUploads = uploadedFiles.some((f) => !f.uploaded); return (

Course Materials

{uploadedFiles.length > 0 && {uploadedFiles.length} file(s)}
{/* ✅ Upload All Pending(只在存在 pending 且提供了回调时显示) */} {uploadedFiles.length > 0 && hasPendingUploads && !!onUploadAll && ( )}
{/* Upload Area */}
!disabled && fileInputRef.current?.click()} >

{disabled ? 'Please log in to upload' : 'Drop files or click to upload'}

.pdf, .docx, .pptx

{/* Uploaded Files List */} {uploadedFiles.length > 0 && (
{uploadedFiles.map((uploadedFile, index) => { const Icon = getFileIcon(uploadedFile.file.name); const isUploaded = !!uploadedFile.uploaded; return (

{uploadedFile.file.name}

{formatFileSize(uploadedFile.file.size)}

{/* ✅ 单文件 Upload(仅未上传时显示 & 必须有回调) */} {!isUploaded && !!onUploadFile && ( )} {/* ✅ 已上传状态 */} {isUploaded && ( Uploaded{typeof uploadedFile.uploadedChunks === 'number' ? ` (+${uploadedFile.uploadedChunks})` : ''} )}
); })}
)} {/* Type Selection Dialog */} {showTypeDialog && ( Select File Types Please select the type for each file you are uploading.
{pendingFiles.map((pendingFile, index) => { const Icon = getFileIcon(pendingFile.file.name); return (

{pendingFile.file.name}

{formatFileSize(pendingFile.file.size)}

); })}
)}
); }