diff --git a/components/kanban/BoardContainer.tsx b/components/kanban/BoardContainer.tsx index 49afde6..3012af3 100644 --- a/components/kanban/BoardContainer.tsx +++ b/components/kanban/BoardContainer.tsx @@ -84,22 +84,26 @@ export function KanbanBoardContainer() { kanbanFilters.swimlanesMode === 'priority' ? ( ) : ( ) ) : ( diff --git a/components/kanban/PrioritySwimlanesBoard.tsx b/components/kanban/PrioritySwimlanesBoard.tsx index 9513a0b..771da0f 100644 --- a/components/kanban/PrioritySwimlanesBoard.tsx +++ b/components/kanban/PrioritySwimlanesBoard.tsx @@ -1,28 +1,33 @@ 'use client'; import { Task, TaskStatus } from '@/lib/types'; +import { CreateTaskData } from '@/clients/tasks-client'; import { useMemo } from 'react'; import { getAllPriorities } from '@/lib/status-config'; import { SwimlanesBase, SwimlaneData } from './SwimlanesBase'; interface PrioritySwimlanesoardProps { tasks: Task[]; + onCreateTask?: (data: CreateTaskData) => Promise; onDeleteTask?: (taskId: string) => Promise; onEditTask?: (task: Task) => void; onUpdateTitle?: (taskId: string, newTitle: string) => Promise; onUpdateStatus?: (taskId: string, newStatus: TaskStatus) => Promise; compactView?: boolean; visibleStatuses?: TaskStatus[]; + loading?: boolean; } export function PrioritySwimlanesBoard({ tasks, + onCreateTask, onDeleteTask, onEditTask, onUpdateTitle, onUpdateStatus, compactView = false, - visibleStatuses + visibleStatuses, + loading = false }: PrioritySwimlanesoardProps) { // Grouper les tâches par priorités et créer les données de swimlanes @@ -57,12 +62,14 @@ export function PrioritySwimlanesBoard({ tasks={tasks} title="Swimlanes par Priorité" swimlanes={swimlanesData} + onCreateTask={onCreateTask} onDeleteTask={onDeleteTask} onEditTask={onEditTask} onUpdateTitle={onUpdateTitle} onUpdateStatus={onUpdateStatus} compactView={compactView} visibleStatuses={visibleStatuses} + loading={loading} /> ); } \ No newline at end of file diff --git a/components/kanban/SwimlanesBase.tsx b/components/kanban/SwimlanesBase.tsx index ddff573..e29cb60 100644 --- a/components/kanban/SwimlanesBase.tsx +++ b/components/kanban/SwimlanesBase.tsx @@ -2,6 +2,10 @@ import { Task, TaskStatus } from '@/lib/types'; import { TaskCard } from './TaskCard'; +import { QuickAddTask } from './QuickAddTask'; +import { CreateTaskForm } from '@/components/forms/CreateTaskForm'; +import { Button } from '@/components/ui/Button'; +import { CreateTaskData } from '@/clients/tasks-client'; import { useState } from 'react'; import { useColumnVisibility } from '@/hooks/useColumnVisibility'; import { getAllStatuses } from '@/lib/status-config'; @@ -28,7 +32,10 @@ function DroppableColumn({ onDeleteTask, onEditTask, onUpdateTitle, - compactView + compactView, + onCreateTask, + showQuickAdd, + onToggleQuickAdd }: { status: TaskStatus; tasks: Task[]; @@ -36,13 +43,16 @@ function DroppableColumn({ onEditTask?: (task: Task) => void; onUpdateTitle?: (taskId: string, newTitle: string) => Promise; compactView: boolean; + onCreateTask?: (data: CreateTaskData) => Promise; + showQuickAdd?: boolean; + onToggleQuickAdd?: () => void; }) { const { setNodeRef } = useDroppable({ id: status, }); return ( -
+
t.id)} strategy={verticalListSortingStrategy}>
{tasks.map(task => ( @@ -57,6 +67,29 @@ function DroppableColumn({ ))}
+ + {/* QuickAdd pour cette colonne */} + {onCreateTask && ( +
+ {showQuickAdd ? ( + {})} + /> + ) : ( + + )} +
+ )}
); } @@ -74,27 +107,33 @@ interface SwimlanesBaseProps { tasks: Task[]; title: string; swimlanes: SwimlaneData[]; + onCreateTask?: (data: CreateTaskData) => Promise; onDeleteTask?: (taskId: string) => Promise; onEditTask?: (task: Task) => void; onUpdateTitle?: (taskId: string, newTitle: string) => Promise; onUpdateStatus?: (taskId: string, newStatus: TaskStatus) => Promise; compactView?: boolean; visibleStatuses?: TaskStatus[]; + loading?: boolean; } export function SwimlanesBase({ tasks, title, swimlanes, + onCreateTask, onDeleteTask, onEditTask, onUpdateTitle, onUpdateStatus, compactView = false, - visibleStatuses + visibleStatuses, + loading = false }: SwimlanesBaseProps) { const [activeTask, setActiveTask] = useState(null); const [collapsedSwimlanes, setCollapsedSwimlanes] = useState>(new Set()); + const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); + const [showQuickAdd, setShowQuickAdd] = useState<{ [key: string]: boolean }>({}); // Gestion de la visibilité des colonnes const { getVisibleStatuses } = useColumnVisibility(); @@ -144,6 +183,25 @@ export function SwimlanesBase({ setCollapsedSwimlanes(newCollapsed); }; + // Handlers pour la création de tâches + const handleCreateTask = async (data: CreateTaskData) => { + if (onCreateTask) { + await onCreateTask(data); + setIsCreateModalOpen(false); + } + }; + + const handleQuickAdd = async (data: CreateTaskData, columnId: string) => { + if (onCreateTask) { + await onCreateTask(data); + setShowQuickAdd(prev => ({ ...prev, [columnId]: false })); + } + }; + + const toggleQuickAdd = (columnId: string) => { + setShowQuickAdd(prev => ({ ...prev, [columnId]: !prev[columnId] })); + }; + return ( {/* Header */}
-

