"use client"; import { useState, useRef } from 'react'; import { Button, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Textarea } from '../ui'; import { Trash2, Plus, Image as ImageIcon, Video as VideoIcon, Upload, Loader2, GripVertical } from 'lucide-react'; import Image from '../../embed-shims/next-image'; import { Video } from './video'; export interface ReleaseMediaItem { media_type: 'image' | 'video' | 'screenshot' | 'demo'; media_url: string; title?: string; description?: string; display_order?: number; _file?: File; // Temporary file before upload _uploading?: boolean; // Upload in progress } interface ReleaseMediaManagerProps { media: ReleaseMediaItem[]; onChange: (media: ReleaseMediaItem[]) => void; onUpload: (file: File, mediaType: 'image' | 'video' | 'screenshot' | 'demo') => Promise; // Returns uploaded URL className?: string; } export function ReleaseMediaManager({ media, onChange, onUpload, className = '' }: ReleaseMediaManagerProps) { const fileInputRef = useRef(null); const [uploadingIndex, setUploadingIndex] = useState(null); const handleFileSelect = async (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (!file) return; // Determine media type let mediaType: 'image' | 'video' | 'screenshot' | 'demo'; if (file.type.startsWith('image/')) { mediaType = 'screenshot'; } else if (file.type.startsWith('video/')) { mediaType = 'demo'; } else { return; } // Add media item with uploading state const newIndex = media.length; const newMedia: ReleaseMediaItem = { media_type: mediaType, media_url: '', title: file.name, _file: file, _uploading: true }; onChange([...media, newMedia]); setUploadingIndex(newIndex); try { // Upload file const url = await onUpload(file, mediaType); // Update with uploaded URL const updated = [...media, { ...newMedia, media_url: url, _file: undefined, _uploading: false }]; onChange(updated); } catch (error) { // Remove failed upload onChange(media); } finally { setUploadingIndex(null); if (fileInputRef.current) { fileInputRef.current.value = ''; } } }; const removeMedia = (index: number) => { onChange(media.filter((_, i) => i !== index)); }; const updateMedia = (index: number, field: keyof ReleaseMediaItem, value: string) => { const updated = [...media]; updated[index] = { ...updated[index], [field]: value }; onChange(updated); }; const handleDragStart = (index: number) => (e: React.DragEvent) => { e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/plain', index.toString()); }; const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; }; const handleDrop = (targetIndex: number) => (e: React.DragEvent) => { e.preventDefault(); const sourceIndex = parseInt(e.dataTransfer.getData('text/plain')); if (sourceIndex === targetIndex) return; const newMedia = [...media]; const [draggedItem] = newMedia.splice(sourceIndex, 1); newMedia.splice(targetIndex, 0, draggedItem); onChange(newMedia.map((item, i) => ({ ...item, display_order: i }))); }; const getIcon = (type: string) => { switch (type) { case 'video': case 'demo': return ; default: return ; } }; return (
{/* Upload Section */}
{uploadingIndex !== null ? ( ) : ( )}

{uploadingIndex !== null ? 'Uploading...' : 'Upload Media'}

Drag and drop or click to select images and videos

Maximum file size: 50MB

{/* Media Grid */} {media.length > 0 && (

Drag to reorder

{media.map((item, index) => (
{/* Drag Handle */}
{/* Delete Button */}
{/* Media Preview */} {item.media_url && (
{item.media_type === 'video' || item.media_type === 'demo' ? ( //
)} {item._uploading && (
Uploading...
)} {/* Media Info */}
{getIcon(item.media_type)}
updateMedia(index, 'title', e.target.value)} onKeyDown={(e) => e.key === 'Enter' && e.preventDefault()} className="bg-ods-bg h-8 text-h6" disabled={item._uploading} />
))}
)} {media.length === 0 && (

No media uploaded yet

Upload your first image or video to get started

)}
); }