vision refactor

This commit is contained in:
alma 2026-01-15 19:54:56 +01:00
parent cc787e040b
commit 0ef38dc5dd

View File

@ -50,6 +50,7 @@ interface ScheduledMeeting {
start: string; // ISO datetime string for start start: string; // ISO datetime string for start
end: string; // ISO datetime string for end end: string; // ISO datetime string for end
isAllDay?: boolean; isAllDay?: boolean;
location?: string; // Jitsi URL for Vision meetings
} }
type ConferenceType = "group" | "mission" | null; type ConferenceType = "group" | "mission" | null;
@ -81,6 +82,7 @@ export default function VisionPage() {
location: string; location: string;
description: string; description: string;
recurrence: "none" | "daily" | "weekly" | "monthly"; recurrence: "none" | "daily" | "weekly" | "monthly";
isVideoConference: boolean;
}>({ }>({
type: "", type: "",
entityId: "", entityId: "",
@ -92,6 +94,7 @@ export default function VisionPage() {
location: "", location: "",
description: "", description: "",
recurrence: "none", recurrence: "none",
isVideoConference: false,
}); });
// Redirect if not authenticated // Redirect if not authenticated
@ -149,6 +152,7 @@ export default function VisionPage() {
start: event.start, start: event.start,
end: event.end, end: event.end,
isAllDay: event.isAllDay || false, isAllDay: event.isAllDay || false,
location: event.location || undefined, // Include Jitsi URL if available
}); });
}); });
}); });
@ -243,18 +247,29 @@ export default function VisionPage() {
fetchData(); fetchData();
}, [session, status, toast]); }, [session, status, toast]);
// Handle conference selection // Generate Jitsi URL (shared function used by both handleConferenceClick and form)
const handleConferenceClick = (type: ConferenceType, id: string, name: string) => { const generateJitsiUrl = (type: "group" | "mission", id: string): string => {
const baseUrl = process.env.NEXT_PUBLIC_IFRAME_CONFERENCE_URL || 'https://vision.slm-lab.net'; const baseUrl = process.env.NEXT_PUBLIC_IFRAME_CONFERENCE_URL || 'https://vision.slm-lab.net';
let url: string;
if (type === "group") { if (type === "group") {
// URL format: https://vision.slm-lab.net/Groupe-{groupId} // URL format: https://vision.slm-lab.net/Groupe-{groupId}
url = `${baseUrl}/Groupe-${id}`; return `${baseUrl}/Groupe-${id}`;
} else { } else {
// URL format: https://vision.slm-lab.net/{missionId} // URL format: https://vision.slm-lab.net/{missionId}
url = `${baseUrl}/${id}`; return `${baseUrl}/${id}`;
} }
};
// Handle conference selection
const handleConferenceClick = (type: ConferenceType, id: string, name: string, jitsiUrl?: string) => {
// If Jitsi URL is provided (from meeting location), use it directly
if (jitsiUrl) {
setSelectedConference({ type, id, name });
setJitsiUrl(jitsiUrl);
return;
}
// Otherwise, generate URL from type and id using shared function
const url = generateJitsiUrl(type, id);
setSelectedConference({ type, id, name }); setSelectedConference({ type, id, name });
setJitsiUrl(url); setJitsiUrl(url);
@ -322,10 +337,17 @@ export default function VisionPage() {
location: "", location: "",
description: "", description: "",
recurrence: "none", recurrence: "none",
isVideoConference: false,
}); });
setShowMeetingDialog(true); setShowMeetingDialog(true);
}; };
// Generate Jitsi URL based on meeting form (uses shared function)
const getJitsiUrl = (): string => {
if (!meetingForm.type || !meetingForm.entityId) return "";
return generateJitsiUrl(meetingForm.type, meetingForm.entityId);
};
// Handle save meeting // Handle save meeting
const handleSaveMeeting = async () => { const handleSaveMeeting = async () => {
if (!meetingForm.type || !meetingForm.entityId || !meetingForm.start || !meetingForm.end) { if (!meetingForm.type || !meetingForm.entityId || !meetingForm.start || !meetingForm.end) {
@ -411,6 +433,9 @@ export default function VisionPage() {
} }
} }
// Determine location: use Jitsi URL if video conference is enabled, otherwise use manual location
const locationToSave = meetingForm.isVideoConference ? getJitsiUrl() : (meetingForm.location || null);
// Create all events via API // Create all events via API
const eventPromises = eventsToCreate.map(async ({ start, end }) => { const eventPromises = eventsToCreate.map(async ({ start, end }) => {
const response = await fetch("/api/events", { const response = await fetch("/api/events", {
@ -424,7 +449,7 @@ export default function VisionPage() {
start: start.toISOString(), start: start.toISOString(),
end: end.toISOString(), end: end.toISOString(),
allDay: meetingForm.allDay, allDay: meetingForm.allDay,
location: meetingForm.location || null, location: locationToSave,
calendarId: targetCalendar.id, calendarId: targetCalendar.id,
}), }),
}); });
@ -458,6 +483,7 @@ export default function VisionPage() {
location: "", location: "",
description: "", description: "",
recurrence: "none", recurrence: "none",
isVideoConference: false,
}); });
toast({ toast({
title: "Succès", title: "Succès",
@ -611,7 +637,7 @@ export default function VisionPage() {
<Button <Button
size="sm" size="sm"
className="bg-blue-600 hover:bg-blue-700 text-white" className="bg-blue-600 hover:bg-blue-700 text-white"
onClick={() => handleConferenceClick(meeting.type, meeting.entityId, meeting.entityName)} onClick={() => handleConferenceClick(meeting.type, meeting.entityId, meeting.entityName, meeting.location)}
> >
<Video className="h-4 w-4 mr-1" /> <Video className="h-4 w-4 mr-1" />
Rejoindre Rejoindre
@ -786,7 +812,7 @@ export default function VisionPage() {
<Button <Button
size="sm" size="sm"
variant="outline" variant="outline"
onClick={() => handleConferenceClick(meeting.type, meeting.entityId, meeting.entityName)} onClick={() => handleConferenceClick(meeting.type, meeting.entityId, meeting.entityName, meeting.location)}
> >
<Video className="h-4 w-4 mr-1" /> <Video className="h-4 w-4 mr-1" />
Rejoindre Rejoindre
@ -1081,16 +1107,56 @@ export default function VisionPage() {
<Label htmlFor="allDay" className="text-gray-800">Toute la journée</Label> <Label htmlFor="allDay" className="text-gray-800">Toute la journée</Label>
</div> </div>
<div className="space-y-2"> <div className="grid gap-2">
<Label className="text-gray-800">Lieu</Label> <div className="flex items-center space-x-2 mb-2">
<Input <Checkbox
value={meetingForm.location} id="isVideoConference"
onChange={(e) => checked={meetingForm.isVideoConference}
setMeetingForm({ ...meetingForm, location: e.target.value }) onCheckedChange={(checked) => {
} const isChecked = checked as boolean;
placeholder="Ajouter un lieu" setMeetingForm({
className="bg-white text-gray-900" ...meetingForm,
/> isVideoConference: isChecked,
// If enabling video conference, generate Jitsi URL
// If disabling, clear location
location: isChecked ? getJitsiUrl() : ""
});
}}
/>
<Label
htmlFor="isVideoConference"
className="text-base font-semibold text-gray-800 cursor-pointer"
>
Visioconférence
</Label>
</div>
{meetingForm.isVideoConference ? (
<div className="space-y-1">
<Input
id="meeting-location"
value={getJitsiUrl()}
disabled
className="bg-gray-100 text-gray-600 cursor-not-allowed"
placeholder="Lien Jitsi généré automatiquement"
/>
<p className="text-xs text-gray-500">
Le lien Jitsi sera généré automatiquement pour cette réunion
</p>
</div>
) : (
<div className="space-y-1">
<Label htmlFor="meeting-location" className="text-gray-800">Lieu</Label>
<Input
id="meeting-location"
value={meetingForm.location}
onChange={(e) =>
setMeetingForm({ ...meetingForm, location: e.target.value })
}
placeholder="Ajouter un lieu"
className="bg-white text-gray-900"
/>
</div>
)}
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
@ -1148,6 +1214,7 @@ export default function VisionPage() {
location: "", location: "",
description: "", description: "",
recurrence: "none", recurrence: "none",
isVideoConference: false,
}); });
}} }}
className="bg-white hover:bg-gray-50 text-gray-900 border-gray-200" className="bg-white hover:bg-gray-50 text-gray-900 border-gray-200"