import { useState, useCallback } from 'react'; import { useDropzone } from 'react-dropzone'; import { useForm } from 'react-hook-form'; import { Dialog, DialogHeader, DialogBody, DialogFooter } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Progress } from '@/components/ui/progress'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Alert } from '@/components/ui/alert'; import { Upload, X, FileAudio, AlertCircle, CheckCircle2 } from 'lucide-react'; import { uploadTrack, type TrackMetadata } from '@/features/tracks/api/trackApi'; import { useQueryClient } from '@tanstack/react-query'; import { LIBRARY_KEYS } from '@/features/library/hooks/useMyTracks'; import type { Track } from '@/features/tracks/types/track'; export interface UploadModalProps { open: boolean; onClose: () => void; } const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100 MB const ACCEPTED_AUDIO_TYPES = { 'audio/mpeg': ['.mp3'], 'audio/wav': ['.wav'], 'audio/ogg': ['.ogg'], 'audio/flac': ['.flac'], 'audio/mp4': ['.m4a'], 'audio/aac': ['.aac'], }; type UploadFormData = { file: File | null; title: string; artist: string; album: string; genre: string; }; export function UploadModal({ open, onClose }: UploadModalProps) { const [file, setFile] = useState(null); const [uploadProgress, setUploadProgress] = useState(0); const [isUploading, setIsUploading] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(false); const queryClient = useQueryClient(); const { register, handleSubmit, setValue, getValues, formState: { errors }, reset, } = useForm({ defaultValues: { file: null, title: '', artist: '', album: '', genre: '', }, }); const onDrop = useCallback( (acceptedFiles: File[]) => { const selectedFile = acceptedFiles[0]; if (selectedFile) { setFile(selectedFile); setError(null); setSuccess(false); // Mettre à jour le formulaire avec setValue pour que react-hook-form connaisse le fichier setValue('file', selectedFile, { shouldValidate: true }); // Pré-remplir le titre avec le nom du fichier (sans extension) const fileNameWithoutExt = selectedFile.name.replace(/\.[^/.]+$/, ''); // Lecture à la demande avec getValues, pas de re-render const currentTitle = getValues('title'); if (!currentTitle) { setValue('title', fileNameWithoutExt, { shouldValidate: true }); } } }, [setValue, getValues], ); const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop, accept: ACCEPTED_AUDIO_TYPES, maxSize: MAX_FILE_SIZE, multiple: false, onError: (err) => { setError(`Erreur lors de la sélection du fichier: ${err.message}`); }, onDropRejected: (fileRejections) => { const rejection = fileRejections[0]; if (rejection.errors[0]?.code === 'file-too-large') { setError('Le fichier est trop volumineux (max 100 MB)'); } else if (rejection.errors[0]?.code === 'file-invalid-type') { setError('Format de fichier non supporté. Formats acceptés: MP3, WAV, OGG, FLAC, M4A, AAC'); } else { setError(rejection.errors[0]?.message || 'Erreur lors de la sélection du fichier'); } }, }); const onSubmit = async (data: UploadFormData) => { console.log('📝 Form submitting...'); console.log('🚀 Form submitted!', data); if (!data.file) { setError('Veuillez sélectionner un fichier'); return; } setIsUploading(true); setError(null); setSuccess(false); setUploadProgress(0); try { const trackMetadata: TrackMetadata = { title: data.title || data.file.name.replace(/\.[^/.]+$/, ''), artist: data.artist, album: data.album, genre: data.genre, is_public: false, }; const track = await uploadTrack( data.file, trackMetadata, (progress) => { setUploadProgress(progress); }, ); setSuccess(true); setUploadProgress(100); // Invalider les queries pour rafraîchir la liste queryClient.invalidateQueries({ queryKey: LIBRARY_KEYS.all }); queryClient.invalidateQueries({ queryKey: ['tracks'] }); // Fermer après 1.5 secondes setTimeout(() => { handleClose(); }, 1500); } catch (err) { const errorMessage = err instanceof Error ? err.message : "Erreur lors de l'upload"; setError(errorMessage); setUploadProgress(0); } finally { setIsUploading(false); } }; const handleClose = () => { if (!isUploading) { setFile(null); setUploadProgress(0); setError(null); setSuccess(false); reset(); onClose(); } }; const handleRemoveFile = () => { setFile(null); setError(null); setSuccess(false); setUploadProgress(0); setValue('file', null, { shouldValidate: true }); }; return (
{ console.error('❌ Form Errors:', errors); })} >
{/* Zone de Drag & Drop */} {!file ? (

{isDragActive ? 'Déposez le fichier ici' : 'Glissez-déposez un fichier audio'}

ou cliquez pour sélectionner

Formats acceptés: MP3, WAV, OGG, FLAC, M4A, AAC (max 100 MB)

) : (

{file.name}

{(file.size / 1024 / 1024).toFixed(2)} MB

{!isUploading && ( )}
)} {/* Progress Bar */} {isUploading && (
Upload en cours... {uploadProgress}%
)} {/* Messages d'erreur */} {error && ( {error} )} {/* Message de succès */} {success && ( Fichier uploadé avec succès ! )} {/* Formulaire de métadonnées */} {file && !isUploading && !success && (

Métadonnées (optionnel)

{errors.title && (

{errors.title.message}

)}
)}
{!success && ( )}
); }