- {title} -

+
+

+ {title} +

+ + {onCreateTask && ( + + )} +
@@ -221,15 +291,20 @@ export function SwimlanesBase({ {statusesToShow.map(status => { const statusTasks = swimlane.tasks.filter(task => task.status === status); + const columnId = `${swimlane.key}-${status}`; + return ( handleQuickAdd(data, columnId) : undefined} + showQuickAdd={showQuickAdd[columnId] || false} + onToggleQuickAdd={() => toggleQuickAdd(columnId)} /> ); })} @@ -251,6 +326,16 @@ export function SwimlanesBase({ /> )} + + {/* Modal de création complète */} + {onCreateTask && ( + setIsCreateModalOpen(false)} + onSubmit={handleCreateTask} + loading={loading} + /> + )}
); } diff --git a/components/kanban/SwimlanesBoard.tsx b/components/kanban/SwimlanesBoard.tsx index f5d2490..e65e4cd 100644 --- a/components/kanban/SwimlanesBoard.tsx +++ b/components/kanban/SwimlanesBoard.tsx @@ -1,28 +1,33 @@ 'use client'; import { Task, TaskStatus } from '@/lib/types'; +import { CreateTaskData } from '@/clients/tasks-client'; import { useMemo } from 'react'; import { useTasksContext } from '@/contexts/TasksContext'; import { SwimlanesBase, SwimlaneData } from './SwimlanesBase'; interface SwimlanesboardProps { tasks: Task[]; + onCreateTask?: (data: CreateTaskData) => Promise; onDeleteTask?: (taskId: string) => Promise; onEditTask?: (task: Task) => void; onUpdateTitle?: (taskId: string, newTitle: string) => Promise; onUpdateStatus?: (taskId: string, newStatus: TaskStatus) => Promise; compactView?: boolean; visibleStatuses?: TaskStatus[]; + loading?: boolean; } export function SwimlanesBoard({ tasks, + onCreateTask, onDeleteTask, onEditTask, onUpdateTitle, onUpdateStatus, compactView = false, - visibleStatuses + visibleStatuses, + loading = false }: SwimlanesboardProps) { const { tags: availableTags } = useTasksContext(); @@ -77,12 +82,14 @@ export function SwimlanesBoard({ tasks={tasks} title="Swimlanes par Tag" swimlanes={swimlanesData} + onCreateTask={onCreateTask} onDeleteTask={onDeleteTask} onEditTask={onEditTask} onUpdateTitle={onUpdateTitle} onUpdateStatus={onUpdateStatus} compactView={compactView} visibleStatuses={visibleStatuses} + loading={loading} /> ); } \ No newline at end of file