'use client'; import Link from 'next/link'; import Image from 'next/image'; import { useState, useCallback } from 'react'; import { VideoData } from '@/app/constants'; import LoadingSpinner from './LoadingSpinner'; function formatViews(views: number): string { if (views >= 1000000) return (views / 1000000).toFixed(1) + 'M'; if (views >= 1000) return (views / 1000).toFixed(1) + 'K'; return views.toString(); } function getStableRelativeTime(id: string): string { const times = ['2 hours ago', '5 hours ago', '1 day ago', '3 days ago', '1 week ago', '2 weeks ago', '1 month ago']; const hash = id.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0); return times[hash % times.length]; } import { memo } from 'react'; const DEFAULT_THUMBNAIL = 'https://i.ytimg.com/vi/default/hqdefault.jpg'; function VideoCard({ video, hideChannelAvatar }: { video: VideoData; hideChannelAvatar?: boolean }) { const relativeTime = video.upload_date || video.publishedAt || getStableRelativeTime(video.id); const [isNavigating, setIsNavigating] = useState(false); const destination = video.list_id ? `/watch?v=${video.id}&list=${video.list_id}` : `/watch?v=${video.id}`; const thumbnailSrc = video.thumbnail || DEFAULT_THUMBNAIL; const handleImageError = useCallback((e: React.SyntheticEvent) => { const img = e.target as HTMLImageElement; if (img.src !== DEFAULT_THUMBNAIL) { img.src = DEFAULT_THUMBNAIL; } }, []); return (
setIsNavigating(true)} style={{ position: 'relative', display: 'block', width: '100%', aspectRatio: '16/9', overflow: 'hidden', borderRadius: '12px' }} > {video.title} {video.duration && !video.is_mix && (
{video.duration}
)} {video.is_mix && (
Mix
)} {isNavigating && (
)}
{/* Video Info */}

{video.title}

{video.channel_id ? ( {video.uploader || video.channelTitle || 'Unknown'} ) : (
{video.uploader || video.channelTitle || 'Unknown'}
)}
{formatViews(video.view_count ?? 0)} views • {relativeTime}
); } export default memo(VideoCard);