'use client'; import { useState, useEffect } from 'react'; import { useRouter, useParams } from 'next/navigation'; import Link from 'next/link'; import Image from 'next/image'; import { ArrowLeft, Loader2, Link as LinkIcon, AlertCircle, CheckCircle2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { parseVideoUrl, fetchVideoMetadata, getThumbnailUrl, type VideoSource } from '@/lib/video-providers'; export default function NewVideoPage() { const router = useRouter(); const params = useParams(); const projectId = params.projectId as string; const [isLoading, setIsLoading] = useState(false); const [isFetchingMeta, setIsFetchingMeta] = useState(false); const [videoUrl, setVideoUrl] = useState(''); const [videoSource, setVideoSource] = useState(null); const [urlError, setUrlError] = useState(''); const [submitError, setSubmitError] = useState(''); const [formData, setFormData] = useState({ title: '', description: '', }); // Auto-fetch metadata when a valid video source is detected useEffect(() => { if (!videoSource) return; let cancelled = false; setIsFetchingMeta(true); fetchVideoMetadata(videoSource).then((meta) => { if (cancelled || !meta) { setIsFetchingMeta(false); return; } if (!formData.title) { setFormData((prev) => ({ ...prev, title: meta.title })); } setVideoSource((prev) => (prev ? { ...prev, metadata: meta } : prev)); setIsFetchingMeta(false); }); return () => { cancelled = true; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [videoSource?.videoId, videoSource?.providerId]); const handleUrlChange = (url: string) => { setVideoUrl(url); setUrlError(''); setSubmitError(''); if (!url.trim()) { setVideoSource(null); return; } const source = parseVideoUrl(url); if (source) { setVideoSource(source); } else { setVideoSource(null); if (url.length > 10) { setUrlError('Could not recognize this video URL. Currently supported: YouTube, Vimeo'); } } }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!videoSource) { setUrlError('Please enter a valid video URL'); return; } setIsLoading(true); setSubmitError(''); try { const thumbnailUrl = getThumbnailUrl(videoSource, 'large'); const title = formData.title.trim() || videoSource.metadata?.title || 'Untitled Video'; const response = await fetch(`/api/projects/${projectId}/videos`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title, description: formData.description.trim() || null, videoUrl: videoSource.originalUrl, providerId: videoSource.providerId, videoId: videoSource.videoId, thumbnailUrl, duration: videoSource.metadata?.duration || null, }), }); if (!response.ok) { const data = await response.json(); setSubmitError(data.error || 'Failed to add video'); return; } router.push(`/projects/${projectId}`); } catch (error) { console.error('Failed to add video:', error); setSubmitError('An unexpected error occurred'); } finally { setIsLoading(false); } }; const thumbnailUrl = videoSource ? getThumbnailUrl(videoSource, 'large') : null; return (
Back to Project
Add Video Paste a video link to add it to your project. Currently supports YouTube and Vimeo.
{/* Video URL Input */}
handleUrlChange(e.target.value)} className="pl-10" required disabled={isLoading} />
{urlError && (

{urlError}

)} {videoSource && (

{videoSource.providerId.charAt(0).toUpperCase() + videoSource.providerId.slice(1)} video detected {isFetchingMeta && ' — fetching metadata...'}

)}
{/* Video Preview */} {thumbnailUrl && videoSource && (
Video thumbnail
)} {/* Title */}
setFormData((prev) => ({ ...prev, title: e.target.value }))} disabled={isLoading} />

Leave empty to use the original video title

{/* Description */}