Agenda refactor

This commit is contained in:
alma 2026-01-15 18:16:15 +01:00
parent 986f66ac92
commit d8846524f0
3 changed files with 132 additions and 50 deletions

View File

@ -647,6 +647,37 @@ export default async function CalendarPage() {
} }
}); });
// Sort calendars: "Mon Calendrier" first, then synced, then groups, then missions
calendars = calendars.sort((a, b) => {
const aIsMonCalendrier = a.name === "Mon Calendrier";
const bIsMonCalendrier = b.name === "Mon Calendrier";
const aIsSynced = a.syncConfig?.syncEnabled && a.syncConfig?.mailCredential;
const bIsSynced = b.syncConfig?.syncEnabled && b.syncConfig?.mailCredential;
const aIsGroup = a.name?.startsWith("Groupe:");
const bIsGroup = b.name?.startsWith("Groupe:");
const aIsMission = a.name?.startsWith("Mission:");
const bIsMission = b.name?.startsWith("Mission:");
// "Mon Calendrier" always first
if (aIsMonCalendrier && !bIsMonCalendrier) return -1;
if (!aIsMonCalendrier && bIsMonCalendrier) return 1;
// Synced calendars second
if (aIsSynced && !bIsSynced) return -1;
if (!aIsSynced && bIsSynced) return 1;
// Groups third
if (aIsGroup && !bIsGroup && !bIsSynced) return -1;
if (!aIsGroup && bIsGroup && !aIsSynced) return 1;
// Missions fourth
if (aIsMission && !bIsMission && !bIsGroup && !bIsSynced) return -1;
if (!aIsMission && bIsMission && !aIsGroup && !aIsSynced) return 1;
// Same type, sort by name
return (a.name || '').localeCompare(b.name || '');
});
const now = new Date(); const now = new Date();
const nextWeek = add(now, { days: 7 }); const nextWeek = add(now, { days: 7 });

View File

