'use client'; import { useState, useEffect } from 'react'; import Link from 'next/link'; import Dropdown from '@/components/Dropdown'; type Stream = { id: number; name: string; obs_source_name: string; url: string; }; type ScreenType = 'large' | 'left' | 'right' | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight'; export default function Home() { const [streams, setStreams] = useState([]); const [activeSources, setActiveSources] = useState>({ large: null, left: null, right: null, topLeft: null, topRight: null, bottomLeft: null, bottomRight: null, }); const [isLoading, setIsLoading] = useState(true); const [openDropdown, setOpenDropdown] = useState(null); useEffect(() => { const fetchData = async () => { try { // Fetch streams and active sources in parallel const [streamsRes, activeRes] = await Promise.all([ fetch('/api/streams'), fetch('/api/getActive') ]); const [streamsData, activeData] = await Promise.all([ streamsRes.json(), activeRes.json() ]); setStreams(streamsData); setActiveSources(activeData); } catch (error) { console.error('Error fetching data:', error); } finally { setIsLoading(false); } }; fetchData(); }, []); const handleSetActive = async (screen: ScreenType, id: number | null) => { const selectedStream = streams.find((stream) => stream.id === id); // Update local state immediately setActiveSources((prev) => ({ ...prev, [screen]: selectedStream?.obs_source_name || null, })); // Update backend if (id) { try { const response = await fetch('/api/setActive', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ screen, id }), }); if (!response.ok) { throw new Error('Failed to set active stream'); } } catch (error) { console.error('Error setting active stream:', error); // Revert local state on error setActiveSources((prev) => ({ ...prev, [screen]: null, })); } } }; const handleToggleDropdown = (screen: string) => { setOpenDropdown((prev) => (prev === screen ? null : screen)); }; if (isLoading) { return (
Loading streams...
); } return (
{/* Title */}

Stream Control Center

Manage your OBS sources across multiple screen positions

{/* Main Screen */}

Primary Display

stream.obs_source_name === activeSources.large)?.id || null } onSelect={(id) => handleSetActive('large', id)} label="Select Primary Stream..." isOpen={openDropdown === 'large'} onToggle={() => handleToggleDropdown('large')} />
{/* Side Displays */}

Side Displays

Left Display

stream.obs_source_name === activeSources.left)?.id || null } onSelect={(id) => handleSetActive('left', id)} label="Select Left Stream..." isOpen={openDropdown === 'left'} onToggle={() => handleToggleDropdown('left')} />

Right Display

stream.obs_source_name === activeSources.right)?.id || null } onSelect={(id) => handleSetActive('right', id)} label="Select Right Stream..." isOpen={openDropdown === 'right'} onToggle={() => handleToggleDropdown('right')} />
{/* Corner Displays */}

Corner Displays

{[ { screen: 'topLeft' as const, label: 'Top Left' }, { screen: 'topRight' as const, label: 'Top Right' }, { screen: 'bottomLeft' as const, label: 'Bottom Left' }, { screen: 'bottomRight' as const, label: 'Bottom Right' }, ].map(({ screen, label }) => (

{label}

stream.obs_source_name === activeSources[screen])?.id || null } onSelect={(id) => handleSetActive(screen, id)} label="Select Stream..." isOpen={openDropdown === screen} onToggle={() => handleToggleDropdown(screen)} />
))}
{/* Manage Streams Section */} {streams.length > 0 && (

Manage Streams

{streams.map((stream) => (

{stream.name}

{stream.obs_source_name}

✏️ Edit
))}
)}
); }