/** * File: VideoThumbnail.tsx * Created by: AI Assistant * Date: 2025-12-05 * Purpose: Video thumbnail component with lazy loading for kreatiVortex platform * Part of: kreatiVortex - Platform Pembelajaran Tari Online */ 'use client'; import { useState, useRef, useEffect } from 'react'; import { Link } from '@/i18n/routing'; import { Play, Video } from 'lucide-react'; interface VideoThumbnailProps { video: { id: string; title: string; videoType: 'YOUTUBE' | 'LOCAL'; videoUrl: string; isPublic: boolean; }; } function VideoThumbnail({ video }: VideoThumbnailProps) { const [isLoaded, setIsLoaded] = useState(false); const [error, setError] = useState(false); const imgRef = useRef(null); // Generate YouTube thumbnail URL const getYouTubeThumbnailUrl = (url: string) => { const videoId = url.match(/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([^&\n?#]+)/); return videoId ? `https://img.youtube.com/vi/${videoId[1]}/mqdefault.jpg` : null; }; const thumbnailUrl = video.videoType === 'YOUTUBE' ? getYouTubeThumbnailUrl(video.videoUrl) : null; useEffect(() => { const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting && imgRef.current && thumbnailUrl) { imgRef.current.src = thumbnailUrl; observer.unobserve(entry.target); } }); }, { threshold: 0.1 } ); if (imgRef.current) { observer.observe(imgRef.current); } return () => observer.disconnect(); }, [thumbnailUrl]); return (
{video.videoType === 'YOUTUBE' && thumbnailUrl ? ( <> {video.title} setIsLoaded(true)} onError={() => setError(true)} /> {!isLoaded && !error && (
)} {error && (
)} ) : (
)} {/* Play Button Overlay */}
{/* Status Badge */}
{video.isPublic ? 'Public' : 'Private'}
{/* Video Type Badge */}
{video.videoType}
); } export default VideoThumbnail;