diff --git a/.replit b/.replit index 3043b2b..f9b73f0 100644 --- a/.replit +++ b/.replit @@ -23,10 +23,6 @@ externalPort = 3002 localPort = 41343 externalPort = 3001 -[[ports]] -localPort = 45213 -externalPort = 3000 - [workflows] runButton = "Project" diff --git a/client/src/pages/Tasks.tsx b/client/src/pages/Tasks.tsx index 316627f..b3c35b9 100644 --- a/client/src/pages/Tasks.tsx +++ b/client/src/pages/Tasks.tsx @@ -24,7 +24,11 @@ import { Calendar, CalendarX, CalendarClock, - Kanban + Kanban, + Filter, + X, + ChevronDown, + ChevronUp } from "lucide-react"; import { format, isToday, isThisWeek, isPast, differenceInDays } from "date-fns"; import { fr } from "date-fns/locale"; @@ -178,7 +182,8 @@ function TaskFormInline({ task, onClose, selectedStoreId, user }: any) { /> -
+ {/* Grille responsive pour priorité et statut */} +
-
+ {/* Grille responsive pour les dates */} +
@@ -248,13 +236,7 @@ function TaskFormInline({ task, onClose, selectedStoreId, user }: any) { name="dueDate" type="date" defaultValue={task?.dueDate ? new Date(task.dueDate).toISOString().split('T')[0] : ""} - style={{ - width: '100%', - padding: '8px 12px', - border: '1px solid #d1d5db', - borderRadius: '0px', - fontSize: '14px' - }} + className="w-full p-3 border border-gray-300 rounded-md text-base min-h-[44px] bg-white dark:bg-gray-800 dark:border-gray-600 dark:text-white" />
@@ -268,40 +250,22 @@ function TaskFormInline({ task, onClose, selectedStoreId, user }: any) { type="text" defaultValue={task?.assignedTo || ""} placeholder="Nom de la personne assignée" - style={{ - width: '100%', - padding: '8px 12px', - border: '1px solid #d1d5db', - borderRadius: '0px', - fontSize: '14px' - }} + className="w-full p-3 border border-gray-300 rounded-md text-base min-h-[44px] bg-white dark:bg-gray-800 dark:border-gray-600 dark:text-white" />
-
+ {/* Boutons responsive - Stack sur mobile */} +
@@ -349,6 +313,7 @@ export default function Tasks() { const [priorityFilter, setPriorityFilter] = useState("all"); const [dueDateFilter, setDueDateFilter] = useState("all"); const [viewMode, setViewMode] = useState("list"); + const [filtersOpen, setFiltersOpen] = useState(false); // Modals const [showCreateModal, setShowCreateModal] = useState(false); @@ -711,95 +676,69 @@ export default function Tasks() { } return ( -
+
{/* Header */} -
-
+
+
-

- +

+ Gestion des Tâches

-

+

{totalItems} tâche{totalItems !== 1 ? 's' : ''} trouvée{totalItems !== 1 ? 's' : ''}

-
+
+ {/* Bouton filtres mobile */} + + {/* Sélecteur de vue */} - + - - - Liste + + + Liste - - - Kanban + + + Kanban -{canCreateTasks && ( + {canCreateTasks && ( <> {showCreateModal && ( -
-
-
-

+
+
+
+

Créer une nouvelle tâche

@@ -818,10 +757,342 @@ export default function Tasks() {
-
- {/* Sidebar avec filtres */} + {/* Section filtres - Responsive */} +
+ + +
+ Filtres + +
+
+ + {/* Recherche */} +
+ + setSearchTerm(e.target.value)} + className="pl-10 h-11 sm:h-10 text-base sm:text-sm" + data-testid="input-search-tasks" + /> +
+ + {/* Filtres en grille responsive */} +
+ {/* Filtre par statut */} +
+ + +
+ + {/* Filtre par priorité */} +
+ + +
+ + {/* Filtre par échéance */} +
+ + +
+
+
+
+
+ + {/* Zone principale mobile/tablet - Contenu pleine largeur */} +
+ + + {/* Contenu mobile identique au desktop mais optimisé */} + {totalItems === 0 ? ( +
+ +

+ Aucune tâche +

+

+ Aucune tâche trouvée avec les filtres sélectionnés. +

+
+ ) : ( +
+ {/* Tâches en cours - Mobile optimisé */} + {paginatedTasks.filter(task => task.status === 'pending').length > 0 && ( +
+

+ Tâches en cours ({paginatedTasks.filter(task => task.status === 'pending').length}) +

+
+ {paginatedTasks + .filter(task => task.status === 'pending') + .map((task) => { + const priorityConfig = getPriorityConfig(task.priority); + const PriorityIcon = priorityConfig.icon; + const isFuture = isTaskFuture(task); + const startDateStatus = getStartDateStatus(task.startDate); + + return ( + + + {/* Layout mobile : vertical stack */} +
+ {/* Header de la tâche */} +
+
+
+ {task.title} + {isFuture && " (Programmée)"} +
+
+ + {/* Badges de priorité et statut */} +
+ + + {priorityConfig.label} + + {isFuture && ( + + + Future + + )} +
+
+ + {/* Description */} + {task.description && ( +

+ {task.description} +

+ )} + + {/* Info assignation et création */} +
+
Assigné à: {task.assignedTo}
+
Créée: {format(new Date(task.createdAt), 'dd/MM/yyyy HH:mm', { locale: fr })}
+
+ + {/* Dates importantes */} +
+ {[ + // Date de départ + startDateStatus && ( +
+ + + 📅 {startDateStatus.text} + + + {startDateStatus.label} + {task.startDate && ` (${format(new Date(task.startDate), 'dd/MM/yyyy', { locale: fr })})`} + +
+ ), + // Date d'échéance + (() => { + const dueDateStatus = getDueDateStatus(task.dueDate, task.status); + if (dueDateStatus) { + const DueDateIcon = dueDateStatus.icon; + return ( +
+ + + ⏰ {dueDateStatus.text} + + {dueDateStatus.label} +
+ ); + } else if (task.dueDate) { + return ( +
+ + + ⏰ {format(new Date(task.dueDate), 'dd/MM', { locale: fr })} + +
+ ); + } + return null; + })() + ].filter(Boolean)} +
+ + {/* Actions - Mobile friendly */} +
+ {isFuture && ( +
+ Visible en avance ({user?.role}) +
+ )} + + {canEditTasks && !isFuture && ( + + )} + {canEditTasks && ( + + )} + {canEditTasks && ( + + )} +
+
+
+
+ ); + })} +
+
+ )} + + {/* Tâches terminées - Mobile optimisé */} + {paginatedTasks.filter(task => task.status === 'completed').length > 0 && ( +
+

+ Tâches terminées ({paginatedTasks.filter(task => task.status === 'completed').length}) +

+
+ {paginatedTasks + .filter(task => task.status === 'completed') + .map((task) => { + const priorityConfig = getPriorityConfig(task.priority); + const PriorityIcon = priorityConfig.icon; + + return ( + + +
+
+
+ {task.title} +
+ + + Terminée + +
+ + {task.description && ( +

+ {task.description} +

+ )} + +
+ Assigné à: {task.assignedTo} + Terminée: {format(new Date(task.updatedAt), 'dd/MM/yyyy', { locale: fr })} +
+
+
+
+ ); + })} +
+
+ )} + + {/* Pagination - Mobile friendly */} + {totalPages > 1 && ( +
+ +
+ )} +
+ )} +
+
+
+ + {/* Sidebar desktop uniquement */} +
+ {/* Sidebar avec filtres desktop */}
- {/* Filtres */} Filtres @@ -895,7 +1166,7 @@ export default function Tasks() {
- {/* Zone principale avec les tâches */} + {/* Zone principale avec les tâches - Desktop */}
{/* Contenu selon la vue sélectionnée */}