122 lines
3.6 KiB
TypeScript
122 lines
3.6 KiB
TypeScript
import { useState, useEffect } from "react";
|
|
import { useSession } from "next-auth/react";
|
|
|
|
export interface CalendarEvent {
|
|
id: string;
|
|
title: string;
|
|
start: Date | string;
|
|
end: Date | string;
|
|
isAllDay: boolean;
|
|
calendarId?: string;
|
|
calendarName?: string;
|
|
calendarColor?: string;
|
|
}
|
|
|
|
export interface UseCalendarEventsOptions {
|
|
limit?: number;
|
|
includeAllDay?: boolean;
|
|
includeMultiDay?: boolean;
|
|
filterCalendarIds?: string[];
|
|
}
|
|
|
|
export function useCalendarEvents({
|
|
limit = 10,
|
|
includeAllDay = true,
|
|
includeMultiDay = true,
|
|
filterCalendarIds
|
|
}: UseCalendarEventsOptions = {}) {
|
|
const [events, setEvents] = useState<CalendarEvent[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [refreshTrigger, setRefreshTrigger] = useState(0);
|
|
const { status } = useSession();
|
|
|
|
const refresh = () => {
|
|
setRefreshTrigger(prev => prev + 1);
|
|
};
|
|
|
|
useEffect(() => {
|
|
const fetchEvents = async () => {
|
|
if (status !== "authenticated") {
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
const response = await fetch('/api/calendars');
|
|
if (!response.ok) {
|
|
throw new Error('Failed to fetch events');
|
|
}
|
|
|
|
const calendarsData = await response.json();
|
|
|
|
// Get current date at the start of the day
|
|
const now = new Date();
|
|
now.setHours(0, 0, 0, 0);
|
|
|
|
// Extract and process events from all calendars
|
|
const allEvents = calendarsData.flatMap((calendar: any) =>
|
|
// Skip calendars if filtering is applied
|
|
(filterCalendarIds && !filterCalendarIds.includes(calendar.id)) ? [] :
|
|
(calendar.events || []).map((event: any) => ({
|
|
id: event.id,
|
|
title: event.title,
|
|
start: new Date(event.start),
|
|
end: new Date(event.end),
|
|
isAllDay: event.isAllDay || false,
|
|
calendarId: calendar.id,
|
|
calendarName: calendar.name,
|
|
calendarColor: calendar.color
|
|
}))
|
|
);
|
|
|
|
// Filter for upcoming events
|
|
const upcomingEvents = allEvents
|
|
.filter((event: CalendarEvent) => {
|
|
// Skip past events
|
|
if (new Date(event.start) < now) {
|
|
return false;
|
|
}
|
|
|
|
// Filter all-day events if not included
|
|
if (!includeAllDay && event.isAllDay) {
|
|
return false;
|
|
}
|
|
|
|
// Filter multi-day events if not included
|
|
if (!includeMultiDay) {
|
|
const startDate = new Date(event.start);
|
|
const endDate = new Date(event.end);
|
|
|
|
// Check if the event spans multiple days
|
|
startDate.setHours(0, 0, 0, 0);
|
|
endDate.setHours(0, 0, 0, 0);
|
|
|
|
if (startDate.getTime() !== endDate.getTime()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
})
|
|
.sort((a: CalendarEvent, b: CalendarEvent) =>
|
|
new Date(a.start).getTime() - new Date(b.start).getTime()
|
|
);
|
|
|
|
setEvents(limit ? upcomingEvents.slice(0, limit) : upcomingEvents);
|
|
setError(null);
|
|
} catch (error) {
|
|
setError(error instanceof Error ? error.message : 'Failed to fetch events');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchEvents();
|
|
}, [status, limit, includeAllDay, includeMultiDay, filterCalendarIds, refreshTrigger]);
|
|
|
|
return { events, loading, error, refresh };
|
|
}
|