63 lines
2.5 KiB
React
63 lines
2.5 KiB
React
import { workerStatusLabel } from '../../lib/workersView'
|
|
import { FLOORS, FLOOR_TITLES, ROLES } from '../../lib/workersRoster'
|
|
|
|
// Statuspunkt je Dienst-Status (Wörterbuch statt zusammengesetzter Klasse: der CSS-Test in workers.css findet die Namen)
|
|
const DOT = {
|
|
arbeitet: 'wk-dot-arbeitet',
|
|
wartet: 'wk-dot-wartet',
|
|
leerlauf: 'wk-dot-leerlauf',
|
|
grau: 'wk-dot-grau',
|
|
fehler: 'wk-dot-fehler',
|
|
}
|
|
|
|
// Etagen von oben nach unten mit ihren Workern; Etagen ohne Worker (Pult, Tresor) entfallen
|
|
const GROUPS = FLOORS.map((floor) => ({ floor, roles: ROLES.filter((r) => r.floor === floor) })).filter((g) => g.roles.length > 0)
|
|
|
|
const isRecord = (v) => v !== null && typeof v === 'object' && !Array.isArray(v)
|
|
|
|
// workers = Tabelle nach workerId (indexWorkers/reduceEvents) oder die Liste aus state.workers; unbekannt -> null
|
|
function entryOf(workers, workerId) {
|
|
if (Array.isArray(workers)) return workers.find((w) => isRecord(w) && w.workerId === workerId) ?? null
|
|
return isRecord(workers) && Object.hasOwn(workers, workerId) && isRecord(workers[workerId]) ? workers[workerId] : null
|
|
}
|
|
|
|
// Status aus dem Eintrag; ein nicht angeschlossener Worker ist grau (wie in indexWorkers)
|
|
function statusOf(entry) {
|
|
if (!entry) return ''
|
|
return entry.connected === false ? 'grau' : entry.status
|
|
}
|
|
|
|
// Alle Worker je Etage als Knopfliste. Ein Klick meldet die workerId über onSelect, der gewählte Knopf ist aria-pressed.
|
|
export default function WorkerList({ workers, selectedId, onSelect }) {
|
|
return (
|
|
<div className="wk-list">
|
|
{GROUPS.map((group) => (
|
|
<section key={group.floor}>
|
|
<h3 className="wk-list-floor">{FLOOR_TITLES[group.floor]}</h3>
|
|
<ul>
|
|
{group.roles.map((role) => {
|
|
const status = statusOf(entryOf(workers, role.workerId))
|
|
const label = workerStatusLabel(status)
|
|
return (
|
|
<li key={role.workerId}>
|
|
<button
|
|
type="button"
|
|
data-wk-worker={role.workerId}
|
|
aria-pressed={selectedId === role.workerId}
|
|
aria-label={`${role.name}, ${label}`}
|
|
onClick={() => { if (onSelect) onSelect(role.workerId) }}
|
|
>
|
|
<span className={Object.hasOwn(DOT, status) ? `wk-dot ${DOT[status]}` : 'wk-dot'} aria-hidden="true" />
|
|
<span>{role.name}</span>
|
|
<span>{label}</span>
|
|
</button>
|
|
</li>
|
|
)
|
|
})}
|
|
</ul>
|
|
</section>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|