calendar 14

This commit is contained in:
Alma 2025-04-13 14:16:02 +02:00
parent 7dab3da369
commit 0d78cc4e6a
4 changed files with 112 additions and 44 deletions

View File

@ -149,31 +149,29 @@ export async function DELETE(
} }
try { try {
// Vérifier que le calendrier existe et appartient à l'utilisateur // Verify calendar ownership
const existingCalendar = await prisma.calendar.findUnique({ const calendar = await prisma.calendar.findFirst({
where: { where: {
id: params.id, id: params.id,
userId: session.user.username,
}, },
}); });
if (!existingCalendar) { if (!calendar) {
return NextResponse.json( return NextResponse.json(
{ error: "Calendrier non trouvé" }, { error: "Calendrier non trouvé ou non autorisé" },
{ status: 404 } { status: 404 }
); );
} }
if (existingCalendar.userId !== session.user.username) { // Delete the calendar (this will also delete all associated events due to the cascade delete)
return NextResponse.json({ error: "Non autorisé" }, { status: 403 });
}
await prisma.calendar.delete({ await prisma.calendar.delete({
where: { where: {
id: params.id, id: params.id,
}, },
}); });
return new NextResponse(null, { status: 204 }); return NextResponse.json({ success: true });
} catch (error) { } catch (error) {
console.error("Erreur lors de la suppression du calendrier:", error); console.error("Erreur lors de la suppression du calendrier:", error);
return NextResponse.json({ error: "Erreur serveur" }, { status: 500 }); return NextResponse.json({ error: "Erreur serveur" }, { status: 500 });

View File

@ -14,15 +14,17 @@ export async function DELETE(
} }
try { try {
// Verify event ownership // Verify event ownership through calendar
const event = await prisma.event.findFirst({ const event = await prisma.event.findFirst({
where: { where: {
id: params.id, id: params.id,
userId: session.user.username,
}, },
include: {
calendar: true
}
}); });
if (!event) { if (!event || event.calendar.userId !== session.user.username) {
return NextResponse.json( return NextResponse.json(
{ error: "Événement non trouvé ou non autorisé" }, { error: "Événement non trouvé ou non autorisé" },
{ status: 404 } { status: 404 }

View File

@ -44,8 +44,11 @@ export async function POST(req: NextRequest) {
end: new Date(end), end: new Date(end),
isAllDay: allDay || false, isAllDay: allDay || false,
location, location,
calendarId, calendar: {
userId: session.user.username, connect: {
id: calendarId
}
}
}, },
}); });
@ -74,15 +77,22 @@ export async function PUT(req: NextRequest) {
); );
} }
// Verify event ownership // Verify calendar ownership
const existingEvent = await prisma.event.findFirst({ const calendar = await prisma.calendar.findFirst({
where: { where: {
id, id: calendarId,
userId: session.user.username, userId: session.user.username,
}, },
include: {
events: {
where: {
id
}
}
}
}); });
if (!existingEvent) { if (!calendar || calendar.events.length === 0) {
return NextResponse.json( return NextResponse.json(
{ error: "Événement non trouvé ou non autorisé" }, { error: "Événement non trouvé ou non autorisé" },
{ status: 404 } { status: 404 }
@ -98,7 +108,11 @@ export async function PUT(req: NextRequest) {
end: new Date(end), end: new Date(end),
isAllDay: allDay || false, isAllDay: allDay || false,
location, location,
calendarId, calendar: {
connect: {
id: calendarId
}
}
}, },
}); });

View File

