feat(collab): Karte + Journal parallel bearbeitbar
Some checks failed
Build and Push Docker Image / build-and-push (push) Has been cancelled
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:
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user