"use client"; import React, { useState, useRef, useEffect, useCallback } from "react"; import { motion, AnimatePresence } from "motion/react"; import { Play, Pause, RotateCcw, RotateCw, Volume2, VolumeX, Maximize, Minimize, Download, Share2, X, Check, ChevronDown, ChevronUp, Sparkles, Loader2 } from "lucide-react"; interface VideoModalPlayerProps { isOpen: boolean; onClose: () => void; video: { id?: string; title?: string; doctor?: string; videoUrl?: string; thumbnail?: string; description?: string; quote?: string; } | null; } const PLAYBACK_RATES = [0.5, 1, 1.25, 1.5, 1.75, 2, 2.5]; export default function VideoModalPlayer({ isOpen, onClose, video }: VideoModalPlayerProps) { const videoRef = useRef(null); const containerRef = useRef(null); const controlsTimeoutRef = useRef | null>(null); const [isPlaying, setIsPlaying] = useState(false); const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); const [volume, setVolume] = useState(1); const [isMuted, setIsMuted] = useState(false); const [playbackRate, setPlaybackRate] = useState(1); const [showRateMenu, setShowRateMenu] = useState(false); const [isFullscreen, setIsFullscreen] = useState(false); const [isBuffering, setIsBuffering] = useState(true); const [showControls, setShowControls] = useState(true); const [isExpandedDesc, setIsExpandedDesc] = useState(false); const [isCopied, setIsCopied] = useState(false); // Reset states on open/close useEffect(() => { if (isOpen) { setIsPlaying(true); setShowControls(true); setIsExpandedDesc(false); setShowRateMenu(false); } else { setIsPlaying(false); setCurrentTime(0); } }, [isOpen, video]); // Handle auto-hide timer for controls const resetControlsTimer = useCallback(() => { setShowControls(true); if (controlsTimeoutRef.current) { clearTimeout(controlsTimeoutRef.current); } // If video is playing, auto-hide after 3.5s; if paused, stay visible if (isPlaying) { controlsTimeoutRef.current = setTimeout(() => { if (!showRateMenu) { setShowControls(false); } }, 3500); } }, [isPlaying, showRateMenu]); useEffect(() => { if (!isPlaying) { setShowControls(true); if (controlsTimeoutRef.current) clearTimeout(controlsTimeoutRef.current); } else { resetControlsTimer(); } return () => { if (controlsTimeoutRef.current) clearTimeout(controlsTimeoutRef.current); }; }, [isPlaying, resetControlsTimer]); const togglePlay = () => { if (!videoRef.current) return; if (videoRef.current.paused) { videoRef.current.play().catch(console.error); setIsPlaying(true); } else { videoRef.current.pause(); setIsPlaying(false); setShowControls(true); } }; const handleSeek = (e: React.ChangeEvent) => { const time = Number(e.target.value); if (videoRef.current) { videoRef.current.currentTime = time; setCurrentTime(time); } }; const skipTime = (seconds: number) => { if (videoRef.current) { videoRef.current.currentTime = Math.max(0, Math.min(videoRef.current.duration || 0, videoRef.current.currentTime + seconds)); resetControlsTimer(); } }; const handleRateChange = (rate: number) => { if (videoRef.current) { videoRef.current.playbackRate = rate; setPlaybackRate(rate); setShowRateMenu(false); resetControlsTimer(); } }; const toggleMute = () => { if (videoRef.current) { videoRef.current.muted = !isMuted; setIsMuted(!isMuted); } }; const handleVolumeChange = (e: React.ChangeEvent) => { const val = Number(e.target.value); setVolume(val); if (videoRef.current) { videoRef.current.volume = val; if (val === 0) { setIsMuted(true); videoRef.current.muted = true; } else { setIsMuted(false); videoRef.current.muted = false; } } }; const toggleFullscreen = async () => { if (!containerRef.current) return; try { if (!document.fullscreenElement) { await containerRef.current.requestFullscreen(); setIsFullscreen(true); } else { await document.exitFullscreen(); setIsFullscreen(false); } } catch (err) { console.error('Fullscreen toggle failed:', err); } }; const handleShare = async () => { const shareUrl = window.location.href; if (navigator.share) { try { await navigator.share({ title: video?.title || 'ویدئوی آموزشی کنینا', text: video?.description || '', url: shareUrl }); } catch { // Fallback to clipboard } } else { try { await navigator.clipboard.writeText(shareUrl); setIsCopied(true); setTimeout(() => setIsCopied(false), 2500); } catch (err) { console.error('Copy failed:', err); } } }; const handleDownload = () => { if (!video?.videoUrl) return; const a = document.createElement('a'); a.href = video.videoUrl; a.download = `${video.title || 'canina-video'}.mp4`; a.target = '_blank'; a.rel = 'noopener noreferrer'; document.body.appendChild(a); a.click(); document.body.removeChild(a); }; const formatTime = (secs: number) => { if (isNaN(secs) || secs < 0) return "00:00"; const mins = Math.floor(secs / 60); const remainingSecs = Math.floor(secs % 60); return `${mins.toString().padStart(2, "0")}:${remainingSecs.toString().padStart(2, "0")}`; }; if (!isOpen || !video) return null; const isIframe = video.videoUrl?.includes("
{/* Backdrop */} {/* Modal Window */} {/* Iframe Support (Aparat / Youtube) */} {isIframe ? (
) : ( <> {/* Native Video Element */}
{/* Top Header Overlay */}

{video.title}

{video.doctor || "کادر علمی کنینا"}

{/* Share button */} {/* Download button */} {/* Close button */}
{/* Bottom Custom Controls Bar */}
e.stopPropagation()} > {/* Expandable Description Box if available */} {video.description && (

{video.description}

{video.description.length > 80 && ( )}
)} {/* Progress / Seek Bar */}
{formatTime(currentTime)}
{formatTime(duration)}
{/* Action Buttons Row */}
{/* Left Controls (Playback & Jumps) */}
{/* Play/Pause */} {/* -10s */} {/* +10s */} {/* Volume slider */}
{/* Right Controls (Speed Menu & Fullscreen) */}
{/* Playback Rate Popup Menu */}
{showRateMenu && (
{PLAYBACK_RATES.map((rate) => ( ))}
)}
{/* Fullscreen Button */}
)}
); }