diff --git a/attached_assets/{2C3F5F28-2666-4611-A472-9594D2C098B3}_1755595272546.png b/attached_assets/{2C3F5F28-2666-4611-A472-9594D2C098B3}_1755595272546.png new file mode 100644 index 0000000..2d1e100 Binary files /dev/null and b/attached_assets/{2C3F5F28-2666-4611-A472-9594D2C098B3}_1755595272546.png differ diff --git a/client/src/components/tasks/SimpleTaskForm.tsx b/client/src/components/tasks/SimpleTaskForm.tsx index bdbed09..1fa25c1 100644 --- a/client/src/components/tasks/SimpleTaskForm.tsx +++ b/client/src/components/tasks/SimpleTaskForm.tsx @@ -1,412 +1,2 @@ -import { useState, useEffect } from "react"; -import { useForm } from "react-hook-form"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useMutation, useQueryClient, useQuery } from "@tanstack/react-query"; -import { useAuthUnified } from "@/hooks/useAuthUnified"; -import { useStore } from "@/components/Layout"; -import { useToast } from "@/hooks/use-toast"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Textarea } from "@/components/ui/textarea"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Calendar } from "@/components/ui/calendar"; -import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; -import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; -import { apiRequest } from "@/lib/queryClient"; -import { insertTaskSchema, Task, Group } from "@shared/schema"; -import { z } from "zod"; -import { CalendarIcon } from "lucide-react"; -import { format } from "date-fns"; -import { fr } from "date-fns/locale"; -// Supprimer complètement l'utilisation de cn pour éviter toute erreur de production - -// Schéma robuste avec dates de début et d'échéance pour production -const taskFormSchema = z.object({ - title: z.string().min(1, "Le titre est requis"), - description: z.string().optional(), - priority: z.enum(["low", "medium", "high"]).default("medium"), - status: z.enum(["pending", "completed"]).default("pending"), - assignedTo: z.string().min(1, "L'assignation est requise"), - startDate: z.date().optional(), // Date de début - dueDate: z.date().optional(), // Date d'échéance -}).refine((data) => { - // Validation : la date d'échéance ne peut pas être antérieure à la date de début - if (data.startDate && data.dueDate) { - return data.dueDate >= data.startDate; - } - return true; -}, { - message: "La date d'échéance ne peut pas être antérieure à la date de début", - path: ["dueDate"] -}); - -type TaskFormData = z.infer; - -type TaskWithRelations = Task & { - assignedUser?: { id: string; username: string; firstName?: string; lastName?: string; }; - creator?: { id: string; username: string; firstName?: string; lastName?: string; }; - group?: { id: number; name: string; color: string; }; -}; - -interface TaskFormProps { - task?: TaskWithRelations; - onClose: () => void; -} - -export default function TaskForm({ task, onClose }: TaskFormProps) { - const { user } = useAuthUnified(); - const { selectedStoreId } = useStore(); - const { toast } = useToast(); - const queryClient = useQueryClient(); - - // État local pour gérer le magasin sélectionné - const [localSelectedStoreId, setLocalSelectedStoreId] = useState(null); - - // Récupération sécurisée des magasins - const { data: groupsData = [], error: groupsError } = useQuery({ - queryKey: ['/api/groups'], - enabled: !!user, - }); - - // Log des erreurs de groupes si nécessaire - if (groupsError) { - console.warn('Erreur lors du chargement des magasins:', groupsError); - } - - const groups = Array.isArray(groupsData) ? groupsData.filter(g => g && typeof g === 'object' && g.id) : []; - - // Auto-sélection du magasin - useEffect(() => { - if (groups.length > 0 && !localSelectedStoreId) { - let defaultStoreId: number | null = null; - - if (user?.role === 'admin') { - if (selectedStoreId && groups.find(g => g.id === selectedStoreId)) { - defaultStoreId = selectedStoreId; - } else { - defaultStoreId = groups[0].id; - } - } else { - defaultStoreId = groups[0].id; - } - - if (defaultStoreId) { - setLocalSelectedStoreId(defaultStoreId); - } - } - }, [groups, selectedStoreId, user?.role, localSelectedStoreId]); - - const form = useForm({ - resolver: zodResolver(taskFormSchema), - defaultValues: { - title: task?.title || "", - description: task?.description || "", - priority: (task?.priority as "low" | "medium" | "high") || "medium", - status: (task?.status as "pending" | "completed") || "pending", - assignedTo: task?.assignedTo || "", - startDate: task?.startDate ? new Date(task.startDate) : undefined, - dueDate: task?.dueDate ? new Date(task.dueDate) : undefined, - }, - }); - - // Mutations sécurisées - const createMutation = useMutation({ - mutationFn: (data: any) => { - const taskData = { - ...data, - groupId: localSelectedStoreId, - createdBy: user?.id, - startDate: data.startDate || null, - dueDate: data.dueDate || null - }; - return apiRequest("/api/tasks", "POST", taskData); - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ["/api/tasks"] }); - toast({ - title: "Succès", - description: "Tâche créée avec succès", - }); - onClose(); - }, - onError: (error: any) => { - console.error("Error creating task:", error); - toast({ - title: "Erreur", - description: "Impossible de créer la tâche", - variant: "destructive", - }); - }, - }); - - const updateMutation = useMutation({ - mutationFn: (data: any) => { - return apiRequest(`/api/tasks/${task?.id}`, "PUT", data); - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ["/api/tasks"] }); - toast({ - title: "Succès", - description: "Tâche modifiée avec succès", - }); - onClose(); - }, - onError: (error: any) => { - console.error("Error updating task:", error); - toast({ - title: "Erreur", - description: "Impossible de modifier la tâche", - variant: "destructive", - }); - }, - }); - - const onSubmit = (data: TaskFormData) => { - if (!localSelectedStoreId) { - toast({ - title: "Erreur", - description: "Aucun magasin disponible", - variant: "destructive", - }); - return; - } - - if (task) { - updateMutation.mutate(data); - } else { - createMutation.mutate(data); - } - }; - - return ( -
-
-
-

- {task ? "Modifier la tâche" : "Nouvelle tâche"} -

-

- 📅 Date de début = Quand la tâche devient visible
- ⏰ Date d'échéance = Quand la tâche doit être terminée -

-
-
- -
- - {/* Titre */} - ( - - Titre * - - - - - - )} - /> - - {/* Description */} - ( - - Description - -