From b51687f30180948bcc1cb02d067ae8190d59479e Mon Sep 17 00:00:00 2001 From: R0m1k3 Date: Wed, 10 Dec 2025 12:51:58 +0100 Subject: [PATCH] feat: introduce responsive task management with a dedicated mobile tasks page and form --- client/src/components/ResponsiveTasks.tsx | 19 + client/src/components/RouterProduction.tsx | 15 +- client/src/pages/mobile/TasksPage.tsx | 472 +++++++++++++++++++++ 3 files changed, 499 insertions(+), 7 deletions(-) create mode 100644 client/src/components/ResponsiveTasks.tsx create mode 100644 client/src/pages/mobile/TasksPage.tsx diff --git a/client/src/components/ResponsiveTasks.tsx b/client/src/components/ResponsiveTasks.tsx new file mode 100644 index 0000000..76e8d84 --- /dev/null +++ b/client/src/components/ResponsiveTasks.tsx @@ -0,0 +1,19 @@ +/** + * ResponsiveTasks - Wrapper component that automatically detects screen size + * and renders either the mobile or desktop version of the Tasks page. + */ +import { useScreenSize } from "@/hooks/use-screen-size"; +import Tasks from "@/pages/Tasks"; +import MobileTasksPage from "@/pages/mobile/TasksPage"; + +export default function ResponsiveTasks() { + const { isMobile } = useScreenSize(); + + // Render mobile version for screens < 768px + if (isMobile) { + return ; + } + + // Render desktop version for larger screens + return ; +} diff --git a/client/src/components/RouterProduction.tsx b/client/src/components/RouterProduction.tsx index 421731e..10b18a3 100644 --- a/client/src/components/RouterProduction.tsx +++ b/client/src/components/RouterProduction.tsx @@ -20,6 +20,7 @@ import DlcPage from "@/pages/DlcPage"; import BackupManager from "@/pages/BackupManager"; import Utilities from "@/pages/Utilities"; import Tasks from "@/pages/Tasks"; +import ResponsiveTasks from "@/components/ResponsiveTasks"; import SavTickets from "@/pages/SavTickets"; import Avoirs from "@/pages/Avoirs"; import WeatherSettings from "@/pages/WeatherSettings"; @@ -30,7 +31,7 @@ import Layout from "@/components/Layout"; function RouterProduction() { const { isAuthenticated, isLoading, user, environment, error } = useAuthUnified(); - + // Debug uniquement en développement if (import.meta.env.DEV) { console.log('🔍 RouterProduction Debug:', { @@ -43,7 +44,7 @@ function RouterProduction() { error: error?.message }); } - + // Debug minimal basé sur l'environnement if (environment === 'production' && error && import.meta.env.DEV) { console.error('🚨 Production Auth Error:', error); @@ -76,7 +77,7 @@ function RouterProduction() { ); } - + return ( @@ -102,19 +103,19 @@ function RouterProduction() { - + - + {/* Routes de compatibilité - redirection vers utilities */} - + {/* Redirection depuis /auth vers dashboard après authentification */} {() => { @@ -127,7 +128,7 @@ function RouterProduction() { return ; }} - + diff --git a/client/src/pages/mobile/TasksPage.tsx b/client/src/pages/mobile/TasksPage.tsx new file mode 100644 index 0000000..c5544f6 --- /dev/null +++ b/client/src/pages/mobile/TasksPage.tsx @@ -0,0 +1,472 @@ +import { useState, useEffect } from "react"; +import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { useAuthUnified } from "@/hooks/useAuthUnified"; +import { useStore } from "@/contexts/StoreContext"; +import { useToast } from "@/hooks/use-toast"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Badge } from "@/components/ui/badge"; +import { Card, CardContent } from "@/components/ui/card"; +import { + ListTodo, + Plus, + Search, + CheckCircle, + Edit, + Trash2, + Calendar, + AlertTriangle, + Clock, + Circle, + X +} from "lucide-react"; +import { format, isPast, differenceInDays, isToday } from "date-fns"; +import { fr } from "date-fns/locale"; +import type { 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; +}; + +// Mobile Task Form Component +function MobileTaskForm({ task, onClose, selectedStoreId, user }: any) { + const { toast } = useToast(); + const [isSubmitting, setIsSubmitting] = useState(false); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsSubmitting(true); + + 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 assignedTo = formData.get('assignedTo') as string; + const dueDate = formData.get('dueDate') as string; + + if (!title?.trim()) { + toast({ title: "Erreur", description: "Le titre est requis", variant: "destructive" }); + setIsSubmitting(false); + return; + } + + try { + const taskData = { + title: title.trim(), + description: description?.trim() || "", + priority: priority || "medium", + status: task?.status || "pending", + assignedTo: assignedTo?.trim() || "Non assigné", + dueDate: dueDate || null, + }; + + const url = task ? `/api/tasks/${task.id}` : '/api/tasks'; + const method = task ? 'PUT' : 'POST'; + + if (!task) { + (taskData as any).groupId = selectedStoreId ? parseInt(selectedStoreId.toString()) : 1; + (taskData as any).createdBy = user?.username || 'admin'; + } + + const response = await fetch(url, { + method, + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(taskData), + }); + + if (!response.ok) throw new Error(`Erreur ${response.status}`); + + toast({ + title: "Succès", + description: task ? "Tâche modifiée" : "Tâche créée", + }); + window.location.reload(); + + } catch (error) { + toast({ title: "Erreur", description: "Erreur lors de l'opération", variant: "destructive" }); + setIsSubmitting(false); + } + }; + + return ( +
+ {/* Header */} +
+

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

+ +
+ + {/* Form */} +
+
+ + +
+ +
+ +