@ -79,10 +79,11 @@ interface CalendarDialogProps {
open: boolean; open: boolean;
onClose: () => void; onClose: () => void;
onSave: (calendarData: Partial<Calendar>) => Promise<void>; onSave: (calendarData: Partial<Calendar>) => Promise<void>;
onDelete?: (calendarId: string) => Promise<void>;
initialData?: Partial<Calendar>; initialData?: Partial<Calendar>;
} }
function CalendarDialog({ open, onClose, onSave, initialData }: CalendarDialogProps) { function CalendarDialog({ open, onClose, onSave, onDelete, initialData }: CalendarDialogProps) {
const [name, setName] = useState(initialData?.name || ""); const [name, setName] = useState(initialData?.name || "");
const [color, setColor] = useState(initialData?.color || "#4f46e5"); const [color, setColor] = useState(initialData?.color || "#4f46e5");
const [description, setDescription] = useState(initialData?.description || ""); const [description, setDescription] = useState(initialData?.description || "");
@ -117,6 +118,20 @@ function CalendarDialog({ open, onClose, onSave, initialData }: CalendarDialogPr
} }
}; };
const handleDelete = async () => {
if (!initialData?.id || !onDelete) return;
setIsSubmitting(true);
try {
await onDelete(initialData.id);
resetForm();
} catch (error) {
console.error("Erreur lors de la suppression du calendrier:", error);
} finally {
setIsSubmitting(false);
}
};
const resetForm = () => { const resetForm = () => {
setName(""); setName("");
setColor("#4f46e5"); setColor("#4f46e5");
@ -229,7 +244,19 @@ function CalendarDialog({ open, onClose, onSave, initialData }: CalendarDialogPr
</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 gap-3 w-full sm:justify-end"> <div className="flex justify-between w-full">
{initialData?.id && (
<Button
type="button"
variant="destructive"
onClick={handleDelete}
disabled={isSubmitting}
>
<X className="w-4 h-4 mr-2" />
Supprimer
</Button>
)}
<div className="flex gap-3">
<Button <Button
type="button" type="button"
variant="outline" variant="outline"
@ -237,7 +264,6 @@ function CalendarDialog({ open, onClose, onSave, initialData }: CalendarDialogPr
disabled={isSubmitting} disabled={isSubmitting}
className="rounded-lg border-gray-300 text-gray-700 hover:bg-gray-50" className="rounded-lg border-gray-300 text-gray-700 hover:bg-gray-50"
> >
<X className="w-4 h-4 mr-2" />
Annuler Annuler
</Button> </Button>
<Button <Button
@ -245,7 +271,6 @@ function CalendarDialog({ open, onClose, onSave, initialData }: CalendarDialogPr
disabled={!name || isSubmitting} disabled={!name || isSubmitting}
className="rounded-lg bg-indigo-600 hover:bg-indigo-700 text-white" className="rounded-lg bg-indigo-600 hover:bg-indigo-700 text-white"
> >
<Check className="w-4 h-4 mr-2" />
{isSubmitting {isSubmitting
? "Enregistrement..." ? "Enregistrement..."
: initialData?.id : initialData?.id
@ -254,6 +279,7 @@ function CalendarDialog({ open, onClose, onSave, initialData }: CalendarDialogPr
} }
</Button> </Button>
</div> </div>
</div>
</DialogFooter> </DialogFooter>
</form> </form>
</DialogContent> </DialogContent>
@ -494,6 +520,33 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
} }
}; };
const handleCalendarDelete = async (calendarId: string) => {
try {
setLoading(true);
const response = await fetch(`/api/calendars/${calendarId}`, {
method: "DELETE",
});
if (!response.ok) {
throw new Error("Failed to delete calendar");
}
await fetchCalendars();
setIsCalendarModalOpen(false);
// If the deleted calendar was selected, select another one
if (selectedCalendarId === calendarId) {
const remainingCalendars = calendars.filter(cal => cal.id !== calendarId);
setSelectedCalendarId(remainingCalendars[0]?.id || "");
}
} catch (error) {
console.error("Error deleting calendar:", error);
setError(error instanceof Error ? error.message : "Failed to delete calendar");
} finally {
setLoading(false);
}
};
const handleDateSelect = (selectInfo: any) => { const handleDateSelect = (selectInfo: any) => {
const startDate = new Date(selectInfo.start); const startDate = new Date(selectInfo.start);
const endDate = new Date(selectInfo.end); const endDate = new Date(selectInfo.end);
@ -730,6 +783,7 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
open={isCalendarModalOpen} open={isCalendarModalOpen}
onClose={() => setIsCalendarModalOpen(false)} onClose={() => setIsCalendarModalOpen(false)}
onSave={handleCalendarSave} onSave={handleCalendarSave}
onDelete={handleCalendarDelete}
initialData={selectedCalendar || undefined} initialData={selectedCalendar || undefined}
/> />