feat(collab): Karte + Journal parallel bearbeitbar
Some checks failed
Build and Push Docker Image / build-and-push (push) Has been cancelled

- Editor-Lock aufgeteilt: canEditMap (Lock-geschützt) vs. canEditJournal (nur Rolle)
- Eine Person kann zeichnen, während eine andere parallel Journal führt
  (Führungsstab-Szenario: Zeichner + Journalführer)
- Journal-Live-Sync existierte bereits (Socket journal-updated -> journal-refresh)
- Banner-Texte präzisiert ("bearbeitet die Karte", "Journal bleibt bearbeitbar")
- Version 1.4.8

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pepe Ziberi
2026-07-19 00:39:31 +02:00
parent a081b3ebe4
commit bae1cfe9a0
3 changed files with 15 additions and 9 deletions

View File

@@ -377,8 +377,12 @@ export default function AppPage() {
}, [authLoading, user, router])
const roleCanEdit = user ? (user.role === 'SERVER_ADMIN' || user.role === 'TENANT_ADMIN' || user.role === 'OPERATOR') : false
// User can only edit if they have the role AND they hold the editing lock (or no one is editing)
const canEdit = !presentationLocked && roleCanEdit && (isEditingByMe || !editingBy)
// Karte: nur mit Editing-Lock bearbeitbar (verhindert Zeichen-Konflikte).
// Journal/Cockpit: unabhängig vom Karten-Lock — so kann eine Person zeichnen,
// während eine andere parallel das Journal führt (Führungsstab-Szenario).
const canEditMap = !presentationLocked && roleCanEdit && (isEditingByMe || !editingBy)
const canEditJournal = !presentationLocked && roleCanEdit
const canEdit = canEditMap // Abwärtskompatibel für Karten-bezogene Stellen
const isReadOnly = !!editingBy && !isEditingByMe
// Auto-save: localStorage persistence + debounced API save + beacon on unload
@@ -870,12 +874,12 @@ export default function AppPage() {
{isReadOnly ? (
<div className="flex items-center gap-2 text-orange-600">
<Eye className="w-4 h-4" />
<span><strong>{editingBy?.name}</strong> bearbeitet gerade Live-Ansicht (alle 5s aktualisiert)</span>
<span><strong>{editingBy?.name}</strong> bearbeitet die Karte Live-Ansicht{roleCanEdit ? ' · Journal bleibt für Sie bearbeitbar' : ''}</span>
</div>
) : isEditingByMe ? (
<div className="flex items-center gap-2 text-green-600">
<Lock className="w-4 h-4" />
<span>Sie bearbeiten andere sehen Ihre Änderungen in Echtzeit</span>
<span>Sie bearbeiten die Karte andere sehen Ihre Änderungen in Echtzeit</span>
</div>
) : (
<div className="flex items-center gap-2 text-muted-foreground">
@@ -941,7 +945,7 @@ export default function AppPage() {
<ExerciseCockpit
projectId={currentProject?.id || null}
projectTitle={currentProject?.title || ''}
canEdit={canEdit}
canEdit={canEditJournal}
initialEvaluation={currentProject?.exerciseEvaluation || ''}
onEvaluationSaved={(value) =>
setCurrentProject((prev) => (prev ? { ...prev, exerciseEvaluation: value } : prev))
@@ -956,7 +960,7 @@ export default function AppPage() {
einsatzleiter={currentProject?.einsatzleiter || ''}
journalfuehrer={currentProject?.journalfuehrer || ''}
einsatzNr={(currentProject as any)?.einsatzNr || ''}
canEdit={canEdit}
canEdit={canEditJournal}
tenantId={tenant?.id || null}
tenantName={tenant?.name || ''}
tenantLogoUrl={tenant?.id ? `/api/admin/tenants/${tenant.id}/logo/serve` : null}