feat(project-view-constants): add enhanced board view to project tabs

- Introduced ProjectViewEnhancedBoard to the project view constants.
- Added a new tab item for the enhanced board view, improving project management options.
- Updated tab items structure to include the new board variant for better user navigation.
This commit is contained in:
shancds
2025-06-20 17:13:37 +05:30
parent dfb360733e
commit bbca644b40
6 changed files with 1125 additions and 0 deletions

View File

@@ -0,0 +1,228 @@
import React, { useState } from 'react';
import { useDroppable } from '@dnd-kit/core';
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
import { Button, Typography } from 'antd';
import { PlusOutlined, MenuOutlined } from '@ant-design/icons';
import { ITaskListGroup } from '@/types/tasks/taskList.types';
import { IGroupBy } from '@/features/tasks/tasks.slice';
import KanbanTaskCard from './kanbanTaskCard';
const { Text } = Typography;
interface TaskGroupProps {
group: ITaskListGroup;
projectId: string;
currentGrouping: IGroupBy;
selectedTaskIds: string[];
onAddTask?: (groupId: string) => void;
onToggleCollapse?: (groupId: string) => void;
onSelectTask?: (taskId: string, selected: boolean) => void;
onToggleSubtasks?: (taskId: string) => void;
dragHandleProps?: any;
activeTaskId?: string | null;
}
const KanbanGroup: React.FC<TaskGroupProps> = ({
group,
projectId,
currentGrouping,
selectedTaskIds,
onAddTask,
onToggleCollapse,
onSelectTask,
onToggleSubtasks,
dragHandleProps,
activeTaskId,
}) => {
const [isCollapsed, setIsCollapsed] = useState(false);
const { setNodeRef, isOver } = useDroppable({
id: group.id,
data: {
type: 'group',
groupId: group.id,
},
});
// Get task IDs for sortable context
const taskIds = group.tasks.map(task => task.id!);
// Get group color based on grouping type
const getGroupColor = () => {
if (group.color_code) return group.color_code;
switch (currentGrouping) {
case 'status':
return group.id === 'todo' ? '#faad14' : group.id === 'doing' ? '#1890ff' : '#52c41a';
case 'priority':
return group.id === 'critical'
? '#ff4d4f'
: group.id === 'high'
? '#fa8c16'
: group.id === 'medium'
? '#faad14'
: '#52c41a';
case 'phase':
return '#722ed1';
default:
return '#d9d9d9';
}
};
const handleAddTask = () => {
onAddTask?.(group.id);
};
return (
<div
ref={setNodeRef}
className={`kanban-group-column${isOver ? ' drag-over' : ''}`}
>
{/* Group Header */}
<div className="kanban-group-header" style={{ backgroundColor: getGroupColor() }}>
{/* Drag handle for column */}
<Button
type="text"
size="small"
icon={<MenuOutlined />}
className="kanban-group-drag-handle"
style={{ marginRight: 8, cursor: 'grab', opacity: 0.7 }}
{...(dragHandleProps || {})}
/>
<Text strong className="kanban-group-header-text">
{group.name} <span className="kanban-group-count">({group.tasks.length})</span>
</Text>
</div>
{/* Tasks as Cards */}
<SortableContext items={taskIds} strategy={verticalListSortingStrategy}>
<div className="kanban-group-tasks">
{group.tasks.length === 0 ? (
<div className="kanban-group-empty">
<Text type="secondary">No tasks in this group</Text>
</div>
) : (
group.tasks.map((task, index) => (
task.id === activeTaskId ? (
<div key={task.id} className="kanban-task-card kanban-task-card-placeholder" />
) : (
<KanbanTaskCard
key={task.id}
task={task}
projectId={projectId}
groupId={group.id}
currentGrouping={currentGrouping}
isSelected={selectedTaskIds.includes(task.id!)}
index={index}
onSelect={onSelectTask}
onToggleSubtasks={onToggleSubtasks}
/>
)
))
)}
</div>
</SortableContext>
{/* Add Task Button */}
<div className="kanban-group-add-task">
<Button
type="dashed"
icon={<PlusOutlined />}
block
onClick={handleAddTask}
>
Add Task
</Button>
</div>
<style>{`
.kanban-group-column {
display: flex;
flex-direction: column;
background: var(--task-bg-primary, #fff);
border-radius: 8px;
box-shadow: 0 1px 3px var(--task-shadow, rgba(0,0,0,0.08));
border: 1px solid var(--task-border-primary, #e8e8e8);
min-width: 320px;
max-width: 350px;
margin: 0 12px;
padding: 0;
height: 100%;
transition: box-shadow 0.2s;
}
.kanban-group-header {
border-top-left-radius: 8px;
border-top-right-radius: 8px;
padding: 16px 16px 12px 16px;
color: #fff;
font-size: 16px;
font-weight: 600;
display: flex;
align-items: center;
min-height: 56px;
}
.kanban-group-header-text {
color: #fff !important;
font-size: 15px;
font-weight: 600;
}
.kanban-group-count {
font-size: 13px;
font-weight: 400;
margin-left: 4px;
color: #f5f5f5;
}
.kanban-group-tasks {
flex: 1;
display: flex;
flex-direction: column;
gap: 12px;
padding: 12px 12px 0 12px;
min-height: 60px;
}
.kanban-group-empty {
text-align: center;
color: #bfbfbf;
padding: 32px 0;
}
.kanban-group-add-task {
padding: 12px;
border-top: 1px solid var(--task-border-secondary, #f0f0f0);
background: var(--task-bg-primary, #fff);
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
.drag-over {
box-shadow: 0 0 0 3px #bae7ff;
border-color: #40a9ff;
}
.kanban-group-drag-handle {
color: #fff !important;
background: transparent !important;
border: none !important;
padding: 0 4px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
}
.kanban-group-drag-handle:hover {
opacity: 1 !important;
}
.kanban-task-card-placeholder {
min-height: 80px;
height: 80px;
border: 2px dashed var(--task-drag-over-border, #40a9ff);
background: var(--task-bg-primary, #fff);
border-radius: 8px;
margin-bottom: 0;
opacity: 0.5;
}
.dark .kanban-task-card-placeholder,
[data-theme="dark"] .kanban-task-card-placeholder {
background: var(--task-bg-primary, #1f1f1f);
border: 2px dashed var(--task-drag-over-border, #40a9ff);
}
`}</style>
</div>
);
};
export default KanbanGroup;