From 1597f0fea183b070e65639f394e12168dc64ef7b Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Sun, 14 Sep 2025 22:34:51 +0200 Subject: [PATCH] feat: add column visibility toggle to Kanban and Swimlanes boards - Integrated `useColumnVisibility` hook for managing column visibility states. - Added `ColumnVisibilityToggle` component to both `KanbanBoard` and `SwimlanesBoard` for user control over visible columns. - Updated rendering logic to filter and display only visible columns, enhancing user experience and task organization. --- components/kanban/Board.tsx | 21 ++++++++++- components/kanban/ColumnVisibilityToggle.tsx | 39 ++++++++++++++++++++ components/kanban/SwimlanesBoard.tsx | 33 ++++++++++++++--- hooks/useColumnVisibility.ts | 35 ++++++++++++++++++ 4 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 components/kanban/ColumnVisibilityToggle.tsx create mode 100644 hooks/useColumnVisibility.ts diff --git a/components/kanban/Board.tsx b/components/kanban/Board.tsx index f417697..2b70bb0 100644 --- a/components/kanban/Board.tsx +++ b/components/kanban/Board.tsx @@ -6,6 +6,8 @@ import { Button } from '@/components/ui/Button'; import { CreateTaskForm } from '@/components/forms/CreateTaskForm'; import { CreateTaskData } from '@/clients/tasks-client'; import { useMemo, useState } from 'react'; +import { useColumnVisibility } from '@/hooks/useColumnVisibility'; +import { ColumnVisibilityToggle } from './ColumnVisibilityToggle'; import { DndContext, DragEndEvent, @@ -31,6 +33,9 @@ interface KanbanBoardProps { export function KanbanBoard({ tasks, onCreateTask, onDeleteTask, onEditTask, onUpdateTitle, onUpdateStatus, loading = false, compactView = false }: KanbanBoardProps) { const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [activeTask, setActiveTask] = useState(null); + + // Gestion de la visibilité des colonnes + const { hiddenStatuses, toggleStatusVisibility, getVisibleStatuses } = useColumnVisibility(); // Configuration des capteurs pour le drag & drop const sensors = useSensors( @@ -54,7 +59,7 @@ export function KanbanBoard({ tasks, onCreateTask, onDeleteTask, onEditTask, onU }, [tasks]); // Configuration des colonnes - const columns: Array<{ + const allColumns: Array<{ id: TaskStatus; title: string; color: string; @@ -86,6 +91,9 @@ export function KanbanBoard({ tasks, onCreateTask, onDeleteTask, onEditTask, onU } ]; + // Filtrer les colonnes visibles + const visibleColumns = getVisibleStatuses(allColumns); + const handleCreateTask = async (data: CreateTaskData) => { if (onCreateTask) { await onCreateTask(data); @@ -145,9 +153,18 @@ export function KanbanBoard({ tasks, onCreateTask, onDeleteTask, onEditTask, onU )} + {/* Toggle de visibilité des colonnes */} +
+ +
+ {/* Board tech dark */}
- {columns.map((column) => ( + {visibleColumns.map((column) => ( ; + onToggleStatus: (status: TaskStatus) => void; + className?: string; +} + +export function ColumnVisibilityToggle({ + statuses, + hiddenStatuses, + onToggleStatus, + className = "" +}: ColumnVisibilityToggleProps) { + return ( +
+ + Colonnes : + + {statuses.map(status => ( + + ))} +
+ ); +} diff --git a/components/kanban/SwimlanesBoard.tsx b/components/kanban/SwimlanesBoard.tsx index 0045700..56e2dc2 100644 --- a/components/kanban/SwimlanesBoard.tsx +++ b/components/kanban/SwimlanesBoard.tsx @@ -4,6 +4,8 @@ import { Task, TaskStatus } from '@/lib/types'; import { TaskCard } from './TaskCard'; import { useMemo, useState } from 'react'; import { useTasksContext } from '@/contexts/TasksContext'; +import { useColumnVisibility } from '@/hooks/useColumnVisibility'; +import { ColumnVisibilityToggle } from './ColumnVisibilityToggle'; import { DndContext, DragEndEvent, @@ -86,6 +88,9 @@ export function SwimlanesBoard({ const { tags: availableTags } = useTasksContext(); const [activeTask, setActiveTask] = useState(null); const [collapsedSwimlanes, setCollapsedSwimlanes] = useState>(new Set()); + + // Gestion de la visibilité des colonnes + const { hiddenStatuses, toggleStatusVisibility, getVisibleStatuses } = useColumnVisibility(); // Configuration des capteurs pour le drag & drop const sensors = useSensors( @@ -137,6 +142,9 @@ export function SwimlanesBoard({ }); }; + // Filtrer les statuts visibles + const visibleStatuses = getVisibleStatuses(statuses); + // Grouper les tâches par tags const tasksByTag = useMemo(() => { const grouped: { [tagName: string]: Task[] } = {}; @@ -184,9 +192,21 @@ export function SwimlanesBoard({
- {/* Headers des colonnes */} -
- {statuses.map(status => ( + {/* Headers des colonnes avec boutons toggle */} +
+ +
+ + {/* Headers des colonnes visibles */} +
+ {visibleStatuses.map(status => (
{status.title} @@ -238,8 +258,11 @@ export function SwimlanesBoard({ {/* Contenu de la swimlane */} {!collapsedSwimlanes.has(tagName) && ( -
- {statuses.map(status => { +
+ {visibleStatuses.map(status => { const statusTasks = tagTasks.filter(task => task.status === status.id); return ( >( + new Set(initialHidden) + ); + + const toggleStatusVisibility = (status: TaskStatus) => { + setHiddenStatuses(prev => { + const newSet = new Set(prev); + if (newSet.has(status)) { + newSet.delete(status); + } else { + newSet.add(status); + } + return newSet; + }); + }; + + const getVisibleStatuses = (statuses: T[]): T[] => { + return statuses.filter(status => !hiddenStatuses.has(status.id)); + }; + + const isStatusVisible = (status: TaskStatus): boolean => { + return !hiddenStatuses.has(status); + }; + + return { + hiddenStatuses, + toggleStatusVisibility, + getVisibleStatuses, + isStatusVisible + }; +}