fix: Zentrale-Seite zeigt den Zustand und den Weg zurueck

Zwei Handhabungsprobleme, die zusammengehoeren.

Auf /zentrale gab es ueberhaupt keinen Knopf zum Zurueckgeben - den fand
man nur ueber den Direktlink, den man nach einer Uebernahme in der Hand
hatte. Wer stattdessen /zentrale aufrief, konnte nur weiter uebernehmen
und sah nicht, dass erst zurueckgesetzt werden muss.

Ausserdem rendern die POST-Endpunkte ihr Ergebnis direkt. Man blieb also
auf /api/zentrale/uebernehmen stehen: eine Adresse, die beim Neuladen die
Aktion wiederholt und den Zustand nicht widerspiegelt.

Neu:

- Zwei Schritte. /zentrale fragt nur die Durchwahl ab und leitet auf
  /zentrale/{durchwahl} um. Diese Zustandsseite ist die Adresse fuer den
  Alltag, als Lesezeichen oder QR-Code, und ist gefahrlos neu ladbar.
- Die Knoepfe richten sich nach der Lage: frei -> besetzen, fremd besetzt
  -> uebernehmen samt Hinweis was mit dieser Person passiert, selbst
  besetzt -> zurueck auf mein Tuerschild, eigener Stammplatz -> kein
  Knopf, nur der Hinweis dass nichts zu tun ist.
- Alle Aktionen antworten mit POST/Redirect/GET auf die Zustandsseite und
  uebergeben nur einen kurzen Code fuer die Bestaetigung. Die Einzelheiten
  - wer sitzt drauf, wer wartet, wer blockiert den Heimatplatz - leitet
  die Seite bei jedem Aufruf frisch aus dem echten Zustand ab.
- Die allgemeine Seite nennt den aktuellen Besetzer und, falls vorhanden,
  wer bei einer Freigabe automatisch zurueckkommt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-21 09:08:08 +00:00
