'use client'; import { useEffect, useState, useRef } from 'react'; import type { ChatMessage } from '@shared/chat'; const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL ?? 'http://localhost:4100'; type SelectionPayload = { message: ChatMessage | null; }; export default function OverlayPage() { const [message, setMessage] = useState(null); const [connected, setConnected] = useState(false); const [fadingOut, setFadingOut] = useState(false); const connectionRef = useRef(null); useEffect(() => { // Prevent multiple connections if (connectionRef.current) { console.log('[Overlay] SSE already connected'); return; } console.log('[Overlay] Creating SSE connection'); const source = new EventSource(`${BACKEND_URL}/overlay/stream`); connectionRef.current = source; const onSelection = (event: MessageEvent) => { try { const payload: SelectionPayload = JSON.parse(event.data); setMessage((prevMessage) => { if (payload.message === null && prevMessage !== null) { // Trigger fade out animation before clearing setFadingOut(true); setTimeout(() => { setMessage(null); setFadingOut(false); }, 300); return prevMessage; // Keep current message during fade } else { setFadingOut(false); return payload.message; } }); setConnected(true); } catch (error) { console.error('overlay: failed to parse payload', error); } }; source.addEventListener('selection', onSelection as EventListener); source.addEventListener('heartbeat', () => setConnected(true)); source.onerror = () => setConnected(false); return () => { console.log('[Overlay] Closing SSE connection'); source.removeEventListener('selection', onSelection as EventListener); source.close(); connectionRef.current = null; }; }, []); // Empty dependency array - only connect once return (
{message ? (
{message.authorPhoto && ( {message.author} )}
{message.author} {message.badges && message.badges.map((badge, i) => ( {badge.type === 'moderator' && '🛡️'} {badge.type === 'member' && '⭐'} {badge.type === 'verified' && '✓'} ))}
{message.superChat && (
💰 {message.superChat.currency}{message.superChat.amount}
)} {(message.membershipGift || message.membershipGiftPurchase) && (
{message.membershipGiftPurchase && message.giftCount ? `🎁 Gifted ${message.giftCount} Membership${message.giftCount > 1 ? 's' : ''}!` : message.membershipGiftPurchase ? '🎁 Gift Purchase' : '🎁 New Member!'}
)} {(!message.superChat && !message.membershipGift && !message.membershipGiftPurchase) && message.text && (

{message.text}

)}
) : (
{connected ? 'Awaiting selection…' : 'Reconnecting…'}
)}
); }