import React, { useState, useEffect } from 'react'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Users, Link, Copy, CheckCircle, Send } from 'lucide-react'; import { useToast } from '@/hooks/use-toast'; interface WatchTogetherProps { title: string; currentTime: number; duration: number; onSeek?: (time: number) => void; } interface Message { id: string; name: string; text: string; timestamp: number; type: 'chat' | 'system' | 'timestamp'; } const WatchTogether: React.FC = ({ title, currentTime, duration, onSeek }) => { const [isOpen, setIsOpen] = useState(false); const [roomId, setRoomId] = useState(''); const [userName, setUserName] = useState(''); const [message, setMessage] = useState(''); const [messages, setMessages] = useState([]); const [userCount, setUserCount] = useState(1); const [isHost, setIsHost] = useState(true); const [linkCopied, setLinkCopied] = useState(false); const { toast } = useToast(); // Generate room ID on mount useEffect(() => { const id = `room-${Math.random().toString(36).substring(2, 8)}`; setRoomId(id); // If no username set, use a default if (!userName) { setUserName(`User${Math.floor(Math.random() * 10000)}`); } // Initial system message addSystemMessage(`Watch Party started for "${title}"`); }, [title]); // Function to add system message const addSystemMessage = (text: string) => { const newMessage: Message = { id: `sys-${Date.now()}`, name: 'System', text, timestamp: Date.now(), type: 'system' }; setMessages(prev => [...prev, newMessage]); }; // Function to add user message const addUserMessage = () => { if (!message.trim()) return; // If message starts with '/seek ', treat as seek command if (message.startsWith('/seek ')) { const seekTime = parseInt(message.replace('/seek ', '')); if (!isNaN(seekTime) && seekTime >= 0 && seekTime <= duration) { handleSeek(seekTime); setMessage(''); return; } } // Regular message const newMessage: Message = { id: `msg-${Date.now()}`, name: userName, text: message, timestamp: Date.now(), type: 'chat' }; setMessages(prev => [...prev, newMessage]); setMessage(''); }; // Function to handle seeking const handleSeek = (time: number) => { if (onSeek) { onSeek(time); // Add timestamp message const newMessage: Message = { id: `time-${Date.now()}`, name: userName, text: `Seeked to ${formatTime(time)}`, timestamp: Date.now(), type: 'timestamp' }; setMessages(prev => [...prev, newMessage]); } }; // Function to share current timestamp const shareCurrentTime = () => { const newMessage: Message = { id: `time-${Date.now()}`, name: userName, text: `Current position: ${formatTime(currentTime)}`, timestamp: Date.now(), type: 'timestamp' }; setMessages(prev => [...prev, newMessage]); }; // Function to format time const formatTime = (timeInSeconds: number) => { const minutes = Math.floor(timeInSeconds / 60); const seconds = Math.floor(timeInSeconds % 60); return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`; }; // Function to copy invite link const copyInviteLink = () => { const inviteLink = `${window.location.href}?room=${roomId}&host=false`; navigator.clipboard.writeText(inviteLink); setLinkCopied(true); toast({ title: "Link Copied", description: "Share this link with friends to watch together", }); setTimeout(() => setLinkCopied(false), 2000); }; // Simulate someone joining after a delay useEffect(() => { if (isOpen && isHost) { const timer = setTimeout(() => { setUserCount(2); addSystemMessage("Alice has joined the watch party"); }, 5000); return () => clearTimeout(timer); } }, [isOpen, isHost]); // Add mock message after some delays useEffect(() => { if (isOpen && userCount > 1) { const timer1 = setTimeout(() => { setMessages(prev => [ ...prev, { id: `msg-alice-1`, name: "Alice", text: "Hey, thanks for inviting me!", timestamp: Date.now(), type: 'chat' } ]); }, 3000); const timer2 = setTimeout(() => { setMessages(prev => [ ...prev, { id: `msg-alice-2`, name: "Alice", text: "I love this part coming up!", timestamp: Date.now(), type: 'chat' } ]); }, 15000); return () => { clearTimeout(timer1); clearTimeout(timer2); }; } }, [isOpen, userCount]); return ( Watch Together
{userCount} {userCount === 1 ? 'viewer' : 'viewers'}
{/* Chat messages */}
{messages.map((msg) => (
{msg.type === 'system' ? (
{msg.text}
) : msg.type === 'timestamp' ? (
{ const timeMatch = msg.text.match(/(\d+):(\d+)/); if (timeMatch) { const minutes = parseInt(timeMatch[1]); const seconds = parseInt(timeMatch[2]); const totalSeconds = minutes * 60 + seconds; onSeek?.(totalSeconds); } }} > {msg.text}
) : ( <> {msg.name === userName ? 'You' : msg.name}

{msg.text}

)}
))}
{/* Share current timestamp button */} {/* Chat input */}
setMessage(e.target.value)} className="bg-gray-800 border-gray-700 text-white" onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); addUserMessage(); } }} />

Pro tip: Type '/seek 10' to jump to 10 seconds, or click on any shared timestamp to seek.

); }; export default WatchTogether;