'use client'; import { useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { FaTimes, FaPlus, FaTrash, FaUpload, FaImage } from 'react-icons/fa'; import { Album, Song } from '@/lib/types'; interface AddAlbumModalProps { show: boolean; onClose: () => void; onAdd: (album: Album) => void; } export default function AddAlbumModal({ show, onClose, onAdd }: AddAlbumModalProps) { const [title, setTitle] = useState(''); const [year, setYear] = useState(''); const [genre, setGenre] = useState(''); const [description, setDescription] = useState(''); const [price, setPrice] = useState(''); const [coverImage, setCoverImage] = useState(''); const [coverImageFile, setCoverImageFile] = useState(null); const [isUploading, setIsUploading] = useState(false); const [songs, setSongs] = useState([{ id: '', title: '', duration: '', previewUrl: '', fullUrl: '' }]); const [error, setError] = useState(''); const [tag, setTag] = useState<'Album' | 'EP' | 'Demo' | 'Deluxe' | 'Single'>('Album'); const [format, setFormat] = useState<'mp3' | 'm4a' | 'flac' | 'wav'>('mp3'); const [bitrate, setBitrate] = useState('320kbps'); const [uploadMethod, setUploadMethod] = useState<'file' | 'url'>('file'); const [isDragging, setIsDragging] = useState(false); const [songUploadMethod, setSongUploadMethod] = useState<{ [key: number]: { preview: 'file' | 'url', full: 'file' | 'url' } }>({}); const [uploadingSong, setUploadingSong] = useState<{ index: number, field: 'preview' | 'full' } | null>(null); const handleAddSong = () => { setSongs([...songs, { id: '', title: '', duration: '', previewUrl: '', fullUrl: '' }]); }; const handleRemoveSong = (index: number) => { if (songs.length > 1) { setSongs(songs.filter((_, i) => i !== index)); } }; const handleSongChange = (index: number, field: 'title' | 'duration' | 'previewUrl' | 'fullUrl', value: string) => { const updatedSongs = [...songs]; updatedSongs[index][field] = value; setSongs(updatedSongs); }; const uploadFile = async (file: File) => { setCoverImageFile(file); setIsUploading(true); setError(''); try { const formData = new FormData(); formData.append('file', file); formData.append('folder', 'album-covers'); const response = await fetch('/api/upload', { method: 'POST', body: formData, }); if (!response.ok) { throw new Error('Upload failed'); } const data = await response.json(); setCoverImage(data.url); } catch (err) { setError('Failed to upload cover image'); setCoverImageFile(null); } finally { setIsUploading(false); } }; const handleCoverImageChange = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; await uploadFile(file); }; const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); setIsDragging(true); }; const handleDragLeave = (e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); }; const handleDrop = async (e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); const file = e.dataTransfer.files[0]; if (!file) return; // Validate file type const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'image/gif']; if (!allowedTypes.includes(file.type)) { setError('Invalid file type. Only images are allowed.'); return; } await uploadFile(file); }; const uploadAudioFile = async (file: File, index: number, field: 'preview' | 'full') => { setUploadingSong({ index, field }); setError(''); try { const formData = new FormData(); formData.append('file', file); formData.append('folder', field === 'preview' ? 'audio/previews' : 'audio/full'); const response = await fetch('/api/upload/audio', { method: 'POST', body: formData, }); if (!response.ok) { throw new Error('Upload failed'); } const data = await response.json(); const updatedSongs = [...songs]; updatedSongs[index][field === 'preview' ? 'previewUrl' : 'fullUrl'] = data.url; setSongs(updatedSongs); } catch (err) { setError(`Failed to upload ${field} audio file`); } finally { setUploadingSong(null); } }; const handleAudioFileChange = async (e: React.ChangeEvent, index: number, field: 'preview' | 'full') => { const file = e.target.files?.[0]; if (!file) return; await uploadAudioFile(file, index, field); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); setError(''); // Validation if (!title.trim()) { setError('Title is required'); return; } const yearNum = parseInt(year); if (!year || yearNum < 1900 || yearNum > new Date().getFullYear() + 1) { setError('Please enter a valid year'); return; } if (!genre.trim()) { setError('Genre is required'); return; } if (!description.trim()) { setError('Description is required'); return; } const priceNum = parseFloat(price); if (!price || priceNum <= 0) { setError('Please enter a valid price'); return; } // Validate songs for (let i = 0; i < songs.length; i++) { if (!songs[i].title.trim()) { setError(`Song ${i + 1} title is required`); return; } if (!songs[i].duration.trim()) { setError(`Song ${i + 1} duration is required`); return; } } // Create album const albumId = title.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); const albumSongs: Song[] = songs.map((song, index) => ({ id: `${albumId}-${index + 1}`, title: song.title, duration: song.duration, previewUrl: song.previewUrl || '/audio/preview-1.mp3', fullUrl: song.fullUrl || '/audio/default-full.mp3', })); const newAlbum: Album = { id: albumId, title, coverImage: coverImage || '/albums/default-cover.jpg', year: yearNum, genre, description, price: priceNum, songs: albumSongs, tag, format, bitrate, }; onAdd(newAlbum); handleClose(); }; const handleClose = () => { setTitle(''); setYear(''); setGenre(''); setDescription(''); setPrice(''); setCoverImage(''); setCoverImageFile(null); setSongs([{ id: '', title: '', duration: '', previewUrl: '', fullUrl: '' }]); setError(''); setTag('Album'); setFormat('mp3'); setBitrate('320kbps'); onClose(); }; return ( {show && ( e.stopPropagation()} className="glass-effect rounded-2xl max-w-2xl w-full max-h-[90vh] overflow-y-auto p-8 border-2 border-accent-cyan/30" > {/* Header */}

Add New Album

{/* Form */}
{/* Title */}
setTitle(e.target.value)} placeholder="Enter album title" className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg focus:border-accent-cyan focus:outline-none focus:ring-2 focus:ring-accent-cyan/50 text-white placeholder-gray-500" required />
{/* Cover Image Upload */}
{/* Method Tabs */}
{uploadMethod === 'file' ? ( <> {/* Drag & Drop Zone */}
{isUploading ? (

Uploading...

) : coverImage ? (
Cover preview

Image Uploaded Successfully

{coverImage}

) : (

Drag & drop your image here

or

)}

Supported: JPG, PNG, WEBP, GIF (max 5MB)

) : ( <> {/* URL Input */}
setCoverImage(e.target.value)} placeholder="https://example.com/album-cover.jpg" className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg focus:border-accent-cyan focus:outline-none focus:ring-2 focus:ring-accent-cyan/50 text-white placeholder-gray-500" /> {coverImage && (
Cover preview
)}

Enter the direct URL to the album cover image

)}
{/* Year and Genre */}
setYear(e.target.value)} placeholder="2024" min="1900" max={new Date().getFullYear() + 1} className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg focus:border-accent-cyan focus:outline-none focus:ring-2 focus:ring-accent-cyan/50 text-white placeholder-gray-500" required />
setGenre(e.target.value)} placeholder="Progressive Rock" className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg focus:border-accent-cyan focus:outline-none focus:ring-2 focus:ring-accent-cyan/50 text-white placeholder-gray-500" required />
{/* Description */}