Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions apps/meteor/client/views/calendar/hooks/useCalendarList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useEndpoint } from '@rocket.chat/ui-contexts';
import { useQuery } from '@tanstack/react-query';

/**
* Generic hook to fetch calendar events for a given date.
*
* This hook calls the provider-agnostic `/v1/calendar-events.list` endpoint,
* so it works regardless of the calendar source (Outlook, Google, CalDAV, etc.).
*
* @param date - The date for which to fetch calendar events.
* @returns A React Query result containing the list of calendar events.
*/
export const useCalendarList = (date: Date) => {
const calendarData = useEndpoint('GET', '/v1/calendar-events.list');

return useQuery({
queryKey: ['calendar', 'list', date.toISOString()],

queryFn: async () => {
const { data } = await calendarData({ date: date.toISOString() });
return data;
},
});
};

/**
* Convenience wrapper that fetches calendar events for today's date.
*/
export const useCalendarListForToday = () => {
return useCalendarList(new Date());
};
Comment on lines +29 to +31
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unstable query key due to new Date() called on every render.

new Date() generates a different timestamp (including milliseconds) on each render, producing a different toISOString() value for the query key. This causes React Query to treat every render as a new query, leading to cache misses and potential excessive API calls.

Memoize the date to ensure stability across renders:

🐛 Proposed fix using useMemo
+import { useMemo } from 'react';
+
+const getStartOfDay = (date: Date) => {
+	const start = new Date(date);
+	start.setHours(0, 0, 0, 0);
+	return start;
+};
+
 export const useCalendarListForToday = () => {
-	return useCalendarList(new Date());
+	const today = useMemo(() => getStartOfDay(new Date()), []);
+	return useCalendarList(today);
 };

Alternatively, if the date should update when the calendar day changes (e.g., app open past midnight), consider a more sophisticated approach that only changes when the calendar day itself changes.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const useCalendarListForToday = () => {
return useCalendarList(new Date());
};
import { useMemo } from 'react';
const getStartOfDay = (date: Date) => {
const start = new Date(date);
start.setHours(0, 0, 0, 0);
return start;
};
export const useCalendarListForToday = () => {
const today = useMemo(() => getStartOfDay(new Date()), []);
return useCalendarList(today);
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/views/calendar/hooks/useCalendarList.ts` around lines 29 -
31, The hook useCalendarListForToday creates an unstable query key by calling
new Date() on every render; update it to memoize the Date (or a date-only value)
so the key remains stable across renders and only changes when the calendar day
changes. Modify useCalendarListForToday to compute a stable "today" value (e.g.,
using React's useMemo to derive a Date representing the current day or a
YYYY-MM-DD string) and pass that memoized value into useCalendarList instead of
calling new Date() directly.

Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { useToastMessageDispatch, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts';
import { useMutation, useQueryClient } from '@tanstack/react-query';

import { useOutlookAuthenticationMutation } from './useOutlookAuthentication';
import { useCalendarList, useCalendarListForToday } from '../../calendar/hooks/useCalendarList';
import { syncOutlookEvents } from '../lib/syncOutlookEvents';

/**
* @deprecated Use {@link useCalendarListForToday} from `views/calendar/hooks/useCalendarList` directly.
* Kept for backward compatibility with existing Outlook calendar views.
*/
export const useOutlookCalendarListForToday = () => {
return useOutlookCalendarList(new Date());
return useCalendarListForToday();
};

/**
* @deprecated Use {@link useCalendarList} from `views/calendar/hooks/useCalendarList` directly.
* Kept for backward compatibility with existing Outlook calendar views.
*/
export const useOutlookCalendarList = (date: Date) => {
const calendarData = useEndpoint('GET', '/v1/calendar-events.list');

return useQuery({
queryKey: ['outlook', 'calendar', 'list'],

queryFn: async () => {
const { data } = await calendarData({ date: date.toISOString() });
return data;
},
});
return useCalendarList(date);
};

export const useMutationOutlookCalendarSync = () => {
Expand All @@ -34,7 +34,7 @@ export const useMutationOutlookCalendarSync = () => {
await syncOutlookEvents();

await queryClient.invalidateQueries({
queryKey: ['outlook', 'calendar', 'list'],
queryKey: ['calendar', 'list'],
});

await checkOutlookCredentials.mutateAsync();
Expand Down