"use client"; import React, { useState, useRef, useCallback } from 'react'; import { Modal, ModalHeader, ModalTitle, Button, Card } from '../ui'; import { Upload, Image as ImageIcon, Video as VideoIcon, Trash2, Loader2, GripVertical, Plus } from 'lucide-react'; import Image from '../../embed-shims/next-image'; import { Video } from './video'; export interface MediaItem { id?: string | number; // Optional for new items media_type: 'image' | 'video' | 'screenshot' | 'demo'; media_url: string; title?: string; description?: string; display_order?: number; _uploading?: boolean; } interface MediaGalleryManagerProps { media: MediaItem[]; onChange: (media: MediaItem[]) => void; onUpload: (file: File, mediaType: 'image' | 'video') => Promise; isUploading?: boolean; showInModal?: boolean; modalTitle?: string; className?: string; } /** * Unified Media Gallery Manager * Handles upload, display, reordering, and deletion of media items * Used across events, product releases, and any content with media galleries */ export function MediaGalleryManager({ media, onChange, onUpload, isUploading = false, showInModal = false, modalTitle = 'Media Gallery', className = '' }: MediaGalleryManagerProps) { const fileInputRef = useRef(null); const [deletingIndex, setDeletingIndex] = useState(null); const [draggedIndex, setDraggedIndex] = useState(null); const handleFileSelect = useCallback(async (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (!file) return; // Determine media type let mediaType: 'image' | 'video'; if (file.type.startsWith('image/')) { mediaType = 'image'; } else if (file.type.startsWith('video/')) { mediaType = 'video'; } else { return; } try { const url = await onUpload(file, mediaType); // Add new media item onChange([...media, { media_type: mediaType === 'image' ? 'screenshot' : 'demo', media_url: url, title: file.name, display_order: media.length }]); // Reset file input if (fileInputRef.current) { fileInputRef.current.value = ''; } } catch (error) { console.error('Upload failed:', error); } }, [media, onChange, onUpload]); const handleDeleteMedia = useCallback((index: number) => { setDeletingIndex(index); onChange(media.filter((_, i) => i !== index)); setDeletingIndex(null); }, [media, onChange]); const handleDragStart = useCallback((index: number) => { setDraggedIndex(index); }, []); const handleDragOver = useCallback((e: React.DragEvent) => { e.preventDefault(); }, []); const handleDrop = useCallback((e: React.DragEvent, targetIndex: number) => { e.preventDefault(); if (draggedIndex === null || draggedIndex === targetIndex) { setDraggedIndex(null); return; } const newMedia = [...media]; const [draggedItem] = newMedia.splice(draggedIndex, 1); newMedia.splice(targetIndex, 0, draggedItem); onChange(newMedia.map((item, i) => ({ ...item, display_order: i }))); setDraggedIndex(null); }, [media, draggedIndex, onChange]); const renderMediaItem = useCallback((mediaItem: MediaItem, index: number) => { const isDeleting = deletingIndex === index; return ( handleDragStart(index)} onDragOver={handleDragOver} onDrop={(e) => handleDrop(e, index)} > {/* Drag Handle */}
{/* Delete Button */}
{/* Media Content */}
{mediaItem.media_type === 'video' || mediaItem.media_type === 'demo' ? ( //
{/* Media Info */}
{mediaItem.media_type === 'video' || mediaItem.media_type === 'demo' ? ( ) : ( )} {mediaItem.media_type}
{mediaItem.title && (

{mediaItem.title}

)}
); }, [deletingIndex, handleDragStart, handleDragOver, handleDrop, handleDeleteMedia]); const content = (
{/* Upload Section */}
{isUploading ? ( ) : ( )}

{isUploading ? 'Uploading...' : 'Upload Media'}

Drag and drop or click to select images and videos

Maximum file size: 50MB

{/* Media Grid */} {media.length === 0 ? (

No media uploaded yet

Upload your first image or video to get started

) : (

Media Gallery ({media.length})

Drag to reorder

{media.map((item, index) => renderMediaItem(item, index))}
)}
); return content; }