254 lines
8.5 KiB
TypeScript
254 lines
8.5 KiB
TypeScript
import { getLocalTimeZone, parseDate, today } from "@internationalized/date";
|
|
import { Button } from "@ui/components/ui/button";
|
|
import { DatePicker } from "@ui/components/ui/date-picker";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@ui/components/ui/dialog";
|
|
import { Input } from "@ui/components/ui/input";
|
|
import { Label } from "@ui/components/ui/label";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@ui/components/ui/select";
|
|
import { Textarea } from "@ui/components/ui/textarea";
|
|
import { TimeInput } from "@ui/components/ui/time-input";
|
|
import { useCreateEvents, useEvent, useUpdateEvent } from "@ui/hooks/events";
|
|
import { useTablosList } from "@ui/hooks/tablos";
|
|
import { useUser } from "@ui/providers/UserStoreProvider";
|
|
import { Event, EventInsert } from "@ui/types/events.types";
|
|
import { useEffect, useState } from "react";
|
|
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
|
|
|
|
export const EventModal = ({ mode }: { mode: "create" | "edit" }) => {
|
|
const { event_id } = useParams();
|
|
const { data: event } = useEvent(event_id as string);
|
|
|
|
const user = useUser();
|
|
const [searchParams] = useSearchParams();
|
|
const tablo_id = searchParams.get("tablo_id");
|
|
const dateFromParams = searchParams.get("date");
|
|
const date = dateFromParams ? new Date(dateFromParams) : new Date();
|
|
|
|
const { data: tablos, isLoading: tablosLoading } = useTablosList();
|
|
const createEvents = useCreateEvents();
|
|
const updateEvent = useUpdateEvent();
|
|
const navigate = useNavigate();
|
|
|
|
const onClose = () => {
|
|
navigate(-1);
|
|
};
|
|
|
|
// Get the local date string without timezone conversion
|
|
const getLocalDateString = (date: Date) => {
|
|
const year = date.getFullYear();
|
|
const month = (date.getMonth() + 1).toString().padStart(2, "0");
|
|
const day = date.getDate().toString().padStart(2, "0");
|
|
return `${year}-${month}-${day}`;
|
|
};
|
|
|
|
// Format time from Date to HH:MM string
|
|
const formatTimeFromDate = (date: Date, addMinutes: number = 0): string => {
|
|
const hours = date.getHours();
|
|
const minutes = date.getMinutes() + addMinutes;
|
|
const totalMinutes = hours * 60 + minutes;
|
|
const finalHours = Math.floor(totalMinutes / 60) % 24;
|
|
const finalMinutes = totalMinutes % 60;
|
|
return `${finalHours.toString().padStart(2, "0")}:${finalMinutes.toString().padStart(2, "0")}`;
|
|
};
|
|
|
|
const [formEvent, setFormEvent] = useState<EventInsert>({
|
|
start_date: date ? getLocalDateString(date) : "",
|
|
start_time: date ? formatTimeFromDate(date) : "",
|
|
end_time: date ? formatTimeFromDate(date, 30) : "",
|
|
tablo_id: tablo_id || "",
|
|
title: "",
|
|
created_by: user.id,
|
|
});
|
|
|
|
// Initialize form data when in edit mode
|
|
useEffect(() => {
|
|
if (mode === "edit" && event) {
|
|
setFormEvent({
|
|
start_date: event.start_date,
|
|
start_time: event.start_time || "",
|
|
end_time: event.end_time || "",
|
|
tablo_id: event.tablo_id,
|
|
title: event.title,
|
|
description: event.description || "",
|
|
created_by: event.created_by,
|
|
});
|
|
}
|
|
}, [mode, event]);
|
|
|
|
return (
|
|
<Dialog open={true} onOpenChange={onClose}>
|
|
<DialogContent className="max-w-2xl">
|
|
<DialogHeader>
|
|
<DialogTitle>{mode === "edit" ? "Modifier l'événement" : "Nouvel événement"}</DialogTitle>
|
|
<DialogDescription>
|
|
{mode === "edit" && event
|
|
? new Date(event.start_date).toLocaleDateString("fr-FR", {
|
|
weekday: "long",
|
|
year: "numeric",
|
|
month: "long",
|
|
day: "numeric",
|
|
})
|
|
: date.toLocaleDateString("fr-FR", {
|
|
weekday: "long",
|
|
year: "numeric",
|
|
month: "long",
|
|
day: "numeric",
|
|
})}
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="space-y-4">
|
|
{/* Title Input */}
|
|
<div className="space-y-2">
|
|
<Label htmlFor="event-title">Titre *</Label>
|
|
<Input
|
|
id="event-title"
|
|
type="text"
|
|
value={formEvent?.title}
|
|
onChange={(e) =>
|
|
setFormEvent({
|
|
...formEvent,
|
|
title: e.target.value,
|
|
} as Event)
|
|
}
|
|
placeholder="Ajouter un titre"
|
|
autoFocus
|
|
/>
|
|
</div>
|
|
|
|
{/* Tablo Selection */}
|
|
<div className="space-y-2">
|
|
<Label htmlFor="event-tablo">Tablo *</Label>
|
|
<Select
|
|
value={formEvent?.tablo_id}
|
|
onValueChange={(value) =>
|
|
setFormEvent({
|
|
...formEvent,
|
|
tablo_id: value,
|
|
} as Event)
|
|
}
|
|
disabled={tablosLoading}
|
|
>
|
|
<SelectTrigger id="event-tablo" className="w-full">
|
|
<SelectValue placeholder="Sélectionner un tablo" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{tablos?.map((tablo) => (
|
|
<SelectItem key={tablo.id} value={tablo.id}>
|
|
{tablo.name}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-3 gap-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="event-date">Date *</Label>
|
|
<DatePicker
|
|
aria-label="Date de l'événement"
|
|
value={formEvent?.start_date ? parseDate(formEvent?.start_date) : undefined}
|
|
minValue={today(getLocalTimeZone())}
|
|
onChange={(date) => {
|
|
if (date) {
|
|
// Convert Date to YYYY-MM-DD format
|
|
const year = date.getFullYear();
|
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
const day = String(date.getDate()).padStart(2, "0");
|
|
setFormEvent({
|
|
...formEvent,
|
|
start_date: `${year}-${month}-${day}`,
|
|
});
|
|
}
|
|
}}
|
|
buttonClassName="h-10 w-full"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="event-start-time">Début *</Label>
|
|
<TimeInput
|
|
value={formEvent?.start_time || undefined}
|
|
onChange={(value) => {
|
|
setFormEvent({
|
|
...formEvent,
|
|
start_time: value,
|
|
});
|
|
}}
|
|
className="w-full"
|
|
id="event-start-time"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="event-end-time">Fin</Label>
|
|
<TimeInput
|
|
value={formEvent?.end_time || undefined}
|
|
onChange={(value) => {
|
|
setFormEvent({
|
|
...formEvent,
|
|
end_time: value,
|
|
});
|
|
}}
|
|
className="w-full"
|
|
id="event-end-time"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Description */}
|
|
<div className="space-y-2">
|
|
<Label htmlFor="event-description">Description</Label>
|
|
<Textarea
|
|
id="event-description"
|
|
value={formEvent?.description ?? ""}
|
|
onChange={(e) =>
|
|
setFormEvent({
|
|
...formEvent,
|
|
description: e.target.value,
|
|
} as Event)
|
|
}
|
|
rows={3}
|
|
placeholder="Ajouter une description (optionnel)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<DialogFooter>
|
|
<Button variant="outline" onClick={onClose}>
|
|
Annuler
|
|
</Button>
|
|
<Button
|
|
onClick={() => {
|
|
const eventName = formEvent?.title.trim() || "(Sans titre)";
|
|
if (mode === "edit" && event) {
|
|
updateEvent.mutate(
|
|
{ id: event.id, ...formEvent, title: eventName },
|
|
{ onSuccess: () => onClose() }
|
|
);
|
|
} else {
|
|
createEvents({ ...formEvent, title: eventName }, { onSuccess: () => onClose() });
|
|
}
|
|
}}
|
|
disabled={!formEvent?.tablo_id}
|
|
>
|
|
{mode === "edit" ? "Modifier" : "Enregistrer"}
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
};
|