- AW-2: Scope calendar events fetch to visible date range via start/end query params, leveraging existing backend support - AW-3: Reduce calendar events poll from 5s to 30s (personal organiser doesn't need 12 API calls/min) - AS-4: Gate shared-calendar polling on hasSharedCalendars — saves 12 wasted API calls/min for personal-only users - AS-2: Lazy-load all route components with React.lazy() — only AdminPortal was previously lazy, now all 10 routes are code-split - AS-1: Add Vite manualChunks to split FullCalendar (~400KB), React, TanStack Query, and UI libs into separate cacheable chunks - AS-3: Extract clockNow into isolated ClockDisplay memo component — prevents all 8 dashboard widgets from re-rendering every minute Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
53 lines
1.8 KiB
TypeScript
53 lines
1.8 KiB
TypeScript
import { useMemo, useRef } from 'react';
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import api from '@/lib/api';
|
|
import type { Calendar, SharedCalendarMembership } from '@/types';
|
|
|
|
interface UseCalendarsOptions {
|
|
pollingEnabled?: boolean;
|
|
}
|
|
|
|
export function useCalendars({ pollingEnabled = false }: UseCalendarsOptions = {}) {
|
|
const ownedQuery = useQuery({
|
|
queryKey: ['calendars'],
|
|
queryFn: async () => {
|
|
const { data } = await api.get<Calendar[]>('/calendars');
|
|
return data;
|
|
},
|
|
});
|
|
|
|
// AS-4: Gate shared-calendar polling on whether user participates in sharing.
|
|
// Saves ~12 API calls/min for personal-only users.
|
|
// Use a ref to latch "has sharing" once discovered, so polling doesn't flicker.
|
|
const hasSharingRef = useRef(false);
|
|
const ownsShared = (ownedQuery.data ?? []).some((c) => c.is_shared);
|
|
if (ownsShared) hasSharingRef.current = true;
|
|
|
|
const sharedQuery = useQuery({
|
|
queryKey: ['calendars', 'shared'],
|
|
queryFn: async () => {
|
|
const { data } = await api.get<SharedCalendarMembership[]>('/shared-calendars');
|
|
return data;
|
|
},
|
|
refetchInterval: pollingEnabled && hasSharingRef.current ? 5_000 : false,
|
|
staleTime: 3_000,
|
|
});
|
|
|
|
// Also latch if user is a member of others' shared calendars
|
|
if ((sharedQuery.data ?? []).length > 0) hasSharingRef.current = true;
|
|
|
|
const allCalendarIds = useMemo(() => {
|
|
const owned = (ownedQuery.data ?? []).map((c) => c.id);
|
|
const shared = (sharedQuery.data ?? []).map((m) => m.calendar_id);
|
|
return new Set([...owned, ...shared]);
|
|
}, [ownedQuery.data, sharedQuery.data]);
|
|
|
|
return {
|
|
data: ownedQuery.data ?? [],
|
|
sharedData: sharedQuery.data ?? [],
|
|
allCalendarIds,
|
|
isLoading: ownedQuery.isLoading,
|
|
isLoadingShared: sharedQuery.isLoading,
|
|
};
|
|
}
|