Files
latosa-escrima/frontend/components/planning.tsx
2025-02-13 11:16:09 +01:00

295 lines
7.8 KiB
TypeScript

"use client";
import { ApiResponse } from "@/types/types";
import request from "@/lib/request";
import "@schedule-x/theme-shadcn/dist/index.css";
import { useNextCalendarApp, ScheduleXCalendar } from "@schedule-x/react";
import { createEventsServicePlugin } from "@schedule-x/events-service";
import { createDragAndDropPlugin } from "@schedule-x/drag-and-drop";
import { createResizePlugin } from "@schedule-x/resize";
import { createEventRecurrencePlugin } from "@schedule-x/event-recurrence";
import { createViewDay, createViewWeek } from "@schedule-x/calendar";
import { useEffect, useState } from "react";
import { format } from "date-fns";
import { Dialog, DialogProps } from "@radix-ui/react-dialog";
import {
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { KeyedMutator } from "swr";
import { getCookie } from "cookies-next";
import { useTheme } from "next-themes";
import { EventForm, EventFormValues } from "./event-dialog";
import ICalendarEvent from "@/interfaces/ICalendarEvent";
import { UseFormReturn } from "react-hook-form";
import mapFrequencyToRrule from "@/lib/mapFrequencyToRrule";
const Planning: React.FC<{
events: ICalendarEvent[];
mutate?: KeyedMutator<ApiResponse<ICalendarEvent[]>>;
}> = ({ events, mutate }) => {
const { resolvedTheme } = useTheme();
console.log(resolvedTheme);
const isConnected = getCookie("auth_token");
const plugins = isConnected
? [
createEventsServicePlugin(),
createDragAndDropPlugin(),
createResizePlugin(),
createEventRecurrencePlugin(),
]
: [];
const [eventSelected, setEventSelected] = useState<ICalendarEvent | null>(
null,
);
const [newEvent, setNewEvent] = useState<Omit<ICalendarEvent, "id"> | null>(
null,
);
const handleEventUpdate = async (
eventSelected: ICalendarEvent | Omit<ICalendarEvent, "id">,
) => {
const event = {
...eventSelected,
start: `${new Date(eventSelected.start).toISOString()}`,
end: `${new Date(eventSelected.end).toISOString()}`,
} as ICalendarEvent;
try {
const res = await request<undefined>(`/events/${event.id}/update`, {
method: "PATCH",
body: event,
requiresAuth: true,
csrfToken: false,
});
if (res.status === "Error") {
// calendar?.events?.update(oldEvent);
} else {
mutate?.();
}
} catch (e) {
console.log(e);
}
};
const calendar = useNextCalendarApp(
{
theme: "shadcn",
views: [createViewDay(), createViewWeek()],
defaultView: "week",
isDark: resolvedTheme === "dark" ? true : false,
isResponsive: true,
locale: "fr-FR",
dayBoundaries: {
start: "06:00",
end: "00:00",
},
events: events.map((event) => ({
...event,
start: format(new Date(event.start), "yyyy-MM-dd HH:mm"),
end: format(new Date(event.end), "yyyy-MM-dd HH:mm"),
})),
callbacks: {
onEventClick(event, e) {
setEventSelected(event as ICalendarEvent);
},
async onEventUpdate(newEvent) {
await handleEventUpdate(newEvent as ICalendarEvent);
},
},
},
plugins,
);
useEffect(() => {
calendar?.events.getAll();
}, []);
useEffect(() => {
calendar?.setTheme(resolvedTheme === "dark" ? "dark" : "light");
}, [resolvedTheme]);
const AddButton: React.FC = () => (
<Button onClick={() => setNewEvent({})} variant="outline">
Nouveau
</Button>
);
return (
<div>
<div className="m-8">
<AddButton />
<ScheduleXCalendar calendarApp={calendar} />
</div>
{newEvent && (
<EventDialog
open={newEvent !== null || false}
onOpenChange={(open) => {
setNewEvent((e) => (open ? e : null));
}}
onAdd={async (formValues) => {
const rrule = mapFrequencyToRrule(
formValues.frequency,
formValues.frequencyEndDate,
);
const [sHours, sMinutes] =
formValues.startTime.split(":");
formValues.startDate.setHours(
parseInt(sHours),
parseInt(sMinutes),
);
const [eHours, eMinutes] =
formValues.endTime.split(":");
formValues.endDate.setHours(
parseInt(eHours),
parseInt(eMinutes),
);
console.log(formValues.endDate);
const event: Omit<ICalendarEvent, "id"> = {
...newEvent,
start: formValues.startDate.toISOString(),
end: formValues.endDate.toISOString(),
title: `${formValues.title}`,
fullday: formValues.fullDay,
rrule: rrule,
isVisible: formValues.isVisible,
};
const res = await request<undefined>(`/events/new`, {
method: "POST",
body: event,
requiresAuth: true,
csrfToken: false,
});
if (res.status === "Error") {
console.log("Error");
}
if (res.status === "Success") {
mutate?.();
console.log("Success");
}
}}
event={newEvent}
/>
)}
{eventSelected && (
<EventDialog
open={eventSelected !== null || false}
onOpenChange={(open) => {
setEventSelected((e) => (open ? e : null));
}}
event={eventSelected}
onDelete={async (id) => {
calendar?.events?.remove(id);
try {
const res = await request<undefined>(
`/events/${id}/delete`,
{
method: "DELETE",
requiresAuth: true,
csrfToken: false,
},
);
if (res.status === "Error") {
console.log("Error");
}
if (res.status === "Success") {
console.log("Success");
}
} catch (e) {
console.log(e);
}
setEventSelected(null);
}}
onUpdate={async (formValues) => {
const rrule = mapFrequencyToRrule(
formValues.frequency,
formValues.frequencyEndDate,
);
const [sHours, sMinutes] =
formValues.startTime.split(":");
formValues.startDate.setHours(
parseInt(sHours),
parseInt(sMinutes),
);
const [eHours, eMinutes] =
formValues.endTime.split(":");
formValues.endDate.setHours(
parseInt(eHours),
parseInt(eMinutes),
);
const event: ICalendarEvent = {
...eventSelected,
start: formValues.startDate.toISOString(),
end: formValues.endDate.toISOString(),
title: `${formValues.title}`,
fullday: formValues.fullDay,
rrule: rrule,
isVisible: formValues.isVisible,
};
await handleEventUpdate(event);
setEventSelected(null);
}}
/>
)}
</div>
);
};
const EventDialog: React.FC<
{
onDelete?: (id: string) => void;
onUpdate?: (formValues: EventFormValues) => void;
onAdd?: (formValues: EventFormValues) => void;
event: ICalendarEvent | Omit<ICalendarEvent, "id">;
} & DialogProps
> = ({ open, onOpenChange, onDelete, onUpdate, onAdd, event }) => {
const [form, setForm] = useState<UseFormReturn<EventFormValues>>();
const submitForm = (event: "add" | "update") => {
const callback = event === "add" ? onAdd : onUpdate;
if (callback) form?.handleSubmit(callback)();
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle>{event.title}</DialogTitle>
<DialogDescription>{event.description}</DialogDescription>
</DialogHeader>
<EventForm event={event} setForm={setForm} />
<DialogFooter className="flex flex-row justify-end">
{onUpdate && (
<Button
variant="outline"
onClick={() => submitForm("update")}
type="submit"
>
Actualiser
</Button>
)}
{onDelete && (
<Button
variant="destructive"
onClick={() => onDelete(event.id)}
type="submit"
>
Supprimer
</Button>
)}
{onAdd && !onUpdate && !onDelete && (
<Button onClick={() => submitForm("add")} type="submit">
Créer
</Button>
)}
</DialogFooter>
</DialogContent>
</Dialog>
);
};
export default Planning;