calendar widget 2
This commit is contained in:
parent
dfc08b920a
commit
1ecd092a66
@ -456,39 +456,64 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [selectedEventPreview, setSelectedEventPreview] = useState<Event | null>(null);
|
const [selectedEventPreview, setSelectedEventPreview] = useState<Event | null>(null);
|
||||||
|
const [upcomingEvents, setUpcomingEvents] = useState<Event[]>([]);
|
||||||
const [statistics, setStatistics] = useState({
|
const [statistics, setStatistics] = useState({
|
||||||
totalEvents: initialCalendars.reduce((acc, cal) => acc + cal.events.length, 0),
|
totalEvents: 0,
|
||||||
upcomingEvents: initialCalendars.reduce((acc, cal) =>
|
upcomingEvents: 0,
|
||||||
acc + cal.events.filter(e => new Date(e.start) > new Date()).length, 0
|
completedEvents: 0,
|
||||||
),
|
meetingHours: 0
|
||||||
completedEvents: initialCalendars.reduce((acc, cal) =>
|
|
||||||
acc + cal.events.filter(e => new Date(e.end) < new Date()).length, 0
|
|
||||||
),
|
|
||||||
meetingHours: initialCalendars.reduce((acc, cal) =>
|
|
||||||
acc + cal.events.reduce((hours, e) => {
|
|
||||||
const duration = (new Date(e.end).getTime() - new Date(e.start).getTime()) / (1000 * 60 * 60);
|
|
||||||
return hours + duration;
|
|
||||||
}, 0)
|
|
||||||
, 0)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const upcomingEvents = initialCalendars
|
|
||||||
.flatMap(cal => cal.events)
|
|
||||||
.filter(event => new Date(event.start) > new Date())
|
|
||||||
.sort((a, b) => new Date(a.start).getTime() - new Date(b.start).getTime())
|
|
||||||
.slice(0, 5);
|
|
||||||
|
|
||||||
const calendarRef = useRef<any>(null);
|
|
||||||
|
|
||||||
const [visibleCalendarIds, setVisibleCalendarIds] = useState<string[]>([]);
|
const [visibleCalendarIds, setVisibleCalendarIds] = useState<string[]>([]);
|
||||||
|
|
||||||
// Update useEffect to initialize visible calendars
|
// Update useEffect to initialize visible calendars and fetch events
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (calendars.length > 0) {
|
if (calendars.length > 0) {
|
||||||
setVisibleCalendarIds(calendars.map(cal => cal.id));
|
setVisibleCalendarIds(calendars.map(cal => cal.id));
|
||||||
|
updateStatistics();
|
||||||
|
updateUpcomingEvents();
|
||||||
}
|
}
|
||||||
}, [calendars]);
|
}, [calendars]);
|
||||||
|
|
||||||
|
const updateStatistics = () => {
|
||||||
|
const now = new Date();
|
||||||
|
const stats = {
|
||||||
|
totalEvents: 0,
|
||||||
|
upcomingEvents: 0,
|
||||||
|
completedEvents: 0,
|
||||||
|
meetingHours: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
calendars.forEach(cal => {
|
||||||
|
cal.events.forEach(event => {
|
||||||
|
stats.totalEvents++;
|
||||||
|
const eventStart = new Date(event.start);
|
||||||
|
const eventEnd = new Date(event.end);
|
||||||
|
|
||||||
|
if (eventStart > now) {
|
||||||
|
stats.upcomingEvents++;
|
||||||
|
} else if (eventEnd < now) {
|
||||||
|
stats.completedEvents++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const duration = (eventEnd.getTime() - eventStart.getTime()) / (1000 * 60 * 60);
|
||||||
|
stats.meetingHours += duration;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
setStatistics(stats);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateUpcomingEvents = () => {
|
||||||
|
const now = new Date();
|
||||||
|
const upcoming = calendars
|
||||||
|
.flatMap(cal => cal.events)
|
||||||
|
.filter(event => new Date(event.start) > now)
|
||||||
|
.sort((a, b) => new Date(a.start).getTime() - new Date(b.start).getTime())
|
||||||
|
.slice(0, 5);
|
||||||
|
setUpcomingEvents(upcoming);
|
||||||
|
};
|
||||||
|
|
||||||
const fetchCalendars = async () => {
|
const fetchCalendars = async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@ -497,79 +522,8 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
console.log("Raw calendars data:", data);
|
console.log("Raw calendars data:", data);
|
||||||
|
|
||||||
// First, clean up duplicate calendars and migrate events
|
// Process calendars and events
|
||||||
let calendarsData = [];
|
const processedCalendars = data.map((cal: Calendar & { events: Event[] }) => ({
|
||||||
let seenPrincipal = false;
|
|
||||||
let principalCalendarId = null;
|
|
||||||
|
|
||||||
// First pass: identify the principal calendar and other valid calendars
|
|
||||||
for (const cal of data) {
|
|
||||||
if (cal.name === "Calendrier principal") {
|
|
||||||
if (!seenPrincipal) {
|
|
||||||
seenPrincipal = true;
|
|
||||||
principalCalendarId = cal.id;
|
|
||||||
calendarsData.push(cal);
|
|
||||||
}
|
|
||||||
} else if (cal.name !== "Default") {
|
|
||||||
calendarsData.push(cal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no principal calendar exists, create one
|
|
||||||
if (!seenPrincipal) {
|
|
||||||
const principalCalendar = await fetch("/api/calendars", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
name: "Calendrier principal",
|
|
||||||
color: "#4f46e5",
|
|
||||||
description: "Calendrier principal",
|
|
||||||
userId,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (principalCalendar.ok) {
|
|
||||||
const newCalendar = await principalCalendar.json();
|
|
||||||
principalCalendarId = newCalendar.id;
|
|
||||||
calendarsData.unshift(newCalendar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete duplicate Calendrier principal and Default calendars
|
|
||||||
const deletePromises = data
|
|
||||||
.filter(cal =>
|
|
||||||
(cal.name === "Calendrier principal" && cal.id !== principalCalendarId) ||
|
|
||||||
cal.name === "Default"
|
|
||||||
)
|
|
||||||
.map(async (cal) => {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`/api/calendars/${cal.id}`, {
|
|
||||||
method: "DELETE",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
console.error(`Failed to delete calendar ${cal.id}: ${response.status}`);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error deleting calendar:", error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.all(deletePromises);
|
|
||||||
|
|
||||||
// Sort calendars to ensure Calendrier principal is first
|
|
||||||
calendarsData.sort((a, b) => {
|
|
||||||
if (a.name === "Calendrier principal") return -1;
|
|
||||||
if (b.name === "Calendrier principal") return 1;
|
|
||||||
return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ensure events array exists for each calendar and convert dates
|
|
||||||
const calendarsWithEvents = calendarsData.map((cal: Calendar & { events: Event[] }) => ({
|
|
||||||
...cal,
|
...cal,
|
||||||
events: (cal.events || []).map(event => ({
|
events: (cal.events || []).map(event => ({
|
||||||
...event,
|
...event,
|
||||||
@ -578,17 +532,12 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
|
|||||||
}))
|
}))
|
||||||
}));
|
}));
|
||||||
|
|
||||||
console.log("Setting calendars with processed events:", calendarsWithEvents);
|
console.log("Setting calendars with processed events:", processedCalendars);
|
||||||
setCalendars(calendarsWithEvents);
|
setCalendars(processedCalendars);
|
||||||
|
|
||||||
// Set initial selected calendar
|
// Update statistics and upcoming events
|
||||||
if (calendarsWithEvents.length > 0) {
|
updateStatistics();
|
||||||
const principalCalendar = calendarsWithEvents.find(cal => cal.name === "Calendrier principal");
|
updateUpcomingEvents();
|
||||||
setSelectedCalendarId(principalCalendar?.id || calendarsWithEvents[0].id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update visible calendars
|
|
||||||
setVisibleCalendarIds(calendarsWithEvents.map(cal => cal.id));
|
|
||||||
|
|
||||||
// Force calendar refresh
|
// Force calendar refresh
|
||||||
if (calendarRef.current) {
|
if (calendarRef.current) {
|
||||||
@ -603,21 +552,12 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
// Add a refresh function
|
||||||
|
const handleRefresh = () => {
|
||||||
fetchCalendars();
|
fetchCalendars();
|
||||||
}, []);
|
};
|
||||||
|
|
||||||
// Add effect to ensure selectedCalendarId is set
|
const calendarRef = useRef<any>(null);
|
||||||
useEffect(() => {
|
|
||||||
if (!selectedCalendarId && calendars.length > 0) {
|
|
||||||
console.log("Setting initial calendar selection:", calendars[0]);
|
|
||||||
setSelectedCalendarId(calendars[0].id);
|
|
||||||
setEventForm(prev => ({
|
|
||||||
...prev,
|
|
||||||
calendarId: calendars[0].id
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}, [calendars, selectedCalendarId]);
|
|
||||||
|
|
||||||
const handleCalendarSelect = (calendarId: string) => {
|
const handleCalendarSelect = (calendarId: string) => {
|
||||||
console.log("Calendar selected:", calendarId);
|
console.log("Calendar selected:", calendarId);
|
||||||
@ -1006,8 +946,8 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
|
|||||||
setEventForm({
|
setEventForm({
|
||||||
title: "",
|
title: "",
|
||||||
description: null,
|
description: null,
|
||||||
start: "",
|
start: new Date().toISOString(),
|
||||||
end: "",
|
end: new Date(new Date().setHours(new Date().getHours() + 1)).toISOString(),
|
||||||
allDay: false,
|
allDay: false,
|
||||||
location: null,
|
location: null,
|
||||||
calendarId: selectedCalendarId
|
calendarId: selectedCalendarId
|
||||||
@ -1019,6 +959,21 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
|
|||||||
<Plus className="mr-2 h-4 w-4" />
|
<Plus className="mr-2 h-4 w-4" />
|
||||||
<span className="font-medium">Nouvel événement</span>
|
<span className="font-medium">Nouvel événement</span>
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={handleRefresh}
|
||||||
|
disabled={loading}
|
||||||
|
className="ml-2"
|
||||||
|
>
|
||||||
|
{loading ? (
|
||||||
|
<Loader2 className="h-4 w-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<svg className="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||||||
|
<path d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
<span className="ml-2">Actualiser</span>
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Tabs value={view} className="w-auto">
|
<Tabs value={view} className="w-auto">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user