'use client' import { useEffect, useState, useRef, useCallback } from 'react' import { useParams, useRouter } from 'next/navigation' import { Button } from '@/components/ui/button' import { Maximize2, Minimize2, Monitor, Loader2, AlertCircle, } from 'lucide-react' import { ViewerToolbar } from '@/components/viewer/toolbar' import { ConnectionStatus } from '@/components/viewer/connection-status' interface Session { id: string machineId: string | null machineName: string | null startedAt: string endedAt: string | null connectionType: string | null } type ConnectionState = 'connecting' | 'connected' | 'disconnected' | 'error' export default function ViewerPage() { const params = useParams() const router = useRouter() const sessionId = params.sessionId as string const [session, setSession] = useState(null) const [connectionState, setConnectionState] = useState('connecting') const [isFullscreen, setIsFullscreen] = useState(false) const [showToolbar, setShowToolbar] = useState(true) const [quality, setQuality] = useState<'high' | 'medium' | 'low'>('high') const [isMuted, setIsMuted] = useState(true) const [error, setError] = useState(null) const containerRef = useRef(null) const canvasRef = useRef(null) useEffect(() => { fetch(`/api/sessions/${sessionId}`) .then((r) => r.json()) .then((data) => { if (!data.session) { setError('Session not found') setConnectionState('error') return } if (data.session.endedAt) { setError('This session has ended') setConnectionState('disconnected') return } setSession(data.session) simulateConnection() }) .catch(() => { setError('Failed to load session') setConnectionState('error') }) }, [sessionId]) const simulateConnection = () => { setConnectionState('connecting') setTimeout(() => { setConnectionState('connected') startDemoScreen() }, 2000) } const startDemoScreen = () => { const canvas = canvasRef.current if (!canvas) return const ctx = canvas.getContext('2d') if (!ctx) return canvas.width = 1920 canvas.height = 1080 const draw = () => { ctx.fillStyle = '#1e1e2e' ctx.fillRect(0, 0, canvas.width, canvas.height) const icons = [ { x: 50, y: 50, label: 'Documents' }, { x: 50, y: 150, label: 'Pictures' }, { x: 50, y: 250, label: 'Downloads' }, ] ctx.font = '14px system-ui' ctx.textAlign = 'center' icons.forEach((icon) => { ctx.fillStyle = '#313244' ctx.fillRect(icon.x, icon.y, 60, 60) ctx.fillStyle = '#cdd6f4' ctx.fillText(icon.label, icon.x + 30, icon.y + 80) }) ctx.fillStyle = '#181825' ctx.fillRect(0, canvas.height - 48, canvas.width, 48) ctx.fillStyle = '#89b4fa' ctx.fillRect(10, canvas.height - 40, 40, 32) const time = new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }) ctx.fillStyle = '#cdd6f4' ctx.font = '14px system-ui' ctx.textAlign = 'right' ctx.fillText(time, canvas.width - 20, canvas.height - 18) ctx.fillStyle = '#1e1e2e' ctx.fillRect(300, 100, 800, 500) ctx.strokeStyle = '#313244' ctx.lineWidth = 1 ctx.strokeRect(300, 100, 800, 500) ctx.fillStyle = '#181825' ctx.fillRect(300, 100, 800, 32) ctx.fillStyle = '#cdd6f4' ctx.font = '13px system-ui' ctx.textAlign = 'left' ctx.fillText('RemoteLink Agent - Connected', 312, 121) ctx.fillStyle = '#a6adc8' ctx.font = '16px system-ui' ctx.fillText('Remote session active', 320, 180) ctx.fillText('Connection: Secure (WebRTC)', 320, 210) ctx.fillText('Latency: ~45ms', 320, 240) ctx.fillStyle = '#a6e3a1' ctx.beginPath() ctx.arc(320, 280, 6, 0, Math.PI * 2) ctx.fill() ctx.fillStyle = '#cdd6f4' ctx.fillText('Connected to viewer', 335, 285) } draw() const interval = setInterval(draw, 1000) return () => clearInterval(interval) } const handleKeyDown = useCallback( (e: KeyboardEvent) => { if (connectionState !== 'connected') return console.log('[Viewer] Key pressed:', e.key) }, [connectionState] ) const handleMouseMove = useCallback( (e: React.MouseEvent) => { if (connectionState !== 'connected') return const canvas = canvasRef.current if (!canvas) return const rect = canvas.getBoundingClientRect() const _x = ((e.clientX - rect.left) * canvas.width) / rect.width const _y = ((e.clientY - rect.top) * canvas.height) / rect.height }, [connectionState] ) const handleMouseClick = useCallback( (e: React.MouseEvent) => { if (connectionState !== 'connected') return console.log('[Viewer] Mouse clicked:', e.button) }, [connectionState] ) const toggleFullscreen = async () => { if (!containerRef.current) return if (!document.fullscreenElement) { await containerRef.current.requestFullscreen() setIsFullscreen(true) } else { await document.exitFullscreen() setIsFullscreen(false) } } const endSession = async () => { if (session) { const duration = Math.floor((Date.now() - new Date(session.startedAt).getTime()) / 1000) await fetch(`/api/sessions/${session.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ endedAt: new Date().toISOString(), durationSeconds: duration }), }) } setConnectionState('disconnected') router.push('/dashboard/sessions') } useEffect(() => { document.addEventListener('keydown', handleKeyDown) return () => document.removeEventListener('keydown', handleKeyDown) }, [handleKeyDown]) useEffect(() => { if (isFullscreen && connectionState === 'connected') { const timer = setTimeout(() => setShowToolbar(false), 3000) return () => clearTimeout(timer) } }, [isFullscreen, connectionState, showToolbar]) if (error) { return (

{error}

) } return (
isFullscreen && setShowToolbar(true)} >
setIsMuted(!isMuted)} onDisconnect={endSession} onReconnect={simulateConnection} />
{connectionState === 'connecting' && (

Connecting to remote machine...

{session?.machineName || 'Establishing connection'}

)} { e.preventDefault(); handleMouseClick(e) }} /> {connectionState === 'disconnected' && (

Session Ended

The remote connection has been closed

)}
{connectionState === 'connected' && }
) }