@ -169,18 +169,49 @@ export async function GET(req: NextRequest) {
new Map(calendars.map(cal => [cal.id, cal])).values() new Map(calendars.map(cal => [cal.id, cal])).values()
); );
// Sort calendars: "Mon Calendrier" first, then synced, then groups, then missions
const sortedCalendars = uniqueCalendars.sort((a, b) => {
const aIsMonCalendrier = a.name === "Mon Calendrier";
const bIsMonCalendrier = b.name === "Mon Calendrier";
const aIsSynced = a.syncConfig?.syncEnabled && a.syncConfig?.mailCredential;
const bIsSynced = b.syncConfig?.syncEnabled && b.syncConfig?.mailCredential;
const aIsGroup = a.name?.startsWith("Groupe:");
const bIsGroup = b.name?.startsWith("Groupe:");
const aIsMission = a.name?.startsWith("Mission:");
const bIsMission = b.name?.startsWith("Mission:");
// "Mon Calendrier" always first
if (aIsMonCalendrier && !bIsMonCalendrier) return -1;
if (!aIsMonCalendrier && bIsMonCalendrier) return 1;
// Synced calendars second
if (aIsSynced && !bIsSynced) return -1;
if (!aIsSynced && bIsSynced) return 1;
// Groups third
if (aIsGroup && !bIsGroup && !bIsSynced) return -1;
if (!aIsGroup && bIsGroup && !aIsSynced) return 1;
// Missions fourth
if (aIsMission && !bIsMission && !bIsGroup && !bIsSynced) return -1;
if (!aIsMission && bIsMission && !aIsGroup && !aIsSynced) return 1;
// Same type, sort by name
return (a.name || '').localeCompare(b.name || '');
});
logger.debug('[CALENDAR] Fetched calendars with events', { logger.debug('[CALENDAR] Fetched calendars with events', {
userId: session.user.id, userId: session.user.id,
personalCount: filteredPersonalCalendars.length, personalCount: filteredPersonalCalendars.length,
missionCount: missionCalendars.length, missionCount: missionCalendars.length,
totalCount: uniqueCalendars.length, totalCount: sortedCalendars.length,
filteredOut: personalCalendars.length - filteredPersonalCalendars.length, filteredOut: personalCalendars.length - filteredPersonalCalendars.length,
}); });
// Cache the results // Cache the results
await cacheCalendarData(session.user.id, uniqueCalendars); await cacheCalendarData(session.user.id, sortedCalendars);
return NextResponse.json(uniqueCalendars); return NextResponse.json(sortedCalendars);
} catch (error) { } catch (error) {
logger.error('[CALENDAR] Erreur lors de la récupération des calendriers', { logger.error('[CALENDAR] Erreur lors de la récupération des calendriers', {
error: error instanceof Error ? error.message : String(error), error: error instanceof Error ? error.message : String(error),

View File

@ -255,15 +255,16 @@ function CalendarDialog({ open, onClose, onSave, onDelete, onSyncSetup, initialD
setIsSubmitting(true); setIsSubmitting(true);
try { try {
// Only update color, preserve name and description from initialData
await onSave({ await onSave({
id: initialData?.id, id: initialData?.id,
name, name: initialData?.name || name, // Keep original name
color, color, // Only color can be changed
description description: initialData?.description || description // Keep original description
}); });
resetForm(); resetForm();
} catch (error) { } catch (error) {
console.error("Erreur lors de la création du calendrier:", error); console.error("Erreur lors de la mise à jour du calendrier:", error);
} finally { } finally {
setIsSubmitting(false); setIsSubmitting(false);
} }
@ -301,12 +302,24 @@ function CalendarDialog({ open, onClose, onSave, onDelete, onSyncSetup, initialD
<DialogHeader> <DialogHeader>
<DialogTitle className="flex items-center text-xl font-semibold text-gray-900"> <DialogTitle className="flex items-center text-xl font-semibold text-gray-900">
<CalendarIcon className="w-5 h-5 mr-2 text-indigo-600" /> <CalendarIcon className="w-5 h-5 mr-2 text-indigo-600" />
{initialData?.id ? "Modifier le calendrier" : "Créer un nouveau calendrier"} {initialData?.id ? "Paramètres du calendrier" : "Créer un nouveau calendrier"}
</DialogTitle> </DialogTitle>
</DialogHeader> </DialogHeader>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<div className="space-y-5 py-4"> <div className="space-y-5 py-4">
{/* Display calendar name (read-only) */}
{initialData?.id && (
<div className="space-y-2">
<Label className="text-gray-700">Nom</Label>
<div className="px-3 py-2 bg-gray-50 rounded-lg text-gray-900 border border-gray-200">
{initialData?.name || name}
</div>
</div>
)}
{/* Name input only for new calendars */}
{!initialData?.id && (
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="calendar-name" className="text-gray-700">Nom</Label> <Label htmlFor="calendar-name" className="text-gray-700">Nom</Label>
<Input <Input
@ -315,10 +328,10 @@ function CalendarDialog({ open, onClose, onSave, onDelete, onSyncSetup, initialD
onChange={(e) => setName(e.target.value)} onChange={(e) => setName(e.target.value)}
placeholder="Nom du calendrier" placeholder="Nom du calendrier"
required required
disabled={isMainCalendar || isMissionOrGroupCalendar}
className="rounded-lg border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 bg-white text-gray-900" className="rounded-lg border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 bg-white text-gray-900"
/> />
</div> </div>
)}
<div className="space-y-3"> <div className="space-y-3">
<Label className="text-gray-700">Couleur</Label> <Label className="text-gray-700">Couleur</Label>
@ -384,6 +397,18 @@ function CalendarDialog({ open, onClose, onSave, onDelete, onSyncSetup, initialD
)} )}
</div> </div>
{/* Display description (read-only) for existing calendars */}
{initialData?.id && initialData?.description && (
<div className="space-y-2">
<Label className="text-gray-700">Description</Label>
<div className="px-3 py-2 bg-gray-50 rounded-lg text-gray-700 border border-gray-200 text-sm">
{initialData?.description || description}
</div>
</div>
)}
{/* Description input only for new calendars */}
{!initialData?.id && (
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="calendar-description" className="text-gray-700"> <Label htmlFor="calendar-description" className="text-gray-700">
Description (optionnelle) Description (optionnelle)
@ -394,10 +419,10 @@ function CalendarDialog({ open, onClose, onSave, onDelete, onSyncSetup, initialD
onChange={(e) => setDescription(e.target.value)} onChange={(e) => setDescription(e.target.value)}
placeholder="Description du calendrier" placeholder="Description du calendrier"
rows={3} rows={3}
disabled={isMissionOrGroupCalendar}
className="rounded-lg border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 bg-white text-gray-900" className="rounded-lg border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 bg-white text-gray-900"
/> />
</div> </div>
)}
{/* Sync Section for Private Calendars */} {/* Sync Section for Private Calendars */}
{isPrivateCalendar && initialData?.id && ( {isPrivateCalendar && initialData?.id && (
@ -532,18 +557,7 @@ function CalendarDialog({ open, onClose, onSave, onDelete, onSyncSetup, initialD
</div> </div>
<DialogFooter className="mt-6 border-t border-gray-100 pt-4"> <DialogFooter className="mt-6 border-t border-gray-100 pt-4">
<div className="flex justify-between w-full"> <div className="flex justify-end w-full">
{initialData?.id && !isMainCalendar && !isMissionOrGroupCalendar && (
<Button
type="button"
variant="destructive"
onClick={handleDelete}
disabled={isSubmitting || isMainCalendar || isMissionOrGroupCalendar}
>
<X className="w-4 h-4 mr-2" />
Supprimer
</Button>
)}
<div className="flex gap-3"> <div className="flex gap-3">
<Button <Button
type="button" type="button"
@ -556,13 +570,13 @@ function CalendarDialog({ open, onClose, onSave, onDelete, onSyncSetup, initialD
</Button> </Button>
<Button <Button
type="submit" type="submit"
disabled={!name || isSubmitting || isMainCalendar || isMissionOrGroupCalendar} disabled={isSubmitting || (initialData?.id ? false : !name)}
className="rounded-lg bg-indigo-600 hover:bg-indigo-700 text-white" className="rounded-lg bg-indigo-600 hover:bg-indigo-700 text-white"
> >
{isSubmitting {isSubmitting
? "Enregistrement..." ? "Enregistrement..."
: initialData?.id : initialData?.id
? "Mettre à jour" ? "Mettre à jour la couleur"
: "Créer" : "Créer"
} }
</Button> </Button>
@ -720,10 +734,12 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
}); });
}; };
// Sort calendars: synced (courrier) first, then groups, then missions // Sort calendars: "Mon Calendrier" first, then synced (courrier), then groups, then missions
const sortCalendars = (cals: typeof initialCalendars) => { const sortCalendars = (cals: typeof initialCalendars) => {
const filtered = filterCalendars(cals); const filtered = filterCalendars(cals);
return [...filtered].sort((a, b) => { return [...filtered].sort((a, b) => {
const aIsMonCalendrier = a.name === "Mon Calendrier";
const bIsMonCalendrier = b.name === "Mon Calendrier";
const aIsSynced = a.syncConfig?.syncEnabled && a.syncConfig?.mailCredential; const aIsSynced = a.syncConfig?.syncEnabled && a.syncConfig?.mailCredential;
const bIsSynced = b.syncConfig?.syncEnabled && b.syncConfig?.mailCredential; const bIsSynced = b.syncConfig?.syncEnabled && b.syncConfig?.mailCredential;
const aIsGroup = a.name?.startsWith("Groupe:"); const aIsGroup = a.name?.startsWith("Groupe:");
@ -731,7 +747,11 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
const aIsMission = a.name?.startsWith("Mission:"); const aIsMission = a.name?.startsWith("Mission:");
const bIsMission = b.name?.startsWith("Mission:"); const bIsMission = b.name?.startsWith("Mission:");
// Synced calendars first // "Mon Calendrier" always first
if (aIsMonCalendrier && !bIsMonCalendrier) return -1;
if (!aIsMonCalendrier && bIsMonCalendrier) return 1;
// Synced calendars second
if (aIsSynced && !bIsSynced) return -1; if (aIsSynced && !bIsSynced) return -1;
if (!aIsSynced && bIsSynced) return 1; if (!aIsSynced && bIsSynced) return 1;