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;