Files
tickte-system/src/components/workers/hochhaus/Hochhaus.jsx
T
ClaudeandClaude Sonnet 5.5 32f4f1d941 Hustler-Stufe: Keller und Bot-Leads erst ab Stufe 6 (Seite, Keller-Etage, Spur-Links, Abruf von /botleads)
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>
2026-10-22 10:36:52 +00:00

98 lines
4.4 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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>
)
}