co-authored by Claude Opus 5
parent 09d9837dec
commit 0867221a3c
3 changed files with 329 additions and 230 deletions
+192 -111
View File
@@ -8,118 +8,199 @@
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.2/font/bootstrap-icons.min.css" rel="stylesheet">
</head>
<body class="bg-light">
<div class="container">
<div class="row justify-content-center mt-4 mb-5">
<div class="col-md-5">
<div class="card shadow-sm">
<div class="card-body p-4">
<div class="text-center mb-4">
<img src="{{ logo_url() }}" alt="Logo" style="height: 40px;" class="mb-2">
<h5 class="mb-0">Zentrale besetzen</h5>
</div>
<div class="container">
<div class="row justify-content-center mt-4 mb-5">
<div class="col-md-5">
<div class="card shadow-sm">
<div class="card-body p-4">
{% if message %}
<div class="alert alert-success py-2">
<small><i class="bi bi-check-circle"></i> {{ message }}</small>
</div>
{% endif %}
{% if error %}
<div class="alert alert-danger py-2">
<small><i class="bi bi-exclamation-triangle"></i> {{ error }}</small>
</div>
{% endif %}
{% if not target %}
<div class="alert alert-warning py-2 mb-0">
<small>
<i class="bi bi-gear"></i>
Die Zentrale ist noch nicht eingerichtet. Unter
<strong>Einstellungen &gt; Zentrale</strong> muss ein Busylight
und ein Segment ausgewaehlt werden.
</small>
</div>
{% else %}
<div class="border rounded p-3 mb-4 bg-white">
<div class="d-flex justify-content-between align-items-center">
<div>
<small class="text-muted d-block">Busylight der Zentrale</small>
<strong>{{ target.name }}</strong>
<small class="text-muted">(Segment {{ target.segment }})</small>
</div>
</div>
<hr class="my-2">
<small class="text-muted d-block">Aktuell besetzt von</small>
{% if occupant %}
<strong class="text-success"><i class="bi bi-person-fill"></i> {{ occupant }}</strong>
{% else %}
<span class="text-muted"><i class="bi bi-person-dash"></i> niemand</span>
{% endif %}
</div>
{% if user %}
<div class="text-center mb-3">
<small class="text-muted d-block">Durchwahl {{ user.phone_extension }}</small>
<strong>{{ user.display_name }}</strong>
</div>
{% if is_here %}
<div class="alert alert-info py-2">
<small><i class="bi bi-info-circle"></i> Du sitzt derzeit auf der Zentrale.</small>
</div>
{% endif %}
<form method="post" action="/api/zentrale/uebernehmen" class="mb-2">
<input type="hidden" name="extension" value="{{ user.phone_extension }}">
<button type="submit" class="btn btn-primary w-100" {% if is_here %}disabled{% endif %}>
<i class="bi bi-box-arrow-in-right"></i> Zentrale uebernehmen
</button>
</form>
<form method="post" action="/api/zentrale/verlassen">
<input type="hidden" name="extension" value="{{ user.phone_extension }}">
<button type="submit" class="btn btn-outline-secondary w-100">
<i class="bi bi-box-arrow-left"></i> Zurueck auf mein Tuerschild
</button>
</form>
{% if home %}
<div class="text-center mt-3">
<small class="text-muted">
Gemerktes Tuerschild: {{ home.name or home.hostname }} (Segment {{ home.segment }})
</small>
</div>
{% endif %}
<div class="text-center mt-3">
<a href="/zentrale" class="text-muted small">Andere Durchwahl</a>
</div>
{% else %}
<form method="post" action="/api/zentrale/uebernehmen">
<div class="mb-3">
<label class="form-label">Eigene Telefon-Durchwahl</label>
<input type="text" name="extension" class="form-control form-control-lg text-center"
inputmode="numeric" autocomplete="off" autofocus required
value="{{ extension }}" placeholder="z.B. 123">
<small class="text-muted">
Damit wird die eigene Person auf das Busylight der Zentrale gesetzt.
</small>
</div>
<button type="submit" class="btn btn-primary w-100">
<i class="bi bi-box-arrow-in-right"></i> Zentrale uebernehmen
</button>
</form>
{% endif %}
{% endif %}
<div class="text-center mt-4">
<small class="text-secondary" style="font-size:0.65rem">&copy; cynfo GmbH</small>
</div>
</div>
</div>
</div>
</div>
<div class="text-center mb-4">
<img src="{{ logo_url() }}" alt="Logo" style="height: 40px;" class="mb-2">
<h5 class="mb-0">Zentrale besetzen</h5>
</div>
{# ── Rueckmeldung der letzten Aktion ───────────────────────────────── #}
{% if done == 'uebernommen' %}
<div class="alert alert-success py-2"><small><i class="bi bi-check-circle"></i>
Du sitzt jetzt auf der Zentrale.</small></div>
{% elif done == 'bereits' %}
<div class="alert alert-info py-2"><small><i class="bi bi-info-circle"></i>
Du warst schon auf der Zentrale eingetragen. Das Licht wurde neu gesetzt.</small></div>
{% elif done == 'zurueck' %}
<div class="alert alert-success py-2"><small><i class="bi bi-check-circle"></i>
Zurueck auf dem eigenen Tuerschild.</small></div>
{% elif done == 'abgemeldet' %}
<div class="alert alert-success py-2"><small><i class="bi bi-check-circle"></i>
Von der Zentrale abgemeldet.</small></div>
{% elif done == 'stammplatz_hier' %}
<div class="alert alert-info py-2"><small><i class="bi bi-info-circle"></i>
Die Zentrale ist dein eigener Platz - es gibt nichts zurueckzusetzen.</small></div>
{% elif done == 'err_unbekannt' %}
<div class="alert alert-danger py-2"><small><i class="bi bi-x-circle"></i>
Die Durchwahl {{ extension }} ist keinem aktiven Benutzer zugeordnet.</small></div>
{% elif done == 'err_nicht_eingerichtet' %}
<div class="alert alert-warning py-2"><small><i class="bi bi-gear"></i>
Die Zentrale ist noch nicht eingerichtet.</small></div>
{% elif done == 'err_heimat_belegt' %}
<div class="alert alert-danger py-2"><small><i class="bi bi-x-circle"></i>
Dein eigenes Tuerschild ist inzwischen
{%- if home_blocker %} {{ home_blocker }}{% else %} jemand anderem{% endif %} zugeordnet.
Es wurde nichts geaendert - bitte den Administrator ansprechen.</small></div>
{% elif done == 'err_nichts_zu_tun' %}
<div class="alert alert-danger py-2"><small><i class="bi bi-x-circle"></i>
Du sitzt nicht auf der Zentrale und es ist kein eigenes Tuerschild gemerkt.</small></div>
{% elif done == 'err_stammplatz_fremd' %}
<div class="alert alert-warning py-2"><small><i class="bi bi-exclamation-triangle"></i>
Die Zentrale ist dein eigener Platz, aktuell hat sie jemand anderes.
Mit "Zentrale uebernehmen" holst du sie zurueck.</small></div>
{% endif %}
{% if not target %}
<div class="alert alert-warning py-2 mb-0">
<small><i class="bi bi-gear"></i>
Die Zentrale ist noch nicht eingerichtet. Unter
<strong>Einstellungen &gt; Zentrale</strong> muss ein Busylight und ein
Segment ausgewaehlt werden.</small>
</div>
{% else %}
{# ── Zustand der Zentrale, immer sichtbar ──────────────────────────── #}
<div class="border rounded p-3 mb-3 bg-white">
<small class="text-muted d-block">Busylight der Zentrale</small>
<strong>{{ target.name }}</strong>
<small class="text-muted">(Segment {{ target.segment }})</small>
<hr class="my-2">
{% if occupant %}
<small class="text-muted d-block">Aktuell besetzt von</small>
<strong class="{% if is_here %}text-primary{% else %}text-success{% endif %}">
<i class="bi bi-person-fill"></i> {{ occupant.display_name }}
{%- if is_here %} <span class="badge bg-primary">das bist du</span>{% endif %}
</strong>
{% if occupant_is_owner %}
<div><small class="text-muted">Das ist der Stammplatz dieser Person.</small></div>
{% endif %}
{% else %}
<small class="text-muted d-block">Aktuell besetzt von</small>
<span class="text-muted"><i class="bi bi-person-dash"></i> niemand - die Zentrale ist frei</span>
{% endif %}
{% if owner_waiting %}
<div class="mt-2"><small class="text-muted">
<i class="bi bi-hourglass-split"></i>
{{ owner_waiting }} gehoert auf die Zentrale und kommt automatisch zurueck,
sobald sie freigegeben wird.
</small></div>
{% endif %}
</div>
{% if not user %}
{# ── Schritt 1: Wer bist du? ──────────────────────────────────── #}
<form method="get" action="/zentrale">
<div class="mb-3">
<label class="form-label">Eigene Telefon-Durchwahl</label>
<input type="text" name="durchwahl" class="form-control form-control-lg text-center"
inputmode="numeric" autocomplete="off" autofocus required
value="{{ extension }}" placeholder="z.B. 123">
<small class="text-muted">
Im naechsten Schritt siehst du, was du tun kannst - es wird noch nichts geaendert.
</small>
</div>
<button type="submit" class="btn btn-primary w-100">
<i class="bi bi-arrow-right-circle"></i> Weiter
</button>
</form>
{% else %}
{# ── Schritt 2: Zustand und passende Aktionen ──────────────────── #}
<div class="text-center mb-3">
<small class="text-muted d-block">Durchwahl {{ user.phone_extension }}</small>
<strong>{{ user.display_name }}</strong>
</div>
{% if is_owner and is_here %}
<div class="alert alert-info py-2">
<small><i class="bi bi-house-check"></i>
Die Zentrale ist dein eigener Platz und du sitzt darauf.
Hier ist nichts zu tun - jemand anderes kann sie jederzeit uebernehmen,
danach kommst du automatisch zurueck.</small>
</div>
{% elif is_here %}
<div class="alert alert-primary py-2">
<small><i class="bi bi-person-check"></i>
Du sitzt aktuell auf der Zentrale.
{% if home %}
Dein eigenes Tuerschild ({{ home.name or home.hostname }}, Segment {{ home.segment }})
ist bis zur Rueckkehr ausgeschaltet.
{% endif %}
</small>
</div>
<form method="post" action="/api/zentrale/verlassen" class="mb-2">
<input type="hidden" name="extension" value="{{ user.phone_extension }}">
<button type="submit" class="btn btn-primary w-100">
<i class="bi bi-box-arrow-left"></i> Zurueck auf mein Tuerschild
</button>
</form>
{% if home_blocker %}
<div class="alert alert-warning py-2 mb-0">
<small><i class="bi bi-exclamation-triangle"></i>
Achtung: dein Tuerschild ist derzeit {{ home_blocker }} zugeordnet.
Die Rueckkehr wird abgelehnt, solange das so ist.</small>
</div>
{% endif %}
{% else %}
<form method="post" action="/api/zentrale/uebernehmen" class="mb-2">
<input type="hidden" name="extension" value="{{ user.phone_extension }}">
<button type="submit" class="btn btn-primary w-100">
<i class="bi bi-box-arrow-in-right"></i>
{% if occupant %}Zentrale uebernehmen{% else %}Zentrale besetzen{% endif %}
</button>
<small class="text-muted">
{% if occupant and occupant_is_owner %}
{{ occupant.display_name }} gehoert auf die Zentrale und kommt automatisch
zurueck, sobald du sie wieder freigibst.
{% elif occupant %}
{{ occupant.display_name }} wird dabei auf das eigene Tuerschild zurueckgesetzt.
{% else %}
Die Zentrale ist frei.
{% endif %}
</small>
</form>
{% if home %}
<form method="post" action="/api/zentrale/verlassen">
<button type="submit" class="btn btn-outline-secondary w-100 btn-sm">
<i class="bi bi-box-arrow-left"></i> Zurueck auf mein Tuerschild
</button>
<input type="hidden" name="extension" value="{{ user.phone_extension }}">
<small class="text-muted">
Gemerkt: {{ home.name or home.hostname }}, Segment {{ home.segment }}.
</small>
</form>
{% endif %}
{% endif %}
<div class="text-center mt-3">
<a href="/zentrale/{{ user.phone_extension }}" class="text-muted small me-3">
<i class="bi bi-arrow-clockwise"></i> Aktualisieren
</a>
<a href="/zentrale" class="text-muted small">Andere Durchwahl</a>
</div>
<div class="text-center mt-2">
<small class="text-secondary" style="font-size:0.7rem">
Diese Seite als Lesezeichen: <code>/zentrale/{{ user.phone_extension }}</code>
</small>
</div>
{% endif %}
{% endif %}
<div class="text-center mt-4">
<small class="text-secondary" style="font-size:0.65rem">&copy; cynfo GmbH</small>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>