Die Stufen-Sperre trennt jetzt zwei Dinge: KELLER_BEGEHBAR_AB = 3 (Keller-Etage als Link, ?tab=botleads gueltig, Spur-Links in den Keller) und BOTLEADS_AB = 6 (Abruf von GET /botleads). kellerOffen/STUFE_KELLER entfallen, dafuer kellerBegehbar() und botleadsAbrufbar(). workersApi.botleads bleibt unter Stufe 6 hart gesperrt, der Text heisst nun BOTLEADS_GESPERRT_TEXT. Die Keller-Ansicht selbst (leeres Register ohne Abruf) folgt im naechsten Commit. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
120 lines
5.9 KiB
React
120 lines
5.9 KiB
React
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=<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.
|
|
// 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 (
|
|
<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}
|
|
vonTab={vonTab}
|
|
stufe={stufe}
|
|
onOpen={(tab) => { if (tabErlaubt(tab, stufe)) setParams({ tab }) }}
|
|
/>
|
|
)}
|
|
{active.id === 'freigabe' && (
|
|
<PultList
|
|
api={api}
|
|
me={{ id: user?.$id, name: user?.name }}
|
|
kpis={state?.kpis}
|
|
workers={workers}
|
|
paused={paused}
|
|
stufe={stufe}
|
|
onBack={() => setParams({ tab: 'hochhaus' })}
|
|
/>
|
|
)}
|
|
{active.id === 'botleads' && (
|
|
<BotLeadList
|
|
api={api}
|
|
stufe={stufe}
|
|
bot={bot}
|
|
onClearBot={() => setParams({ tab: 'botleads' })}
|
|
kpis={state?.kpis}
|
|
workers={workers}
|
|
paused={paused}
|
|
onBack={() => setParams({ tab: 'hochhaus' })}
|
|
/>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|