refactor(task-list): streamline task addition and socket handling

- Removed local socket listener from AddTaskRow, delegating task addition to the global socket handler for real-time updates.
- Simplified the handleTaskAdded function in TaskListV2, eliminating the need for refetching tasks upon addition.
- Updated useTaskSocketHandlers to handle task data more efficiently, ensuring proper integration with the Redux store.
This commit is contained in:
chamiakJ
2025-07-06 15:42:12 +05:30
parent a5291483f7
commit 6ba1ff57b2
3 changed files with 15 additions and 83 deletions

View File

@@ -271,10 +271,9 @@ const TaskListV2: React.FC = () => {
// Add callback for task added // Add callback for task added
const handleTaskAdded = useCallback(() => { const handleTaskAdded = useCallback(() => {
if (urlProjectId) { // Task is now added in real-time via socket, no need to refetch
dispatch(fetchTasksV3(urlProjectId)); // The global socket handler will handle the real-time update
} }, []);
}, [dispatch, urlProjectId]);
// Memoized values for GroupedVirtuoso // Memoized values for GroupedVirtuoso
const virtuosoGroups = useMemo(() => { const virtuosoGroups = useMemo(() => {

View File

@@ -1,14 +1,10 @@
import React, { useState, useCallback, memo, useEffect } from 'react'; import React, { useState, useCallback, memo } from 'react';
import { Input } from 'antd'; import { Input } from 'antd';
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useSocket } from '@/socket/socketContext'; import { useSocket } from '@/socket/socketContext';
import { SocketEvents } from '@/shared/socket-events'; import { SocketEvents } from '@/shared/socket-events';
import { useAuthService } from '@/hooks/useAuth'; import { useAuthService } from '@/hooks/useAuth';
import { useAppDispatch } from '@/hooks/useAppDispatch';
import { addTaskToGroup } from '@/features/task-management/task-management.slice';
import { Task } from '@/types/task-management.types';
import { IProjectTask } from '@/types/project/projectTasksViewModel.types';
interface AddTaskRowProps { interface AddTaskRowProps {
groupId: string; groupId: string;
@@ -35,77 +31,12 @@ const AddTaskRow: React.FC<AddTaskRowProps> = memo(({
const [taskName, setTaskName] = useState(''); const [taskName, setTaskName] = useState('');
const { socket, connected } = useSocket(); const { socket, connected } = useSocket();
const { t } = useTranslation('task-list-table'); const { t } = useTranslation('task-list-table');
const dispatch = useAppDispatch();
// Get session data for reporter_id and team_id // Get session data for reporter_id and team_id
const currentSession = useAuthService().getCurrentSession(); const currentSession = useAuthService().getCurrentSession();
// Listen for task creation completion and add to Redux store immediately // The global socket handler (useTaskSocketHandlers) will handle task addition
useEffect(() => { // No need for local socket listener to avoid duplicate additions
if (!socket) return;
const handleTaskCreated = (data: IProjectTask) => {
if (data) {
// Transform backend response to Task format for real-time addition
const task: Task = {
id: data.id || '',
task_key: data.task_key || '',
title: data.name || '',
description: data.description || '',
status: (data.status_category?.is_todo
? 'todo'
: data.status_category?.is_doing
? 'doing'
: data.status_category?.is_done
? 'done'
: 'todo') as 'todo' | 'doing' | 'done',
priority: (data.priority_value === 3
? 'critical'
: data.priority_value === 2
? 'high'
: data.priority_value === 1
? 'medium'
: 'low') as 'critical' | 'high' | 'medium' | 'low',
phase: data.phase_name || 'Development',
progress: data.complete_ratio || 0,
assignees: data.assignees?.map(a => a.team_member_id) || [],
assignee_names: data.names || [],
labels:
data.labels?.map(l => ({
id: l.id || '',
name: l.name || '',
color: l.color_code || '#1890ff',
end: l.end,
names: l.names,
})) || [],
dueDate: data.end_date,
startDate: data.start_date,
timeTracking: {
estimated: (data.total_hours || 0) + (data.total_minutes || 0) / 60,
logged: (data.time_spent?.hours || 0) + (data.time_spent?.minutes || 0) / 60,
},
created_at: data.created_at || new Date().toISOString(),
updated_at: data.updated_at || new Date().toISOString(),
order: data.sort_order || 0,
sub_tasks: [],
sub_tasks_count: 0,
show_sub_tasks: false,
};
// Add task to the correct group in Redux store for immediate UI update
dispatch(addTaskToGroup({ task, groupId }));
// Optional: Call onTaskAdded for any additional UI updates
onTaskAdded();
}
};
socket.on(SocketEvents.QUICK_TASK.toString(), handleTaskCreated);
return () => {
socket.off(SocketEvents.QUICK_TASK.toString(), handleTaskCreated);
};
}, [socket, onTaskAdded, dispatch, groupId]);
const handleAddTask = useCallback(() => { const handleAddTask = useCallback(() => {
if (!taskName.trim() || !currentSession) return; if (!taskName.trim() || !currentSession) return;
@@ -147,7 +78,7 @@ const AddTaskRow: React.FC<AddTaskRowProps> = memo(({
} catch (error) { } catch (error) {
console.error('Error creating task:', error); console.error('Error creating task:', error);
} }
}, [taskName, projectId, groupType, groupValue, socket, connected, currentSession, onTaskAdded]); }, [taskName, projectId, groupType, groupValue, socket, connected, currentSession]);
const handleCancel = useCallback(() => { const handleCancel = useCallback(() => {
setTaskName(''); setTaskName('');

View File

@@ -575,7 +575,9 @@ export const useTaskSocketHandlers = () => {
); );
const handleNewTaskReceived = useCallback( const handleNewTaskReceived = useCallback(
(data: IProjectTask) => { (response: any) => {
// Handle array format response [index, taskData]
const data = Array.isArray(response) ? response[1] : response;
if (!data) return; if (!data) return;
if (data.parent_task_id) { if (data.parent_task_id) {
// Handle subtask creation // Handle subtask creation
@@ -600,10 +602,10 @@ export const useTaskSocketHandlers = () => {
: 'low') as 'critical' | 'high' | 'medium' | 'low', : 'low') as 'critical' | 'high' | 'medium' | 'low',
phase: data.phase_name || 'Development', phase: data.phase_name || 'Development',
progress: data.complete_ratio || 0, progress: data.complete_ratio || 0,
assignees: data.assignees?.map(a => a.team_member_id) || [], assignees: data.assignees?.map((a: any) => a.team_member_id) || [],
assignee_names: data.names || [], assignee_names: data.names || [],
labels: labels:
data.labels?.map(l => ({ data.labels?.map((l: any) => ({
id: l.id || '', id: l.id || '',
name: l.name || '', name: l.name || '',
color: l.color_code || '#1890ff', color: l.color_code || '#1890ff',
@@ -654,10 +656,10 @@ export const useTaskSocketHandlers = () => {
: 'low') as 'critical' | 'high' | 'medium' | 'low', : 'low') as 'critical' | 'high' | 'medium' | 'low',
phase: data.phase_name || 'Development', phase: data.phase_name || 'Development',
progress: data.complete_ratio || 0, progress: data.complete_ratio || 0,
assignees: data.assignees?.map(a => a.team_member_id) || [], assignees: data.assignees?.map((a: any) => a.team_member_id) || [],
assignee_names: data.names || [], assignee_names: data.names || [],
labels: labels:
data.labels?.map(l => ({ data.labels?.map((l: any) => ({
id: l.id || '', id: l.id || '',
name: l.name || '', name: l.name || '',
color: l.color_code || '#1890ff', color: l.color_code || '#1890ff',
@@ -697,7 +699,7 @@ export const useTaskSocketHandlers = () => {
} }
// Use addTaskToGroup with the actual group UUID // Use addTaskToGroup with the actual group UUID
dispatch(addTaskToGroup({ task, groupId })); dispatch(addTaskToGroup({ task, groupId: groupId || '' }));
// Also update enhanced kanban slice for regular task creation // Also update enhanced kanban slice for regular task creation
dispatch( dispatch(