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
end: string; // ISO datetime string for end
isAllDay?: boolean;
location?: string; // Jitsi URL for Vision meetings
}
type ConferenceType = "group" | "mission" | null;
@ -81,6 +82,7 @@ export default function VisionPage() {
location: string;
description: string;
recurrence: "none" | "daily" | "weekly" | "monthly";
isVideoConference: boolean;
}>({
type: "",
entityId: "",
@ -92,6 +94,7 @@ export default function VisionPage() {
location: "",
description: "",
recurrence: "none",
isVideoConference: false,
});
// Redirect if not authenticated
@ -149,6 +152,7 @@ export default function VisionPage() {
start: event.start,
end: event.end,
isAllDay: event.isAllDay || false,
location: event.location || undefined, // Include Jitsi URL if available
});
});
});
@ -243,18 +247,29 @@ export default function VisionPage() {
fetchData();
}, [session, status, toast]);
// Handle conference selection
const handleConferenceClick = (type: ConferenceType, id: string, name: string) => {
// Generate Jitsi URL (shared function used by both handleConferenceClick and form)
const generateJitsiUrl = (type: "group" | "mission", id: string): string => {
const baseUrl = process.env.NEXT_PUBLIC_IFRAME_CONFERENCE_URL || 'https://vision.slm-lab.net';
let url: string;
if (type === "group") {
// URL format: https://vision.slm-lab.net/Groupe-{groupId}
url = `${baseUrl}/Groupe-${id}`;
return `${baseUrl}/Groupe-${id}`;
} else {
// 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 });
setJitsiUrl(url);
@ -322,10 +337,17 @@ export default function VisionPage() {
location: "",
description: "",
recurrence: "none",
isVideoConference: false,
});
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
const handleSaveMeeting = async () => {
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
const eventPromises = eventsToCreate.map(async ({ start, end }) => {
const response = await fetch("/api/events", {
@ -424,7 +449,7 @@ export default function VisionPage() {
start: start.toISOString(),
end: end.toISOString(),
allDay: meetingForm.allDay,
location: meetingForm.location || null,
location: locationToSave,
calendarId: targetCalendar.id,
}),
});
@ -458,6 +483,7 @@ export default function VisionPage() {
location: "",
description: "",
recurrence: "none",
isVideoConference: false,
});
toast({
title: "Succès",
@ -611,7 +637,7 @@ export default function VisionPage() {
<Button
size="sm"
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" />
Rejoindre
@ -786,7 +812,7 @@ export default function VisionPage() {
<Button
size="sm"
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" />
Rejoindre
@ -1081,16 +1107,56 @@ export default function VisionPage() {
<Label htmlFor="allDay" className="text-gray-800">Toute la journée</Label>
</div>
<div className="space-y-2">
<Label className="text-gray-800">Lieu</Label>
<Input
value={meetingForm.location}
onChange={(e) =>
setMeetingForm({ ...meetingForm, location: e.target.value })
}
placeholder="Ajouter un lieu"
className="bg-white text-gray-900"
/>
<div className="grid gap-2">
<div className="flex items-center space-x-2 mb-2">
<Checkbox
id="isVideoConference"
checked={meetingForm.isVideoConference}
onCheckedChange={(checked) => {
const isChecked = checked as boolean;
setMeetingForm({
...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 className="space-y-2">
@ -1148,6 +1214,7 @@ export default function VisionPage() {
location: "",
description: "",
recurrence: "none",
isVideoConference: false,
});
}}
className="bg-white hover:bg-gray-50 text-gray-900 border-gray-200"