feat(notruf): Alarmpause pro Nutzer im Notfall-Profil (Minuten, 0=aus, leer=global)

Bisher war die Wiederauslöse-Sperre nur global einstellbar. Jetzt zusätzlich
pro Nutzer im Notfall-Profil (Admin), hinter „Standort im Notfall mitsenden":
„Pause bis zum erneuten Alarm: [n] Minuten" (leer = globaler Standard, 0 = aus).

- Auflösung serverseitig: Nutzer-Pref > globale Einstellung > 5
  (_resolve_cooldown_minutes in emergency.py; emergency_cooldown_status nutzt sie,
  die Notruf-UI/der Status-Endpunkt liefern dadurch automatisch den per-User-Wert).
- Schema AdminUserPrefsUpdate.emergency_cooldown_minutes (String) mit Validator
  (leer/0–60, sonst 422). /api/admin/users gibt das Feld jetzt mit aus
  (sonst lädt das Formular leer).
- Frontend: Zahlenfeld + Hinweis im Notfall-Profil, über PROF_KEYS/PROF_VALIDATORS
  verdrahtet. Bump app.js v=51 -> v=52.
- Doku: BEDIENUNGSANLEITUNG § Nutzer › Verwalten.

Tests: per-User-Override/Erben/Aus + Schema-Validierung. 254 Offline-Tests grün.
Live verifiziert: PUT prefs -> /status spiegelt 300->120s, 99 -> 422, Formular
zeigt/lädt das Feld hinter der Standort-Checkbox.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-26 17:10:12 +02:00
commit 904f7db82c
7 changed files with 97 additions and 8 deletions

View file

@ -368,6 +368,7 @@ const PROF_VALIDATORS = {
birth_date: { ok: _isGermanDate, msg: "Geburtsdatum: TT.MM.JJJJ" },
emergency_contacts: { ok: (v) => _csvAll(v, _isEmail), msg: "Kontakt-E-Mail(s): gültige Adressen (Komma-getrennt)" },
emergency_phones: { ok: (v) => _csvAll(v, _isPhone), msg: "Kontakt-Telefon(e): gültige Nummern (Komma-getrennt)" },
emergency_cooldown_minutes: { ok: (v) => /^\d+$/.test(v) && +v <= 60, msg: "Pause: 060 ganze Minuten" },
};
// Wendet die vom Admin erlaubten Sprachen auf das Sprachmenü an. Leer = alle erlaubt.
@ -1191,6 +1192,13 @@ function buildUserCard(u) {
<label class="flex items-center gap-2 text-xs text-slate-600 dark:text-slate-300">
<input type="checkbox" class="prof-consent" /> Standort im Notfall mitsenden
</label>
<label class="flex items-center gap-2 text-xs text-slate-600 dark:text-slate-300">
Pause bis zum erneuten Alarm:
<input type="number" min="0" max="60" inputmode="numeric"
class="prof-f w-16 rounded-lg border border-slate-300 dark:border-slate-600 bg-transparent px-2 py-1.5 text-xs focus:outline-none focus:ring-2 focus:ring-blue-500"
data-k="emergency_cooldown_minutes" placeholder="Standard" /> Minuten
</label>
<p class="text-[11px] text-slate-400">leer = globaler Standard · 0 = aus</p>
</div>
</div>
@ -1241,7 +1249,8 @@ function buildUserCard(u) {
// Notfall-Profil — Admin pflegt Kontaktdaten + med. Hinweise + Standort-Freigabe.
const PROF_KEYS = ["full_name", "street", "postal_code", "city", "phone_mobile",
"phone_landline", "birth_date", "medical_notes",
"emergency_contacts", "emergency_phones"];
"emergency_contacts", "emergency_phones",
"emergency_cooldown_minutes"];
PROF_KEYS.forEach((k) => {
const el = card.querySelector(`.prof-f[data-k="${k}"]`);
if (el) el.value = u[k] || "";