import { useCallback, useEffect, useRef, useState } from 'react' import { useSearchParams } from 'react-router-dom' import BotLeadList from '../components/workers/BotLeadList' import Hochhaus from '../components/workers/hochhaus/Hochhaus' import PultList from '../components/workers/PultList' import { useAuth } from '../context/AuthContext' import { useWorkersFeed } from '../hooks/useWorkersFeed' import { HUSTLER_STUFE, tabErlaubt } from '../lib/hustlerStufe' import { indexWorkers, reduceEvents } from '../lib/workersEvents' import { workersApi } from '../lib/workersClient' import { pickTab } from '../lib/workersView' import '../styles/workers.css' import '../styles/hustler/schrift.css' import '../styles/hustler/hochhaus.css' import '../styles/hustler/keller.css' import '../styles/hustler/hustler-keller-ui.css' import '../styles/hustler/pult.css' import '../styles/hustler/hustler-pult-ui.css' import '../styles/hustler/hustler-ui.css' import '../styles/hustler/hustler-welt.css' import '../styles/hustler/hustler-kopf.css' import '../styles/hustler/hustler-detail.css' import '../styles/hustler/hustler-regie.css' // Bildschirme der Seite: das Hochhaus, das Pult (Freigabe von P3) und der Keller (Bot-Leads von P6). Eine Reiterleiste gibt es nicht mehr; // gewechselt wird im Haus (Etage Freigabe, Etage Keller) und über „◂ Hochhaus“ in Pult und Keller. // Stufen-Sperre (lib/hustlerStufe.js, HUSTLER_STUFE): der Keller ist ab Stufe 3 ein Bildschirm (begehbar), die Bot-Leads ruft er aber erst ab Stufe 6 ab; darunter zeigt // BotLeadList sein leeres Register und fragt /api/workers/botleads nie an. Unterhalb von Stufe 3 fallen ?tab=botleads (auch mit &bot=) und jeder andere unbekannte Wert // auf das Hochhaus zurück (pickTab nimmt den ersten Reiter), BotLeadList wird dann nie eingehängt. const WORKERS_TABS = [ { id: 'hochhaus', label: 'Hochhaus' }, { id: 'freigabe', label: 'Freigabe' }, { id: 'botleads', label: 'Bot-Leads' }, ] const api = workersApi // Seite „Hustler“ (Dateiname bleibt WorkersPage): Tab-Titel, Bildschirmwahl über ?tab= und der gewählte Bildschirm in voller Höhe. // ?tab=botleads&bot= (Link aus dem Ereignisstrom) zeigt einen einzelnen Bot-Lead; ein Wechsel per setParams lässt bot weg. // Auth und Dienst-API kommen von hier. Der Feed (Zustand alle 15 s, Ereignisse alle 5 s) läuft genau einmal pro Seite, egal welcher // Bildschirm offen ist; die Hustler-Tabelle (indexWorkers beim Schnappschuss, reduceEvents bei Ereignissen) gehört ebenfalls hierher. // Ereignisse gehen zusätzlich an die Regie, die nur das Hochhaus über regieRef einhängt. // Die Tabelle liegt nie einen Render hinter dem Schnappschuss zurück (sonst stünden alle Figuren kurz auf „Leerlauf“): sie merkt sich, aus welchem Schnappschuss sie // entstand, und wird im Render neu aus `state` gebaut, sobald der Schnappschuss ein anderer ist. Pause (state.paused) geht an alle drei Bildschirme. // Das Hochhaus bekommt vonTab (der Bildschirm, von dem man zurückkommt) und fokussiert dann die Etage, über die man gegangen war. // stufe (Standard HUSTLER_STUFE) ist nur für Tests ein Parameter; die App rendert die Seite ohne und liest die Stufe aus dem Bau. export default function WorkersPage({ stufe = HUSTLER_STUFE }) { const { isAdmin, user } = useAuth() const [params, setParams] = useSearchParams() const active = pickTab(WORKERS_TABS.filter((t) => tabErlaubt(t.id, stufe)), params.get('tab')) const bot = params.get('bot') ?? '' const [tabelle, setTabelle] = useState({ von: null, workers: {} }) // Hustler-Tabelle samt dem Schnappschuss, aus dem sie entstand const [verlauf, setVerlauf] = useState({ aktuell: active.id, vorher: null }) // aktueller und vorheriger Bildschirm const regieRef = useRef(null) // Tab-Titel nur solange die Seite offen ist; beim Verlassen kommt der vorige Titel zurück useEffect(() => { const previous = document.title document.title = 'Hustler' return () => { document.title = previous } }, []) // Neue Ereignisse: Tabelle fortschreiben und der Regie vorspielen (die Regie kennt den Rückstau selbst) const onEvents = useCallback((events) => { setTabelle((t) => ({ von: t.von, workers: reduceEvents(t.workers, events) })) if (regieRef.current) regieRef.current.push(events) }, []) const { state, error, loaded, refresh } = useWorkersFeed(api, { onEvents }) // Neuer Schnappschuss: Tabelle sofort neu bauen (nicht erst nach einem Effekt) und merken const veraltet = Boolean(state) && tabelle.von !== state const workers = veraltet ? indexWorkers(state) : tabelle.workers if (veraltet) setTabelle({ von: state, workers }) // Bildschirmwechsel: der bisherige wird zum vorherigen const gewechselt = verlauf.aktuell !== active.id const vonTab = gewechselt ? verlauf.aktuell : verlauf.vorher if (gewechselt) setVerlauf({ aktuell: active.id, vorher: vonTab }) const paused = state?.paused === true return (
{active.id === 'hochhaus' && ( { if (tabErlaubt(tab, stufe)) setParams({ tab }) }} /> )} {active.id === 'freigabe' && ( setParams({ tab: 'hochhaus' })} /> )} {active.id === 'botleads' && ( setParams({ tab: 'botleads' })} kpis={state?.kpis} workers={workers} paused={paused} onBack={() => setParams({ tab: 'hochhaus' })} /> )}
) }