import { useState, useEffect } from "react"; import { useQuery, useQueryClient } 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Badge } from "@/components/ui/badge"; import { Pagination, usePagination } from "@/components/ui/pagination"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ListTodo, Plus, Search, Circle, Clock, AlertTriangle, CheckCircle, Edit, Trash2, Calendar, CalendarX, CalendarClock, Kanban } from "lucide-react"; import { format, isToday, isThisWeek, isPast, differenceInDays } from "date-fns"; import { fr } from "date-fns/locale"; // TaskForm inline pour éviter les problèmes d'import en production import { Task } from "@shared/schema"; 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; }; isFutureTask?: boolean; // Pour les tâches futures (admin/directeur uniquement) }; // Composant TaskForm inline - Version production ultra-simple function TaskFormInline({ task, onClose, selectedStoreId, user }: any) { const { toast } = useToast(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(e.currentTarget); const title = formData.get('title') as string; const description = formData.get('description') as string; const priority = formData.get('priority') as string; const status = formData.get('status') as string; const assignedTo = formData.get('assignedTo') as string; const startDate = formData.get('startDate') as string; const dueDate = formData.get('dueDate') as string; if (!title?.trim()) { toast({ title: "Erreur", description: "Le titre est requis", variant: "destructive", }); return; } const submitBtn = e.currentTarget.querySelector('button[type="submit"]') as HTMLButtonElement; submitBtn.disabled = true; submitBtn.textContent = "..."; try { const taskData = { title: title.trim(), description: description?.trim() || "", priority: priority || "medium", status: status || "pending", assignedTo: assignedTo?.trim() || "Non assigné", startDate: startDate || null, dueDate: dueDate || null, }; const url = task ? `/api/tasks/${task.id}` : '/api/tasks'; const method = task ? 'PUT' : 'POST'; if (!task) { // Utiliser le magasin sélectionné ou le premier disponible comme fallback (taskData as any).groupId = selectedStoreId ? parseInt(selectedStoreId.toString()) : 1; (taskData as any).createdBy = user?.username || 'admin'; } console.log('📤 Tasks.tsx - Sending request:', { url, method, taskData, selectedStoreId, finalGroupId: (taskData as any).groupId }); const response = await fetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(taskData), }); console.log('📥 Response:', { status: response.status, ok: response.ok }); if (!response.ok) { const errorText = await response.text(); console.error('❌ API Error:', { status: response.status, error: errorText }); throw new Error(`Erreur ${response.status}: ${errorText}`); } toast({ title: "Succès", description: task ? "Tâche modifiée avec succès" : "Tâche créée avec succès", }); window.location.reload(); } catch (error) { console.error('Erreur:', error); toast({ title: "Erreur", description: "Erreur lors de l'opération", variant: "destructive", }); submitBtn.disabled = false; submitBtn.textContent = task ? "Modifier" : "Créer"; } }; return (

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