Hustler-Pixelwelt T3: Seite hält den Feed, Bildschirme Hochhaus/Pult/Keller, Vollhöhen-Rahmen

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-22 08:02:44 +00:00
1 parent 8bd365b1fc
commit d8912ee363
5 files changed
+527 -23

No files matched your search

+63 -14
View File
@@ -1,15 +1,22 @@
import { useEffect } from 'react'
import { useCallback, useEffect, useRef, useState } from 'react'
import { useSearchParams } from 'react-router-dom'
import { PageHeader, Tabs } from '../components/ui'
import BotLeadList from '../components/workers/BotLeadList'
import Hochhaus from '../components/workers/hochhaus/Hochhaus'
import PultList from '../components/workers/PultList'
import WorkersBoard from '../components/workers/WorkersBoard'
import { useAuth } from '../context/AuthContext'
import { useWorkersFeed } from '../hooks/useWorkersFeed'
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/pult.css'
import '../styles/hustler/hustler-ui.css'
// Reiter der Seite (Hochhaus, Freigabe von P3, Bot-Leads von P6); die Reiterleiste erscheint erst ab zwei Reitern.
// 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.
const WORKERS_TABS = [
{ id: 'hochhaus', label: 'Hochhaus' },
{ id: 'freigabe', label: 'Freigabe' },
@@ -18,14 +25,18 @@ const WORKERS_TABS = [
const api = workersApi
// Seite „Hustler“ (Dateiname bleibt WorkersPage): Titel, Reiterwahl über ?tab= und der Inhalt des gewählten Reiters.
// ?tab=botleads&bot=<Id> (Link aus dem Ereignisstrom) zeigt einen einzelnen Bot-Lead; ein Reiterwechsel lässt bot weg.
// Auth und Dienst-API kommen von hier; das Board selbst kennt weder Anmeldung noch Appwrite.
// Seite „Hustler“ (Dateiname bleibt WorkersPage): Tab-Titel, Bildschirmwahl über ?tab= und der gewählte Bildschirm in voller Höhe.
// ?tab=botleads&bot=<Id> (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.
export default function WorkersPage() {
const { isAdmin, user } = useAuth()
const [params, setParams] = useSearchParams()
const active = pickTab(WORKERS_TABS, params.get('tab'))
const bot = params.get('bot') ?? ''
const [workers, setWorkers] = useState({})
const regieRef = useRef(null)
// Tab-Titel nur solange die Seite offen ist; beim Verlassen kommt der vorige Titel zurück
useEffect(() => {
@@ -34,15 +45,53 @@ export default function WorkersPage() {
return () => { document.title = previous }
}, [])
// Neue Ereignisse: Tabelle fortschreiben und der Regie vorspielen (die Regie kennt den Rückstau selbst)
const onEvents = useCallback((events) => {
setWorkers((w) => reduceEvents(w, events))
if (regieRef.current) regieRef.current.push(events)
}, [])
const { state, error, loaded, refresh } = useWorkersFeed(api, { onEvents })
useEffect(() => {
if (state) setWorkers(indexWorkers(state))
}, [state])
return (
<div className="page wk-page">
<PageHeader title="Hustler" subtitle="Die Nachtschicht deiner Claude-Armee" />
{WORKERS_TABS.length > 1 && (
<Tabs tabs={WORKERS_TABS} active={active.id} onChange={(id) => setParams({ tab: id })} />
<div className="hk-seite" data-tab={active.id}>
{active.id === 'hochhaus' && (
<Hochhaus
api={api}
isAdmin={isAdmin}
feed={{ state, error, loaded, refresh }}
workers={workers}
regieRef={regieRef}
onOpen={(tab) => setParams({ tab })}
/>
)}
{/* Pult und Keller stecken bis T9/T10 noch in der alten hellen Hülle (.page.wk-page); hustler-ui.css gibt ihnen dafür normale Höhe */}
{active.id === 'freigabe' && (
<div className="page wk-page">
<PultList
api={api}
me={{ id: user?.$id, name: user?.name }}
kpis={state?.kpis}
workers={workers}
onBack={() => setParams({ tab: 'hochhaus' })}
/>
</div>
)}
{active.id === 'botleads' && (
<div className="page wk-page">
<BotLeadList
api={api}
bot={bot}
onClearBot={() => setParams({ tab: 'botleads' })}
kpis={state?.kpis}
workers={workers}
onBack={() => setParams({ tab: 'hochhaus' })}
/>
</div>
)}
{active.id === 'hochhaus' && <WorkersBoard api={api} isAdmin={isAdmin} />}
{active.id === 'freigabe' && <PultList api={api} me={{ id: user?.$id, name: user?.name }} />}
{active.id === 'botleads' && <BotLeadList api={api} bot={bot} onClearBot={() => setParams({ tab: 'botleads' })} />}
</div>
)
}