'use client'; import { useState } from 'react'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { Play, MessageSquare, Clock, MoreVertical, Loader2, Link as LinkIcon, AlertCircle, CheckCircle2, Share2, Pencil, Plus, Trash2, } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '@/components/ui/alert-dialog'; import { parseVideoUrl, fetchVideoMetadata, getThumbnailUrl, type VideoSource } from '@/lib/video-providers'; interface VideoCardProps { video: { id: string; title: string; thumbnailUrl: string; currentVersion: number; commentCount: number; duration: string; lastUpdated: string; }; projectId: string; canManage: boolean; onDeleted?: (videoId: string) => void; } export function VideoCard({ video, projectId, canManage, onDeleted }: VideoCardProps) { const router = useRouter(); const [imgError, setImgError] = useState(false); const [retryKey, setRetryKey] = useState(0); // Edit dialog const [showEditDialog, setShowEditDialog] = useState(false); const [editTitle, setEditTitle] = useState(video.title); const [editDescription, setEditDescription] = useState(''); const [isSaving, setIsSaving] = useState(false); const [editError, setEditError] = useState(''); // Add Version dialog const [showVersionDialog, setShowVersionDialog] = useState(false); const [versionUrl, setVersionUrl] = useState(''); const [versionLabel, setVersionLabel] = useState(''); const [versionSource, setVersionSource] = useState(null); const [versionUrlError, setVersionUrlError] = useState(''); const [isCreatingVersion, setIsCreatingVersion] = useState(false); // Delete dialog const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [isDeleting, setIsDeleting] = useState(false); const handleEdit = async () => { setIsSaving(true); setEditError(''); try { const res = await fetch(`/api/projects/${projectId}/videos/${video.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: editTitle.trim(), description: editDescription.trim() || null, }), }); if (!res.ok) { const data = await res.json(); setEditError(data.error || 'Failed to update video'); return; } setShowEditDialog(false); router.refresh(); } catch { setEditError('An unexpected error occurred'); } finally { setIsSaving(false); } }; const handleVersionUrlChange = (url: string) => { setVersionUrl(url); setVersionUrlError(''); if (!url.trim()) { setVersionSource(null); return; } const source = parseVideoUrl(url); if (source) { setVersionSource(source); } else { setVersionSource(null); if (url.length > 10) setVersionUrlError('Unsupported URL'); } }; const handleCreateVersion = async () => { if (!versionSource) return; setIsCreatingVersion(true); try { const meta = await fetchVideoMetadata(versionSource); const thumbnailUrl = getThumbnailUrl(versionSource, 'large'); const res = await fetch(`/api/projects/${projectId}/videos/${video.id}/versions`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ videoUrl: versionSource.originalUrl, providerId: versionSource.providerId, providerVideoId: versionSource.videoId, versionLabel: versionLabel.trim() || null, thumbnailUrl, duration: meta?.duration || null, setActive: true, }), }); if (res.ok) { setShowVersionDialog(false); setVersionUrl(''); setVersionLabel(''); setVersionSource(null); router.refresh(); } } catch (err) { console.error('Failed to create version:', err); } finally { setIsCreatingVersion(false); } }; const handleDelete = async () => { setIsDeleting(true); try { const res = await fetch(`/api/projects/${projectId}/videos/${video.id}`, { method: 'DELETE', }); if (res.ok) { setShowDeleteDialog(false); onDeleted?.(video.id); router.refresh(); } } catch (err) { console.error('Failed to delete video:', err); } finally { setIsDeleting(false); } }; return ( <>
{/* Thumbnail */}
{imgError ? (
Processing...
) : ( // eslint-disable-next-line @next/next/no-img-element {video.title} { setImgError(true); // Check again after 10 seconds in case Bunny is still processing setTimeout(() => { setRetryKey(Date.now()); setImgError(false); }, 10000); }} /> )} {!imgError && (
)} {video.duration}

{video.title}

v{video.currentVersion} {video.commentCount} {video.lastUpdated}
{canManage ? ( Share setShowEditDialog(true)}> Edit setShowVersionDialog(true)}> Add Version setShowDeleteDialog(true)} > Delete ) : null}
{isDeleting && (
Deleting...
)}
{/* Edit Dialog */} Edit Video Update the video title and description.
setEditTitle(e.target.value)} disabled={isSaving} />