WorkersPage: ?tab=botleads (auch mit &bot=) und unbekannte Werte fallen unterhalb von Stufe 6 auf das Hochhaus zurück, BotLeadList wird nie eingehängt; die Weiterleitungen /leads und /workers bleiben. HochhausWelt: die Keller-Etage ist dann ein Knopf wie jede andere (zoomt heran) statt eines Links; Arne bleibt klickbar, die Zahl Bot-Leads in der Kopfzeile bleibt Text. HustlerDialog: Spur-Links in den Keller bleiben Text. workersApi.botleads ruft unterhalb von Stufe 6 nichts ab (kein JWT, keine Anfrage), sondern liefert 404 mit deutschem Satz. Bestehende Keller-Tests laufen ausdrücklich auf Stufe 6; neue Tests prüfen Stufe 1, 3 und 5 (gesperrt) und 6 bis 9 (offen). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
98 lines
4.4 KiB
React
98 lines
4.4 KiB
React
import { useEffect, useRef, useState } from 'react'
|
||
import { HUSTLER_STUFE } from '../../../lib/hustlerStufe'
|
||
import HochhausKopf from './HochhausKopf'
|
||
import HochhausWelt from './HochhausWelt'
|
||
import HustlerDialog from './HustlerDialog'
|
||
import RegieEbene from './RegieEbene'
|
||
|
||
// Von welchem Bildschirm man zurückkommt -> Etage, über die man gegangen war (Freigabe-Pult über die Etage „freigabe“, Keller über „keller“)
|
||
const ETAGE_NACH_TAB = Object.freeze({ freigabe: 'freigabe', botleads: 'keller' })
|
||
|
||
// Überschrift der Seite, nur für Screenreader (Pult und Keller haben ihre eigene sichtbare Überschrift)
|
||
function Ueberschrift() {
|
||
return <h1 className="hk-nur-sr">Hustler – Hochhaus</h1>
|
||
}
|
||
|
||
// Bildschirm „Hochhaus“: Spielwelt mit Regie-Ebene (T5, T8), Kopfzeile (T6) und Detailansicht eines Hustlers (T7). Zustände wie bisher im WorkersBoard.
|
||
// Reine Darstellung ohne Auth-Bezug: isAdmin, der Feed (feed = { state, error, loaded, refresh }), die Hustler-Tabelle (workers), die Regie-Anbindung
|
||
// (regieRef, die Seite ruft regieRef.current.push(events) bei neuen Ereignissen), der Bildschirmwechsel (onOpen(tab)) und vonTab (der Bildschirm, von dem man
|
||
// zurückkommt: 'freigabe' | 'botleads' | null) kommen von der Seite. Beim Zurückkommen bekommt die Etage, über die man gegangen war, den Fokus (M2).
|
||
// Die Kopfzeile steht im DOM vor der Welt, damit die Tab-Reihenfolge oben beginnt (M7); über der Welt liegt sie per z-index.
|
||
// stufe (Standard HUSTLER_STUFE, hustlerStufe.js) geht an die Welt (Keller-Etage als Link nur ab Stufe 6) und an die Detailansicht (Spur-Links in den Keller nur ab Stufe 6).
|
||
// Kein CSS-Import und keine Bilder: die Stile hängt WorkersPage ein (Regeln dieser Datei in styles/hustler/hustler-ui.css).
|
||
export default function Hochhaus({ api, isAdmin, feed, workers, regieRef, onOpen, vonTab = null, stufe = HUSTLER_STUFE }) {
|
||
const wurzelRef = useRef(null)
|
||
const weltRef = useRef(null)
|
||
const [auswahl, setAuswahl] = useState(null) // workerId der offenen Detailansicht (null = keine)
|
||
const ready = feed.loaded && Boolean(feed.state)
|
||
|
||
// Rückweg aus Pult oder Keller: Fokus auf die Etage, über die man ging (erst wenn die Welt steht; die Kamera holt sie bei Tastaturfokus ins Bild)
|
||
useEffect(() => {
|
||
if (!ready || !vonTab || !Object.hasOwn(ETAGE_NACH_TAB, vonTab)) return
|
||
const wurzel = wurzelRef.current
|
||
if (!wurzel || typeof wurzel.querySelector !== 'function') return
|
||
const etage = wurzel.querySelector(`[data-hk-etage="${ETAGE_NACH_TAB[vonTab]}"]`)
|
||
if (etage && typeof etage.focus === 'function') etage.focus({ preventScroll: true })
|
||
}, [ready, vonTab])
|
||
|
||
// Dienst noch nie erreicht: Pixel-Leerzustand mit Fehlertext und „Neu laden“
|
||
if (!ready && feed.error) {
|
||
return (
|
||
<div className="hk-hochhaus" ref={wurzelRef}>
|
||
<Ueberschrift />
|
||
<div className="hk-leer">
|
||
<strong className="hk-leer-titel">Der Hustler-Dienst ist noch nicht erreichbar</strong>
|
||
<p className="hk-leer-text">{feed.error}</p>
|
||
<button type="button" className="hk-knopf" onClick={() => feed.refresh()}>Neu laden</button>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
if (!ready) {
|
||
return (
|
||
<div className="hk-hochhaus" ref={wurzelRef}>
|
||
<Ueberschrift />
|
||
<div className="hk-laden" role="status">Wird geladen …</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
// Die Regie-Ebene liegt in der skalierten Bühne (Weltkoordinaten); ihr Handle ist regieRef der Seite, die neue Ereignisse hineinreicht.
|
||
// Solange die Detailansicht offen ist, ruhen Rad, Ziehen und Tasten der Kamera (gesperrt).
|
||
return (
|
||
<div className="hk-hochhaus" ref={wurzelRef}>
|
||
<Ueberschrift />
|
||
<HochhausKopf
|
||
api={api}
|
||
isAdmin={isAdmin}
|
||
state={feed.state}
|
||
error={feed.error}
|
||
refresh={feed.refresh}
|
||
onGanz={() => { if (weltRef.current) weltRef.current.ganz() }}
|
||
/>
|
||
<HochhausWelt
|
||
ref={weltRef}
|
||
state={feed.state}
|
||
workers={workers}
|
||
onZeige={setAuswahl}
|
||
onOpen={onOpen}
|
||
gesperrt={auswahl !== null}
|
||
stufe={stufe}
|
||
>
|
||
<RegieEbene ref={regieRef} />
|
||
</HochhausWelt>
|
||
{auswahl !== null && (
|
||
<HustlerDialog
|
||
api={api}
|
||
workerId={auswahl}
|
||
workers={workers}
|
||
paused={feed.state?.paused === true}
|
||
stufe={stufe}
|
||
onClose={() => setAuswahl(null)}
|
||
onWechsel={setAuswahl}
|
||
/>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|