vision refactor
This commit is contained in:
parent
b5e05bdd81
commit
6eb510e7d7
@ -12,6 +12,20 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import DatePicker, { registerLocale } from "react-datepicker";
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
import { fr } from "date-fns/locale";
|
||||
|
||||
registerLocale('fr', fr);
|
||||
|
||||
interface Group {
|
||||
id: string;
|
||||
@ -56,16 +70,24 @@ export default function VisionPage() {
|
||||
type: "group" | "mission" | "";
|
||||
entityId: string;
|
||||
entityName: string;
|
||||
date: string;
|
||||
time: string;
|
||||
title: string;
|
||||
start: string;
|
||||
end: string;
|
||||
allDay: boolean;
|
||||
location: string;
|
||||
description: string;
|
||||
recurrence: "none" | "daily" | "weekly" | "monthly";
|
||||
}>({
|
||||
type: "",
|
||||
entityId: "",
|
||||
entityName: "",
|
||||
date: "",
|
||||
time: "",
|
||||
title: "",
|
||||
start: "",
|
||||
end: "",
|
||||
allDay: false,
|
||||
location: "",
|
||||
description: "",
|
||||
recurrence: "none",
|
||||
});
|
||||
|
||||
// Redirect if not authenticated
|
||||
@ -186,22 +208,42 @@ export default function VisionPage() {
|
||||
return scheduledMeetings.filter(meeting => meeting.date === dateStr);
|
||||
};
|
||||
|
||||
// Helper function to get date from string
|
||||
const getDateFromString = (dateString: string): Date | null => {
|
||||
if (!dateString) return null;
|
||||
try {
|
||||
return new Date(dateString);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// Handle open meeting dialog
|
||||
const handleOpenMeetingDialog = (type: "group" | "mission", id: string, name: string) => {
|
||||
const defaultDate = selectedDate || new Date();
|
||||
const startDate = new Date(defaultDate);
|
||||
startDate.setHours(new Date().getHours(), 0, 0, 0);
|
||||
const endDate = new Date(startDate);
|
||||
endDate.setHours(startDate.getHours() + 1);
|
||||
|
||||
setMeetingForm({
|
||||
type,
|
||||
entityId: id,
|
||||
entityName: name,
|
||||
date: selectedDate ? selectedDate.toISOString().split('T')[0] : new Date().toISOString().split('T')[0],
|
||||
time: "",
|
||||
title: "",
|
||||
start: startDate.toISOString().slice(0, 16),
|
||||
end: endDate.toISOString().slice(0, 16),
|
||||
allDay: false,
|
||||
location: "",
|
||||
description: "",
|
||||
recurrence: "none",
|
||||
});
|
||||
setShowMeetingDialog(true);
|
||||
};
|
||||
|
||||
// Handle save meeting
|
||||
const handleSaveMeeting = () => {
|
||||
if (!meetingForm.type || !meetingForm.entityId || !meetingForm.date || !meetingForm.time) {
|
||||
if (!meetingForm.type || !meetingForm.entityId || !meetingForm.start || !meetingForm.end) {
|
||||
toast({
|
||||
title: "Erreur",
|
||||
description: "Veuillez remplir tous les champs requis",
|
||||
@ -210,29 +252,74 @@ export default function VisionPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
const newMeeting: ScheduledMeeting = {
|
||||
id: `${Date.now()}-${Math.random()}`,
|
||||
type: meetingForm.type,
|
||||
entityId: meetingForm.entityId,
|
||||
entityName: meetingForm.entityName,
|
||||
date: meetingForm.date,
|
||||
time: meetingForm.time,
|
||||
title: meetingForm.title || `${meetingForm.type === "group" ? "Groupe" : "Mission"}: ${meetingForm.entityName}`,
|
||||
};
|
||||
const startDate = new Date(meetingForm.start);
|
||||
const endDate = new Date(meetingForm.end);
|
||||
|
||||
// Create meetings based on recurrence
|
||||
const meetings: ScheduledMeeting[] = [];
|
||||
|
||||
if (meetingForm.recurrence === "none") {
|
||||
// Single meeting
|
||||
const dateStr = startDate.toISOString().split('T')[0];
|
||||
const timeStr = meetingForm.allDay ? "" : startDate.toTimeString().slice(0, 5);
|
||||
|
||||
meetings.push({
|
||||
id: `${Date.now()}-${Math.random()}`,
|
||||
type: meetingForm.type,
|
||||
entityId: meetingForm.entityId,
|
||||
entityName: meetingForm.entityName,
|
||||
date: dateStr,
|
||||
time: timeStr,
|
||||
title: meetingForm.title || `${meetingForm.type === "group" ? "Groupe" : "Mission"}: ${meetingForm.entityName}`,
|
||||
});
|
||||
} else {
|
||||
// Recurring meetings - create for next 12 occurrences
|
||||
const recurrenceCount = 12;
|
||||
let currentDate = new Date(startDate);
|
||||
const timeDiff = endDate.getTime() - startDate.getTime();
|
||||
|
||||
for (let i = 0; i < recurrenceCount; i++) {
|
||||
const dateStr = currentDate.toISOString().split('T')[0];
|
||||
const timeStr = meetingForm.allDay ? "" : currentDate.toTimeString().slice(0, 5);
|
||||
|
||||
meetings.push({
|
||||
id: `${Date.now()}-${i}-${Math.random()}`,
|
||||
type: meetingForm.type,
|
||||
entityId: meetingForm.entityId,
|
||||
entityName: meetingForm.entityName,
|
||||
date: dateStr,
|
||||
time: timeStr,
|
||||
title: meetingForm.title || `${meetingForm.type === "group" ? "Groupe" : "Mission"}: ${meetingForm.entityName}`,
|
||||
});
|
||||
|
||||
// Calculate next occurrence
|
||||
if (meetingForm.recurrence === "daily") {
|
||||
currentDate.setDate(currentDate.getDate() + 1);
|
||||
} else if (meetingForm.recurrence === "weekly") {
|
||||
currentDate.setDate(currentDate.getDate() + 7);
|
||||
} else if (meetingForm.recurrence === "monthly") {
|
||||
currentDate.setMonth(currentDate.getMonth() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setScheduledMeetings([...scheduledMeetings, newMeeting]);
|
||||
setScheduledMeetings([...scheduledMeetings, ...meetings]);
|
||||
setShowMeetingDialog(false);
|
||||
setMeetingForm({
|
||||
type: "",
|
||||
entityId: "",
|
||||
entityName: "",
|
||||
date: "",
|
||||
time: "",
|
||||
title: "",
|
||||
start: "",
|
||||
end: "",
|
||||
allDay: false,
|
||||
location: "",
|
||||
description: "",
|
||||
recurrence: "none",
|
||||
});
|
||||
toast({
|
||||
title: "Succès",
|
||||
description: "Réunion planifiée avec succès",
|
||||
description: `${meetings.length} réunion${meetings.length > 1 ? 's' : ''} planifiée${meetings.length > 1 ? 's' : ''} avec succès`,
|
||||
});
|
||||
};
|
||||
|
||||
@ -706,43 +793,177 @@ export default function VisionPage() {
|
||||
|
||||
{/* Meeting Dialog */}
|
||||
<Dialog open={showMeetingDialog} onOpenChange={setShowMeetingDialog}>
|
||||
<DialogContent className="sm:max-w-[500px]">
|
||||
<DialogContent className="sm:max-w-lg">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Planifier une réunion</DialogTitle>
|
||||
<DialogTitle className="text-gray-800">Planifier une réunion</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4 py-4">
|
||||
<div>
|
||||
<Label htmlFor="meeting-title">Titre (optionnel)</Label>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="meeting-title" className="text-base font-semibold text-gray-800">Titre</Label>
|
||||
<Input
|
||||
id="meeting-title"
|
||||
value={meetingForm.title}
|
||||
onChange={(e) => setMeetingForm({ ...meetingForm, title: e.target.value })}
|
||||
placeholder={`Réunion ${meetingForm.type === "group" ? "du groupe" : "de la mission"}`}
|
||||
className="mt-1 bg-black text-white border-gray-700 placeholder-gray-400"
|
||||
className="bg-white text-gray-900"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="meeting-date">Date *</Label>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-800">Début *</Label>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex-1">
|
||||
<DatePicker
|
||||
selected={getDateFromString(meetingForm.start)}
|
||||
onChange={(date: Date | null) => {
|
||||
if (date) {
|
||||
const newStart = new Date(date);
|
||||
if (!meetingForm.allDay) {
|
||||
const currentStart = getDateFromString(meetingForm.start);
|
||||
if (currentStart) {
|
||||
newStart.setHours(currentStart.getHours(), currentStart.getMinutes());
|
||||
}
|
||||
}
|
||||
setMeetingForm({ ...meetingForm, start: newStart.toISOString().slice(0, 16) });
|
||||
}
|
||||
}}
|
||||
dateFormat="dd/MM/yyyy"
|
||||
locale="fr"
|
||||
className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary bg-white text-gray-900"
|
||||
placeholderText="Date"
|
||||
customInput={<Input className="bg-white text-gray-900" />}
|
||||
/>
|
||||
</div>
|
||||
{!meetingForm.allDay && (
|
||||
<DatePicker
|
||||
selected={getDateFromString(meetingForm.start)}
|
||||
onChange={(date: Date | null) => {
|
||||
if (date) {
|
||||
const currentStart = getDateFromString(meetingForm.start) || new Date();
|
||||
const newStart = new Date(currentStart);
|
||||
newStart.setHours(date.getHours(), date.getMinutes());
|
||||
setMeetingForm({ ...meetingForm, start: newStart.toISOString().slice(0, 16) });
|
||||
}
|
||||
}}
|
||||
showTimeSelect
|
||||
showTimeSelectOnly
|
||||
timeIntervals={15}
|
||||
timeCaption="Heure"
|
||||
dateFormat="HH:mm"
|
||||
className="w-32 bg-white text-gray-900"
|
||||
customInput={<Input className="bg-white text-gray-900" />}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-800">Fin *</Label>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex-1">
|
||||
<DatePicker
|
||||
selected={getDateFromString(meetingForm.end)}
|
||||
onChange={(date: Date | null) => {
|
||||
if (date) {
|
||||
const newEnd = new Date(date);
|
||||
if (!meetingForm.allDay) {
|
||||
const currentEnd = getDateFromString(meetingForm.end);
|
||||
if (currentEnd) {
|
||||
newEnd.setHours(currentEnd.getHours(), currentEnd.getMinutes());
|
||||
}
|
||||
}
|
||||
setMeetingForm({ ...meetingForm, end: newEnd.toISOString().slice(0, 16) });
|
||||
}
|
||||
}}
|
||||
dateFormat="dd/MM/yyyy"
|
||||
locale="fr"
|
||||
className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary bg-white text-gray-900"
|
||||
placeholderText="Date"
|
||||
customInput={<Input className="bg-white text-gray-900" />}
|
||||
minDate={getDateFromString(meetingForm.start)}
|
||||
/>
|
||||
</div>
|
||||
{!meetingForm.allDay && (
|
||||
<DatePicker
|
||||
selected={getDateFromString(meetingForm.end)}
|
||||
onChange={(date: Date | null) => {
|
||||
if (date) {
|
||||
const currentEnd = getDateFromString(meetingForm.end) || new Date();
|
||||
const newEnd = new Date(currentEnd);
|
||||
newEnd.setHours(date.getHours(), date.getMinutes());
|
||||
setMeetingForm({ ...meetingForm, end: newEnd.toISOString().slice(0, 16) });
|
||||
}
|
||||
}}
|
||||
showTimeSelect
|
||||
showTimeSelectOnly
|
||||
timeIntervals={15}
|
||||
timeCaption="Heure"
|
||||
dateFormat="HH:mm"
|
||||
className="w-32 bg-white text-gray-900"
|
||||
customInput={<Input className="bg-white text-gray-900" />}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="allDay"
|
||||
checked={meetingForm.allDay}
|
||||
onCheckedChange={(checked) =>
|
||||
setMeetingForm({ ...meetingForm, allDay: checked as boolean })
|
||||
}
|
||||
/>
|
||||
<Label htmlFor="allDay" className="text-gray-800">Toute la journée</Label>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-800">Lieu</Label>
|
||||
<Input
|
||||
id="meeting-date"
|
||||
type="date"
|
||||
value={meetingForm.date}
|
||||
onChange={(e) => setMeetingForm({ ...meetingForm, date: e.target.value })}
|
||||
className="mt-1 bg-black text-white border-gray-700"
|
||||
required
|
||||
value={meetingForm.location}
|
||||
onChange={(e) =>
|
||||
setMeetingForm({ ...meetingForm, location: e.target.value })
|
||||
}
|
||||
placeholder="Ajouter un lieu"
|
||||
className="bg-white text-gray-900"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="meeting-time">Heure *</Label>
|
||||
<Input
|
||||
id="meeting-time"
|
||||
type="time"
|
||||
value={meetingForm.time}
|
||||
onChange={(e) => setMeetingForm({ ...meetingForm, time: e.target.value })}
|
||||
className="mt-1 bg-black text-white border-gray-700"
|
||||
required
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-800">Description</Label>
|
||||
<Textarea
|
||||
value={meetingForm.description}
|
||||
onChange={(e) =>
|
||||
setMeetingForm({ ...meetingForm, description: e.target.value })
|
||||
}
|
||||
placeholder="Ajouter une description"
|
||||
className="bg-white text-gray-900"
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-800">Récurrence</Label>
|
||||
<Select
|
||||
value={meetingForm.recurrence}
|
||||
onValueChange={(value: "none" | "daily" | "weekly" | "monthly") =>
|
||||
setMeetingForm({ ...meetingForm, recurrence: value })
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="w-full bg-white text-gray-900">
|
||||
<SelectValue placeholder="Sélectionner une récurrence" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="none">Aucune récurrence</SelectItem>
|
||||
<SelectItem value="daily">Tous les jours</SelectItem>
|
||||
<SelectItem value="weekly">Toutes les semaines</SelectItem>
|
||||
<SelectItem value="monthly">Tous les mois</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="bg-gray-50 p-3 rounded-lg">
|
||||
<p className="text-sm text-gray-600">
|
||||
<strong>{meetingForm.type === "group" ? "Groupe" : "Mission"}:</strong> {meetingForm.entityName}
|
||||
@ -751,18 +972,23 @@ export default function VisionPage() {
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
setShowMeetingDialog(false);
|
||||
setMeetingForm({
|
||||
type: "",
|
||||
entityId: "",
|
||||
entityName: "",
|
||||
date: "",
|
||||
time: "",
|
||||
title: "",
|
||||
start: "",
|
||||
end: "",
|
||||
allDay: false,
|
||||
location: "",
|
||||
description: "",
|
||||
recurrence: "none",
|
||||
});
|
||||
}}
|
||||
className="bg-black text-white hover:bg-gray-900 border border-black"
|
||||
className="bg-white hover:bg-gray-50 text-gray-900 border-gray-200"
|
||||
>
|
||||
Annuler
|
||||
</Button>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user