vision refactor

This commit is contained in:
alma 2026-01-15 21:00:00 +01:00
parent 607f762a40
commit b185c130c9

View File

@ -1,6 +1,6 @@
"use client";
import { useState, useEffect } from "react";
import { useState, useEffect, useCallback } from "react";
import { useSession } from "next-auth/react";
import { redirect } from "next/navigation";
import { ResponsiveIframe } from "@/app/components/responsive-iframe";
@ -197,39 +197,70 @@ export default function VisionPage() {
return meetings;
};
// Load meetings from database (events from group and mission calendars)
useEffect(() => {
const fetchMeetings = async () => {
if (status !== "authenticated" || !session?.user?.id) {
return;
}
// Function to fetch and refresh meetings from database
const fetchMeetings = useCallback(async (showLoading = true) => {
if (status !== "authenticated" || !session?.user?.id) {
return;
}
try {
try {
if (showLoading) {
setMeetingsLoading(true);
// Fetch calendars with events
const calendarsResponse = await fetch("/api/calendars");
if (!calendarsResponse.ok) {
throw new Error("Impossible de charger les calendriers");
}
const calendarsData = await calendarsResponse.json();
}
// Fetch calendars with events, use refresh=true to bypass cache
const calendarsResponse = await fetch("/api/calendars?refresh=true");
if (!calendarsResponse.ok) {
throw new Error("Impossible de charger les calendriers");
}
const calendarsData = await calendarsResponse.json();
const meetings = convertCalendarsToMeetings(calendarsData);
setScheduledMeetings(meetings);
} catch (error) {
console.error("Error loading meetings:", error);
toast({
title: "Erreur",
description: "Impossible de charger les réunions",
variant: "destructive",
});
} finally {
const meetings = convertCalendarsToMeetings(calendarsData);
// Debug log
console.log('[Vision] Loaded meetings:', {
totalMeetings: meetings.length,
todayMeetings: meetings.filter(m => m.date === formatDateLocal(new Date())).length,
meetings: meetings.map(m => ({
id: m.id,
title: m.title,
date: m.date,
time: m.time,
type: m.type,
entityId: m.entityId,
entityName: m.entityName,
start: m.start,
end: m.end,
location: m.location
}))
});
setScheduledMeetings(meetings);
} catch (error) {
console.error("Error loading meetings:", error);
toast({
title: "Erreur",
description: "Impossible de charger les réunions",
variant: "destructive",
});
} finally {
if (showLoading) {
setMeetingsLoading(false);
}
};
fetchMeetings();
}
}, [session, status, groups, missions, toast]);
// Load meetings from database (events from group and mission calendars)
useEffect(() => {
fetchMeetings();
// Refresh meetings every minute to update "Rejoindre" button status
const interval = setInterval(() => {
fetchMeetings(false); // Don't show loading spinner on auto-refresh
}, 60000); // Every minute
return () => clearInterval(interval);
}, [fetchMeetings]);
// Fetch user groups and missions
useEffect(() => {
const fetchData = async () => {
@ -321,10 +352,25 @@ export default function VisionPage() {
// Check if meeting can be joined (5 minutes before start until end)
const canJoinMeeting = (meeting: ScheduledMeeting): boolean => {
if (!meeting.start || !meeting.end) {
console.warn('[Vision] canJoinMeeting: missing start or end', meeting);
return false;
}
const now = new Date();
const start = new Date(meeting.start);
const end = new Date(meeting.end);
// Validate dates
if (isNaN(start.getTime()) || isNaN(end.getTime())) {
console.warn('[Vision] canJoinMeeting: invalid dates', {
meetingId: meeting.id,
start: meeting.start,
end: meeting.end
});
return false;
}
// Calculate 5 minutes before start
const fiveMinutesBeforeStart = new Date(start);
fiveMinutesBeforeStart.setMinutes(fiveMinutesBeforeStart.getMinutes() - 5);
@ -332,18 +378,27 @@ export default function VisionPage() {
// Can join if now is between 5 minutes before start and end
const canJoin = now >= fiveMinutesBeforeStart && now <= end;
// Debug log
if (meeting.date === formatDateLocal(now)) {
// Debug log for today's meetings
const today = formatDateLocal(now);
if (meeting.date === today) {
console.log('[Vision] canJoinMeeting check:', {
meetingId: meeting.id,
title: meeting.title,
date: meeting.date,
time: meeting.time,
now: now.toISOString(),
nowLocal: now.toString(),
start: start.toISOString(),
startLocal: start.toString(),
end: end.toISOString(),
endLocal: end.toString(),
fiveMinutesBeforeStart: fiveMinutesBeforeStart.toISOString(),
fiveMinutesBeforeStartLocal: fiveMinutesBeforeStart.toString(),
canJoin,
nowVsFiveMinBefore: now >= fiveMinutesBeforeStart,
nowVsEnd: now <= end
nowVsEnd: now <= end,
timeDiff: (now.getTime() - fiveMinutesBeforeStart.getTime()) / 1000 / 60, // minutes
location: meeting.location
});
}
@ -589,30 +644,7 @@ export default function VisionPage() {
await Promise.all(eventPromises);
// Refresh meetings from database after creation
// Use refresh=true to bypass cache and ensure immediate update
const refreshCalendarsResponse = await fetch("/api/calendars?refresh=true");
if (refreshCalendarsResponse.ok) {
const calendarsData = await refreshCalendarsResponse.json();
const meetings = convertCalendarsToMeetings(calendarsData);
// Debug log
console.log('[Vision] Refreshed meetings after creation:', {
totalMeetings: meetings.length,
meetings: meetings.map(m => ({
id: m.id,
title: m.title,
date: m.date,
time: m.time,
type: m.type,
entityId: m.entityId,
entityName: m.entityName,
start: m.start,
end: m.end
}))
});
setScheduledMeetings(meetings);
}
await fetchMeetings(false); // Don't show loading spinner
setShowMeetingDialog(false);
setMeetingForm({
type: "",
@ -652,13 +684,7 @@ export default function VisionPage() {
}
// Refresh meetings from database after deletion
// Use refresh=true to bypass cache and ensure immediate update
const refreshCalendarsResponse = await fetch("/api/calendars?refresh=true");
if (refreshCalendarsResponse.ok) {
const calendarsData = await refreshCalendarsResponse.json();
const meetings = convertCalendarsToMeetings(calendarsData);
setScheduledMeetings(meetings);
}
await fetchMeetings(false); // Don't show loading spinner
toast({
title: "Succès",
@ -773,7 +799,7 @@ export default function VisionPage() {
</div>
</div>
<div className="flex items-center gap-2">
{canJoinMeeting(meeting) && (
{canJoinMeeting(meeting) && meeting.location ? (
<Button
size="sm"
className="bg-blue-600 hover:bg-blue-700 text-white"
@ -782,6 +808,10 @@ export default function VisionPage() {
<Video className="h-4 w-4 mr-1" />
Rejoindre
</Button>
) : (
<span className="text-xs text-gray-400">
{!meeting.location ? 'Pas de lien' : 'Bientôt disponible'}
</span>
)}
</div>
</div>
@ -988,8 +1018,7 @@ export default function VisionPage() {
{groups.map((group) => (
<div
key={group.id}
className="bg-white rounded-lg border border-gray-200 p-4 hover:shadow-md transition-shadow cursor-pointer"
onClick={() => handleConferenceClick("group", group.id, group.name)}
className="bg-white rounded-lg border border-gray-200 p-4 hover:shadow-md transition-shadow"
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3 flex-1">
@ -1058,8 +1087,7 @@ export default function VisionPage() {
{missions.map((mission) => (
<div
key={mission.id}
className="bg-white rounded-lg border border-gray-200 p-4 hover:shadow-md transition-shadow cursor-pointer"
onClick={() => handleConferenceClick("mission", mission.id, mission.name)}
className="bg-white rounded-lg border border-gray-200 p-4 hover:shadow-md transition-shadow"
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3 flex-1">