From e62503424c72075b5d7c88aa928d90e0451f4fad Mon Sep 17 00:00:00 2001 From: Kyle Pope Date: Fri, 6 Mar 2026 17:26:22 +0800 Subject: [PATCH] Fix event lock system: banner persistence, stale isEditing guard, and Edit button gating - Remove isEditing guard from viewLockQuery effect so lock banner shows for user B even after user A transitions into edit mode (fixes banner disappearing) - Disable Edit button proactively when lockInfo.locked is already known from polling, preventing the user from even attempting acquireLock when a lock is active - Fix acquire callback dep array in useEventLock (missing acquireMutation) Co-Authored-By: Claude Opus 4.6 --- .../components/calendar/EventDetailPanel.tsx | 19 +++++++++---------- frontend/src/hooks/useEventLock.ts | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/frontend/src/components/calendar/EventDetailPanel.tsx b/frontend/src/components/calendar/EventDetailPanel.tsx index 0fe4b34..b656fbe 100644 --- a/frontend/src/components/calendar/EventDetailPanel.tsx +++ b/frontend/src/components/calendar/EventDetailPanel.tsx @@ -276,16 +276,15 @@ export default function EventDetailPanel({ refetchInterval: 5_000, }); - // Show/hide lock banner proactively in view mode + // Show/hide lock banner proactively in view mode (poll data always authoritative) useEffect(() => { - if (viewLockQuery.data && !isEditing && !isCreating) { - if (viewLockQuery.data.locked) { - setLockInfo(viewLockQuery.data); - } else { - setLockInfo(null); - } + if (!viewLockQuery.data) return; + if (viewLockQuery.data.locked) { + setLockInfo(viewLockQuery.data); + } else { + setLockInfo(null); } - }, [viewLockQuery.data, isEditing, isCreating]); + }, [viewLockQuery.data]); const isRecurring = !!(event?.is_recurring || event?.parent_event_id); @@ -581,8 +580,8 @@ export default function EventDetailPanel({ size="icon" className="h-7 w-7" onClick={handleEditStart} - disabled={isAcquiringLock} - title="Edit event" + disabled={isAcquiringLock || !!(lockInfo && lockInfo.locked)} + title={lockInfo && lockInfo.locked ? `Locked by ${lockInfo.locked_by_name || 'another user'}` : 'Edit event'} > {isAcquiringLock ? : } diff --git a/frontend/src/hooks/useEventLock.ts b/frontend/src/hooks/useEventLock.ts index 9c8d695..3495773 100644 --- a/frontend/src/hooks/useEventLock.ts +++ b/frontend/src/hooks/useEventLock.ts @@ -34,7 +34,7 @@ export function useEventLock(eventId: number | null) { if (!eventId) return null; const data = await acquireMutation.mutateAsync(eventId); return data; - }, [eventId]); + }, [eventId, acquireMutation]); const release = useCallback(async () => { const id = activeEventIdRef.current;