Agenda refactor

This commit is contained in:
alma 2026-01-15 18:36:33 +01:00
parent 9d5a8d6d2f
commit 82070fa033

View File

@ -994,10 +994,15 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
const endDate = new Date(startDate); const endDate = new Date(startDate);
endDate.setHours(startDate.getHours() + 1); endDate.setHours(startDate.getHours() + 1);
// If no calendar is selected, use the first available calendar // Get available calendars and use the first one if needed
if (!selectedCalendarId && calendars.length > 0) { const availableCalendarsList = getAvailableCalendars();
const firstCalendar = calendars[0]; const calendarToUse = selectedCalendarId && availableCalendarsList.some(cal => cal.id === selectedCalendarId)
setSelectedCalendarId(firstCalendar.id); ? selectedCalendarId
: (availableCalendarsList[0]?.id || calendars[0]?.id);
if (calendarToUse && calendarToUse !== selectedCalendarId) {
setSelectedCalendarId(calendarToUse);
}
setEventForm({ setEventForm({
title: "", title: "",
@ -1006,19 +1011,8 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
end: endDate.toISOString(), end: endDate.toISOString(),
allDay: false, allDay: false,
location: null, location: null,
calendarId: firstCalendar.id calendarId: calendarToUse
}); });
} else {
setEventForm({
title: "",
description: null,
start: startDate.toISOString(),
end: endDate.toISOString(),
allDay: false,
location: null,
calendarId: selectedCalendarId
});
}
setIsEventModalOpen(true); setIsEventModalOpen(true);
lastClickDateRef.current = null; lastClickDateRef.current = null;
@ -1050,32 +1044,25 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
selectDate.setHours(0, 0, 0, 0); selectDate.setHours(0, 0, 0, 0);
setSelectedDate(selectDate); setSelectedDate(selectDate);
// If no calendar is selected, use the first available calendar // Get available calendars and use the first one if needed
if (!selectedCalendarId && calendars.length > 0) { const availableCalendarsList = getAvailableCalendars();
const firstCalendar = calendars[0]; const calendarToUse = selectedCalendarId && availableCalendarsList.some(cal => cal.id === selectedCalendarId)
console.log("No calendar selected, selecting first calendar:", firstCalendar); ? selectedCalendarId
setSelectedCalendarId(firstCalendar.id); : (availableCalendarsList[0]?.id || calendars[0]?.id);
if (calendarToUse && calendarToUse !== selectedCalendarId) {
setSelectedCalendarId(calendarToUse);
}
setEventForm({ setEventForm({
title: "", title: "",
description: null, description: null,
start: startDate.toISOString(), start: startDate.toISOString(),
end: endDate.toISOString(), end: endDate.toISOString(),
allDay: selectInfo.allDay, allDay: selectInfo.allDay || false,
location: null, location: null,
calendarId: firstCalendar.id calendarId: calendarToUse
}); });
} else {
setEventForm({
title: "",
description: null,
start: startDate.toISOString(),
end: endDate.toISOString(),
allDay: selectInfo.allDay,
location: null,
calendarId: selectedCalendarId
});
}
setIsEventModalOpen(true); setIsEventModalOpen(true);
}; };
@ -1085,6 +1072,15 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
const startDate = new Date(event.start); const startDate = new Date(event.start);
const endDate = new Date(event.end || event.start); const endDate = new Date(event.end || event.start);
const eventCalendarId = event.extendedProps.calendarId;
const availableCalendars = getAvailableCalendars();
// Check if the event's calendar is still available for editing
const canEditEventCalendar = availableCalendars.some(cal => cal.id === eventCalendarId);
// If not available, use the first available calendar instead
const calendarIdToUse = canEditEventCalendar ? eventCalendarId : (availableCalendars[0]?.id || eventCalendarId);
setSelectedEvent(event.extendedProps.originalEvent); setSelectedEvent(event.extendedProps.originalEvent);
setEventForm({ setEventForm({
title: event.title, title: event.title,
@ -1093,7 +1089,7 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
end: endDate.toISOString().slice(0, 16), end: endDate.toISOString().slice(0, 16),
allDay: event.isAllDay, allDay: event.isAllDay,
location: event.extendedProps.location, location: event.extendedProps.location,
calendarId: event.extendedProps.calendarId, calendarId: calendarIdToUse,
}); });
setIsEventModalOpen(true); setIsEventModalOpen(true);
}; };
@ -1248,6 +1244,59 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
return calendar.name; return calendar.name;
}; };
// Check if user can create/edit events in a mission calendar
const canEditMissionCalendar = (calendar: CalendarWithMission): boolean => {
// If not a mission calendar, allow
if (!calendar.missionId || !calendar.mission) {
return true;
}
const mission = calendar.mission;
// Check if user is the creator
if (mission.creatorId === userId) {
return true;
}
// Check if user has one of the guardian roles
const guardianRoles = ['gardien-temps', 'gardien-parole', 'gardien-memoire'];
const userMissionRole = mission.missionUsers?.find(
mu => mu.userId === userId && guardianRoles.includes(mu.role)
);
return !!userMissionRole;
};
// Get available calendars for event creation/editing
const getAvailableCalendars = (): CalendarWithMission[] => {
return calendars.filter(cal => {
const calWithMission = cal as CalendarWithMission;
// Always allow "Mon Calendrier"
if (cal.name === "Mon Calendrier") {
return true;
}
// Always allow Microsoft synced calendars
if (calWithMission.syncConfig?.syncEnabled && calWithMission.syncConfig?.mailCredential) {
return true;
}
// Always allow group calendars
if (cal.name?.startsWith("Groupe:")) {
return true;
}
// For mission calendars, check permissions
if (cal.name?.startsWith("Mission:")) {
return canEditMissionCalendar(calWithMission);
}
// Allow other calendars by default
return true;
});
};
// Update CalendarSelector to handle visibility - displayed as a left column // Update CalendarSelector to handle visibility - displayed as a left column
const CalendarSelector = () => ( const CalendarSelector = () => (
<div className="flex flex-col gap-2 mb-4"> <div className="flex flex-col gap-2 mb-4">
@ -1892,8 +1941,9 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
<div className="space-y-2"> <div className="space-y-2">
<Label className="text-base font-semibold text-gray-800">Calendrier</Label> <Label className="text-base font-semibold text-gray-800">Calendrier</Label>
<div className="grid grid-cols-2 gap-2"> <ScrollArea className="max-h-64 border border-gray-200 rounded-lg">
{calendars.map((cal) => { <div className="space-y-1 p-2">
{getAvailableCalendars().map((cal) => {
const calWithMission = cal as CalendarWithMission; const calWithMission = cal as CalendarWithMission;
const label = getCalendarDisplayName(calWithMission); const label = getCalendarDisplayName(calWithMission);
return ( return (
@ -1906,17 +1956,17 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
calendarId: cal.id calendarId: cal.id
})); }));
}} }}
className={`flex items-center gap-2 px-3 py-2 rounded-lg transition-all ${ className={`w-full flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all text-left ${
eventForm.calendarId === cal.id eventForm.calendarId === cal.id
? 'bg-white ring-2 ring-primary' ? 'bg-blue-50 ring-2 ring-blue-500 border border-blue-200'
: 'bg-white hover:bg-gray-50 border border-gray-200' : 'bg-white hover:bg-gray-50 border border-gray-200'
}`} }`}
> >
<div <div
className="w-3 h-3 rounded-full" className="w-4 h-4 rounded-full flex-shrink-0"
style={{ backgroundColor: cal.color }} style={{ backgroundColor: cal.color }}
/> />
<span className={`text-sm ${ <span className={`text-sm flex-1 ${
eventForm.calendarId === cal.id eventForm.calendarId === cal.id
? 'font-medium text-gray-900' ? 'font-medium text-gray-900'
: 'text-gray-700' : 'text-gray-700'
@ -1924,13 +1974,18 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
{label} {label}
</span> </span>
{calWithMission.syncConfig?.syncEnabled && ( {calWithMission.syncConfig?.syncEnabled && (
<Badge variant="outline" className="ml-auto text-[10px] px-1 py-0.5 border-blue-400 text-blue-600"> <Badge variant="outline" className="text-[10px] px-1.5 py-0.5 border-blue-400 text-blue-600 flex-shrink-0">
Sync Sync
</Badge> </Badge>
)} )}
{eventForm.calendarId === cal.id && (
<Check className="w-4 h-4 text-blue-600 flex-shrink-0" />
)}
</button> </button>
);})} );
})}
</div> </div>
</ScrollArea>
</div> </div>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">