import { useState, useEffect, useRef } from 'react'; import RadioTab from './plugins/radio/RadioTab'; import SoundboardTab from './plugins/soundboard/SoundboardTab'; interface PluginInfo { name: string; version: string; description: string; } // Plugin tab components const tabComponents: Record> = { radio: RadioTab, soundboard: SoundboardTab, }; export function registerTab(pluginName: string, component: React.FC<{ data: any }>) { tabComponents[pluginName] = component; } export default function App() { const [connected, setConnected] = useState(false); const [plugins, setPlugins] = useState([]); const [activeTab, setActiveTab] = useState(''); const [pluginData, setPluginData] = useState>({}); const eventSourceRef = useRef(null); // Fetch plugin list useEffect(() => { fetch('/api/plugins') .then(r => r.json()) .then((list: PluginInfo[]) => { setPlugins(list); if (list.length > 0 && !activeTab) setActiveTab(list[0].name); }) .catch(() => {}); }, []); // SSE connection useEffect(() => { let es: EventSource | null = null; let retryTimer: ReturnType; function connect() { es = new EventSource('/api/events'); eventSourceRef.current = es; es.onopen = () => setConnected(true); es.onmessage = (ev) => { try { const msg = JSON.parse(ev.data); if (msg.type === 'snapshot') { setPluginData(prev => ({ ...prev, ...msg })); } else if (msg.plugin) { setPluginData(prev => ({ ...prev, [msg.plugin]: { ...(prev[msg.plugin] || {}), ...msg }, })); } } catch {} }; es.onerror = () => { setConnected(false); es?.close(); retryTimer = setTimeout(connect, 3000); }; } connect(); return () => { es?.close(); clearTimeout(retryTimer); }; }, []); const TabComponent = activeTab ? tabComponents[activeTab] : null; const version = (import.meta as any).env?.VITE_APP_VERSION ?? '1.0.0'; // Tab icon mapping const tabIcons: Record = { radio: '\u{1F30D}', soundboard: '\u{1F3B5}', stats: '\u{1F4CA}', events: '\u{1F4C5}', games: '\u{1F3B2}', gamevote: '\u{1F3AE}', }; return (
{'\u{1F3AE}'} Gaming Hub
v{version}
{plugins.length === 0 ? (
{'\u{1F4E6}'}

Keine Plugins geladen

Plugins werden im Server konfiguriert.

) : TabComponent ? ( ) : (
{tabIcons[activeTab] ?? '\u{1F4E6}'}

{activeTab}

Plugin-UI wird geladen...

)}
); }