diff --git a/attached_assets/{496F0E32-2A57-4E68-BCC2-2FEF5994C6B5}_1755601443875.png b/attached_assets/{496F0E32-2A57-4E68-BCC2-2FEF5994C6B5}_1755601443875.png new file mode 100644 index 0000000..64ad496 Binary files /dev/null and b/attached_assets/{496F0E32-2A57-4E68-BCC2-2FEF5994C6B5}_1755601443875.png differ diff --git a/client/src/components/RouterProduction.tsx b/client/src/components/RouterProduction.tsx index e5276d6..44ed4c5 100644 --- a/client/src/components/RouterProduction.tsx +++ b/client/src/components/RouterProduction.tsx @@ -19,7 +19,7 @@ import CustomerOrders from "@/pages/CustomerOrders"; import DlcPage from "@/pages/DlcPage"; import BackupManager from "@/pages/BackupManager"; import Utilities from "@/pages/Utilities"; -import TasksProductionSimple from "@/pages/TasksProductionSimple"; +import TasksListSimple from "@/pages/TasksListSimple"; import SavTickets from "@/pages/SavTickets"; import WeatherSettings from "@/pages/WeatherSettings"; import Layout from "@/components/Layout"; @@ -94,7 +94,7 @@ function RouterProduction() { - + {/* Routes de compatibilité - redirection vers utilities */} diff --git a/client/src/pages/TasksListSimple.tsx b/client/src/pages/TasksListSimple.tsx new file mode 100644 index 0000000..2e57e57 --- /dev/null +++ b/client/src/pages/TasksListSimple.tsx @@ -0,0 +1,568 @@ +import { useState, useEffect } from "react"; + +// Interface pour les tâches +interface Task { + id: number; + title: string; + description?: string; + priority: 'low' | 'medium' | 'high'; + status: 'pending' | 'completed'; + assignedTo: string; + startDate?: string | null; + dueDate?: string | null; + createdAt?: string; + groupId?: number; + createdBy?: string; +} + +export default function TasksListSimple() { + const [tasks, setTasks] = useState([]); + const [loading, setLoading] = useState(true); + const [editingId, setEditingId] = useState(null); + const [searchTerm, setSearchTerm] = useState(""); + const [statusFilter, setStatusFilter] = useState("all"); + const [showCreateForm, setShowCreateForm] = useState(false); + + // Charger les tâches + const loadTasks = async () => { + try { + const response = await fetch('/api/tasks'); + if (response.ok) { + const data = await response.json(); + setTasks(data); + } else { + console.error('Erreur lors du chargement des tâches:', response.status); + } + } catch (error) { + console.error('Erreur lors du chargement des tâches:', error); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + loadTasks(); + }, []); + + // Créer une tâche + const createTask = async (formData: FormData) => { + 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()) { + alert("Le titre est requis"); + return false; + } + + if (!assignedTo?.trim()) { + alert("L'assignation est requise"); + return false; + } + + try { + const taskData = { + title: title.trim(), + description: description?.trim() || "", + priority: priority || "medium", + status: status || "pending", + assignedTo: assignedTo.trim(), + startDate: startDate || null, + dueDate: dueDate || null, + groupId: 1, + createdBy: 'admin', + }; + + console.log('📤 Creating task:', taskData); + + const response = await fetch('/api/tasks', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(taskData), + }); + + if (!response.ok) { + const errorText = await response.text(); + console.error('❌ Create Error:', { status: response.status, error: errorText }); + throw new Error(`Erreur ${response.status}: ${errorText}`); + } + + alert("Tâche créée avec succès"); + loadTasks(); + return true; + } catch (error) { + console.error('Erreur lors de la création:', error); + alert("Erreur lors de la création"); + return false; + } + }; + + // Modifier une tâche + const updateTask = async (id: number, formData: FormData) => { + 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()) { + alert("Le titre est requis"); + return false; + } + + if (!assignedTo?.trim()) { + alert("L'assignation est requise"); + return false; + } + + try { + // Préparer les données exactement comme le serveur les attend + const taskData: Partial = { + title: title.trim(), + description: description?.trim() || "", + priority: (priority as Task['priority']) || "medium", + status: (status as Task['status']) || "pending", + assignedTo: assignedTo.trim(), + }; + + // Gestion spéciale des dates pour éviter les erreurs de format + if (startDate && startDate.trim() !== '') { + taskData.startDate = startDate; + } else { + taskData.startDate = null; + } + + if (dueDate && dueDate.trim() !== '') { + taskData.dueDate = dueDate; + } else { + taskData.dueDate = null; + } + + console.log('📤 Updating task:', { id, taskData }); + + const response = await fetch(`/api/tasks/${id}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(taskData), + }); + + console.log('📥 Update Response:', { status: response.status, ok: response.ok }); + + if (!response.ok) { + const errorText = await response.text(); + console.error('❌ Update Error:', { status: response.status, error: errorText }); + throw new Error(`Erreur ${response.status}: ${errorText}`); + } + + alert("Tâche modifiée avec succès"); + setEditingId(null); + loadTasks(); + return true; + } catch (error) { + console.error('Erreur lors de la modification:', error); + alert("Erreur lors de la modification"); + return false; + } + }; + + // Filtrer les tâches + const filteredTasks = tasks.filter(task => { + const matchesSearch = !searchTerm || task.title?.toLowerCase().includes(searchTerm.toLowerCase()); + const matchesStatus = statusFilter === "all" || task.status === statusFilter; + return matchesSearch && matchesStatus; + }); + + // Formulaire inline + const TaskForm = ({ task, onSubmit, onCancel }: { + task?: Task; + onSubmit: (formData: FormData) => Promise; + onCancel: () => void; + }) => { + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + const formData = new FormData(e.currentTarget); + const success = await onSubmit(formData); + if (success && !task) { + (e.target as HTMLFormElement).reset(); + } + }; + + return ( + + +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + + ); + }; + + if (loading) { + return ( +
+

Chargement des tâches...

+
+ ); + } + + return ( +
+ {/* Header */} +
+
+

+ 📋 Gestion des Tâches +

+ +
+ + {/* Filtres */} +
+
+ setSearchTerm(e.target.value)} + style={{ + width: '100%', + padding: '8px 12px', + border: '1px solid #d1d5db', + borderRadius: '6px', + fontSize: '14px' + }} + /> +
+
+ +
+
+
+ + {/* Tableau des tâches */} +
+ + + + + + + + + + + + + {showCreateForm && ( + setShowCreateForm(false)} + /> + )} + + {filteredTasks.length === 0 ? ( + + + + ) : ( + filteredTasks.map((task) => ( + editingId === task.id ? ( + updateTask(task.id, formData)} + onCancel={() => setEditingId(null)} + /> + ) : ( + + + + + + + + + ) + )) + )} + +
TitrePrioritéStatutAssigné àDatesActions
+ Aucune tâche trouvée +
+
+
+ {task.title} +
+ {task.description && ( +
+ {task.description} +
+ )} +
+
+ + {task.priority === 'high' ? '🔴 Élevée' : task.priority === 'medium' ? '🟡 Moyenne' : '🟢 Faible'} + + + + {task.status === 'completed' ? '✅ Terminée' : '⏳ En cours'} + + + {task.assignedTo} + + {task.startDate && ( +
📅 {new Date(task.startDate).toLocaleDateString('fr-FR')}
+ )} + {task.dueDate && ( +
⏰ {new Date(task.dueDate).toLocaleDateString('fr-FR')}
+ )} +
+ +
+
+
+ ); +} \ No newline at end of file diff --git a/server/routes.ts b/server/routes.ts index 83ab079..e248193 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -1455,7 +1455,20 @@ export async function registerRoutes(app: Express): Promise { } } - const updatedTask = await storage.updateTask(id, req.body); + // Nettoyer les données reçues pour éviter les problèmes de types + const cleanData = { + ...(req.body.title && { title: req.body.title }), + ...(req.body.description !== undefined && { description: req.body.description }), + ...(req.body.priority && { priority: req.body.priority }), + ...(req.body.status && { status: req.body.status }), + ...(req.body.assignedTo && { assignedTo: req.body.assignedTo }), + ...(req.body.startDate !== undefined && { startDate: req.body.startDate === '' ? null : req.body.startDate }), + ...(req.body.dueDate !== undefined && { dueDate: req.body.dueDate === '' ? null : req.body.dueDate }), + }; + + console.log('🧹 Cleaned data for update:', cleanData); + + const updatedTask = await storage.updateTask(id, cleanData); console.log('✅ Task updated:', { id: updatedTask.id, title: updatedTask.title,