Merge branch 'fix/enhanced-task-board' into fix/get-pull-6-26

This commit is contained in:
shancds
2025-06-26 12:18:29 +05:30
3 changed files with 46 additions and 18 deletions

View File

@@ -45,6 +45,7 @@ import alertService from '@/services/alerts/alertService';
import { IGroupBy } from '@/features/enhanced-kanban/enhanced-kanban.slice'; import { IGroupBy } from '@/features/enhanced-kanban/enhanced-kanban.slice';
import EnhancedKanbanCreateSection from './EnhancedKanbanCreateSection'; import EnhancedKanbanCreateSection from './EnhancedKanbanCreateSection';
import ImprovedTaskFilters from '../task-management/improved-task-filters'; import ImprovedTaskFilters from '../task-management/improved-task-filters';
import { fetchStatusesCategories } from '@/features/taskAttributes/taskStatusSlice';
// Import the TaskListFilters component // Import the TaskListFilters component
const TaskListFilters = React.lazy(() => import('@/pages/projects/projectView/taskList/task-list-filters/task-list-filters')); const TaskListFilters = React.lazy(() => import('@/pages/projects/projectView/taskList/task-list-filters/task-list-filters'));
@@ -66,7 +67,7 @@ const EnhancedKanbanBoard: React.FC<EnhancedKanbanBoardProps> = ({ projectId, cl
const { teamId } = useAppSelector((state: RootState) => state.auth); const { teamId } = useAppSelector((state: RootState) => state.auth);
const groupBy = useSelector((state: RootState) => state.enhancedKanbanReducer.groupBy); const groupBy = useSelector((state: RootState) => state.enhancedKanbanReducer.groupBy);
const project = useAppSelector((state: RootState) => state.projectReducer.project); const project = useAppSelector((state: RootState) => state.projectReducer.project);
const { statusCategories, status: existingStatuses } = useAppSelector((state) => state.taskStatusReducer);
// Local state for drag overlay // Local state for drag overlay
const [activeTask, setActiveTask] = useState<any>(null); const [activeTask, setActiveTask] = useState<any>(null);
const [activeGroup, setActiveGroup] = useState<any>(null); const [activeGroup, setActiveGroup] = useState<any>(null);
@@ -86,6 +87,9 @@ const EnhancedKanbanBoard: React.FC<EnhancedKanbanBoardProps> = ({ projectId, cl
if (projectId) { if (projectId) {
dispatch(fetchEnhancedKanbanGroups(projectId) as any); dispatch(fetchEnhancedKanbanGroups(projectId) as any);
} }
if (!statusCategories.length) {
dispatch(fetchStatusesCategories() as any);
}
}, [dispatch, projectId]); }, [dispatch, projectId]);
// Get all task IDs for sortable context // Get all task IDs for sortable context
@@ -385,10 +389,10 @@ const EnhancedKanbanBoard: React.FC<EnhancedKanbanBoardProps> = ({ projectId, cl
<> <>
{/* Task Filters */} {/* Task Filters */}
<div className="mb-4"> <div className="mb-4">
<React.Suspense fallback={<div>Loading filters...</div>}> <React.Suspense fallback={<div>Loading filters...</div>}>
<ImprovedTaskFilters position="board" /> <ImprovedTaskFilters position="board" />
</React.Suspense> </React.Suspense>
</div> </div>
<div className={`enhanced-kanban-board ${className}`}> <div className={`enhanced-kanban-board ${className}`}>
{/* Performance Monitor - only show for large datasets */} {/* Performance Monitor - only show for large datasets */}
{/* {performanceMetrics.totalTasks > 100 && <PerformanceMonitor />} */} {/* {performanceMetrics.totalTasks > 100 && <PerformanceMonitor />} */}

View File

@@ -38,9 +38,11 @@ const EnhancedKanbanCreateTaskCard: React.FC<EnhancedKanbanCreateTaskCardProps>
const groupBy = useAppSelector(state => state.enhancedKanbanReducer.groupBy); const groupBy = useAppSelector(state => state.enhancedKanbanReducer.groupBy);
useEffect(() => { useEffect(() => {
setTimeout(() => { const timer = setTimeout(() => {
inputRef.current?.focus(); inputRef.current?.focus();
}, 100); }, 100);
return () => clearTimeout(timer);
}, []); }, []);
const createRequestBody = (): ITaskCreateRequest | null => { const createRequestBody = (): ITaskCreateRequest | null => {
@@ -66,18 +68,30 @@ const EnhancedKanbanCreateTaskCard: React.FC<EnhancedKanbanCreateTaskCardProps>
}, 100); }, 100);
}; };
const resetForNextTask = () => {
setNewTaskName('');
setCreatingTask(false);
// Keep the card visible for creating the next task
setTimeout(() => {
inputRef.current?.focus();
}, 100);
};
const handleAddTask = async () => { const handleAddTask = async () => {
if (creatingTask || !projectId || !currentSession || newTaskName.trim() === '') return; if (creatingTask || !projectId || !currentSession || newTaskName.trim() === '') return;
setCreatingTask(true);
const body = createRequestBody(); const body = createRequestBody();
if (!body) return; if (!body) {
setCreatingTask(true);
setShowNewCard(true);
return;
}
// Real-time socket event handler // Real-time socket event handler
const eventHandler = (task: IProjectTask) => { const eventHandler = (task: IProjectTask) => {
setCreatingTask(false);
dispatch(addTaskToGroup({ sectionId, task: { ...task, id: task.id || nanoid(), name: task.name || newTaskName.trim() } })); dispatch(addTaskToGroup({ sectionId, task: { ...task, id: task.id || nanoid(), name: task.name || newTaskName.trim() } }));
socket?.off(SocketEvents.QUICK_TASK.toString(), eventHandler); socket?.off(SocketEvents.QUICK_TASK.toString(), eventHandler);
resetForm(); resetForNextTask();
}; };
socket?.once(SocketEvents.QUICK_TASK.toString(), eventHandler); socket?.once(SocketEvents.QUICK_TASK.toString(), eventHandler);
socket?.emit(SocketEvents.QUICK_TASK.toString(), JSON.stringify(body)); socket?.emit(SocketEvents.QUICK_TASK.toString(), JSON.stringify(body));
@@ -89,6 +103,13 @@ const EnhancedKanbanCreateTaskCard: React.FC<EnhancedKanbanCreateTaskCardProps>
setCreatingTask(false); setCreatingTask(false);
}; };
const handleBlur = () => {
if (newTaskName.trim() === '') {
setCreatingTask(false);
setShowNewCard(false);
}
};
return ( return (
<Flex <Flex
ref={cardRef} ref={cardRef}
@@ -111,9 +132,11 @@ const EnhancedKanbanCreateTaskCard: React.FC<EnhancedKanbanCreateTaskCardProps>
> >
<Input <Input
ref={inputRef} ref={inputRef}
autoFocus
value={newTaskName} value={newTaskName}
onChange={e => setNewTaskName(e.target.value)} onChange={e => setNewTaskName(e.target.value)}
onPressEnter={handleAddTask} onPressEnter={handleAddTask}
onBlur={handleBlur}
placeholder={t('newTaskNamePlaceholder')} placeholder={t('newTaskNamePlaceholder')}
style={{ style={{
width: '100%', width: '100%',

View File

@@ -7,18 +7,19 @@ import { fetchStatuses, fetchStatusesCategories } from '@/features/taskAttribute
import { useMixpanelTracking } from '@/hooks/useMixpanelTracking'; import { useMixpanelTracking } from '@/hooks/useMixpanelTracking';
import useTabSearchParam from '@/hooks/useTabSearchParam'; import useTabSearchParam from '@/hooks/useTabSearchParam';
import { fetchTaskGroups } from '@/features/tasks/tasks.slice'; import { fetchTaskGroups } from '@/features/tasks/tasks.slice';
import { fetchBoardTaskGroups } from '@/features/board/board-slice';
import { deleteStatusToggleDrawer } from '@/features/projects/status/DeleteStatusSlice'; import { deleteStatusToggleDrawer } from '@/features/projects/status/DeleteStatusSlice';
import { Drawer, Alert, Card, Select, Button, Typography, Badge } from 'antd'; import { Drawer, Alert, Card, Select, Button, Typography, Badge } from 'antd';
import { DownOutlined } from '@ant-design/icons'; import { DownOutlined } from '@ant-design/icons';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { import {
deleteSection, deleteSection,
IGroupBy, IGroupBy,
} from '@features/board/board-slice'; } from '@features/board/board-slice';
import { statusApiService } from '@/api/taskAttributes/status/status.api.service'; import { statusApiService } from '@/api/taskAttributes/status/status.api.service';
import { phasesApiService } from '@/api/taskAttributes/phases/phases.api.service'; import { phasesApiService } from '@/api/taskAttributes/phases/phases.api.service';
import logger from '@/utils/errorLogger'; import logger from '@/utils/errorLogger';
import { fetchEnhancedKanbanGroups } from '@/features/enhanced-kanban/enhanced-kanban.slice';
const { Title, Text } = Typography; const { Title, Text } = Typography;
const { Option } = Select; const { Option } = Select;
@@ -43,8 +44,8 @@ const DeleteStatusDrawer: React.FC = () => {
const refreshTasks = useCallback(() => { const refreshTasks = useCallback(() => {
if (!projectId) return; if (!projectId) return;
const fetchAction = projectView === 'list' ? fetchTaskGroups : fetchBoardTaskGroups; const fetchAction = projectView === 'list' ? fetchTaskGroups : fetchEnhancedKanbanGroups;
dispatch(fetchAction(projectId)); dispatch(fetchAction(projectId) as any);
}, [projectId, projectView, dispatch]); }, [projectId, projectView, dispatch]);
const handleDrawerOpenChange = () => { const handleDrawerOpenChange = () => {
@@ -71,7 +72,7 @@ const DeleteStatusDrawer: React.FC = () => {
dispatch(fetchStatuses(projectId)); dispatch(fetchStatuses(projectId));
refreshTasks(); refreshTasks();
dispatch(fetchStatusesCategories()); dispatch(fetchStatusesCategories());
} else{ } else {
console.error('Error deleting status', res); console.error('Error deleting status', res);
} }
} else if (groupBy === IGroupBy.PHASE) { } else if (groupBy === IGroupBy.PHASE) {
@@ -83,7 +84,7 @@ const DeleteStatusDrawer: React.FC = () => {
} catch (error) { } catch (error) {
logger.error('Error deleting section', error); logger.error('Error deleting section', error);
}finally { } finally {
setDeletingStatus(false); setDeletingStatus(false);
} }
}; };
@@ -98,7 +99,7 @@ const DeleteStatusDrawer: React.FC = () => {
open={isDelteStatusDrawerOpen} open={isDelteStatusDrawerOpen}
afterOpenChange={handleDrawerOpenChange} afterOpenChange={handleDrawerOpenChange}
> >
<Alert type="warning" message={selectedForDelete?.message.replace("$","")} /> <Alert type="warning" message={selectedForDelete?.message.replace("$", "")} />
<Card className="text-center" style={{ marginTop: 16 }}> <Card className="text-center" style={{ marginTop: 16 }}>
<Title level={5}>{selectedForDelete?.name}</Title> <Title level={5}>{selectedForDelete?.name}</Title>