Implement task completion prompt and enhance progress handling

- Added logic to prompt users to mark tasks as done when progress reaches 100%, integrating with the socket events for real-time updates.
- Updated backend functions to check task statuses and determine if a prompt is necessary based on the task's current state.
- Enhanced frontend components to display a modal for confirming task completion, improving user experience and clarity in task management.
- Refactored socket event handling to include new events for retrieving "done" statuses, ensuring accurate task status updates across the application.
This commit is contained in:
chamikaJ
2025-05-02 17:05:16 +05:30
parent a5b881c609
commit a368b979d5
9 changed files with 239 additions and 34 deletions

View File

@@ -1,11 +1,11 @@
import { Form, InputNumber, Tooltip } from 'antd';
import { Form, InputNumber, Tooltip, Modal } from 'antd';
import { useTranslation } from 'react-i18next';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { useAppSelector } from '@/hooks/useAppSelector';
import { ITaskViewModel } from '@/types/tasks/task.types';
import Flex from 'antd/lib/flex';
import { SocketEvents } from '@/shared/socket-events';
import { useEffect, useState } from 'react';
import { useState, useEffect } from 'react';
import { useSocket } from '@/socket/socketContext';
interface TaskDrawerProgressProps {
@@ -17,42 +17,20 @@ const TaskDrawerProgress = ({ task, form }: TaskDrawerProgressProps) => {
const { t } = useTranslation('task-drawer/task-drawer');
const { project } = useAppSelector(state => state.projectReducer);
const { socket, connected } = useSocket();
const [confirmedHasSubtasks, setConfirmedHasSubtasks] = useState<boolean | null>(null);
const [isCompletionModalVisible, setIsCompletionModalVisible] = useState(false);
const isSubTask = !!task?.parent_task_id;
const hasSubTasks = task?.sub_tasks_count > 0 || confirmedHasSubtasks === true;
// Safe handling of sub_tasks_count which might be undefined in some cases
const hasSubTasks = (task?.sub_tasks_count || 0) > 0;
// Additional debug logging
console.log(`TaskDrawerProgress for task ${task.id} (${task.name}): hasSubTasks=${hasSubTasks}, count=${task.sub_tasks_count}, confirmedHasSubtasks=${confirmedHasSubtasks}`);
// Log task details for debugging
console.log(`TaskDrawerProgress: task=${task?.id}, sub_tasks_count=${task?.sub_tasks_count}, hasSubTasks=${hasSubTasks}`);
// HIGHEST PRIORITY CHECK: Never show progress inputs for parent tasks with subtasks
// This check happens before any other logic to ensure consistency
if (hasSubTasks) {
console.error(`REJECTED: Progress input for parent task ${task.id} with ${task.sub_tasks_count} subtasks. confirmedHasSubtasks=${confirmedHasSubtasks}`);
return null;
}
// Double-check by directly querying for subtasks from the server
useEffect(() => {
if (connected && task.id) {
socket?.emit(SocketEvents.GET_TASK_SUBTASKS_COUNT.toString(), task.id);
}
// Listen for the subtask count response
const handleSubtasksCount = (data: any) => {
if (data.task_id === task.id) {
console.log(`Received subtask count for task ${task.id}: ${data.subtask_count}, has_subtasks=${data.has_subtasks}`);
setConfirmedHasSubtasks(data.has_subtasks);
}
};
socket?.on(SocketEvents.TASK_SUBTASKS_COUNT.toString(), handleSubtasksCount);
return () => {
socket?.off(SocketEvents.TASK_SUBTASKS_COUNT.toString(), handleSubtasksCount);
};
}, [socket, connected, task.id]);
// Never show manual progress input for parent tasks (tasks with subtasks)
// Only show progress input for tasks without subtasks
const showManualProgressInput = !hasSubTasks;
@@ -70,6 +48,11 @@ const TaskDrawerProgress = ({ task, form }: TaskDrawerProgressProps) => {
if (data.weight !== undefined) {
form.setFieldsValue({ weight: data.weight });
}
// Check if we should prompt the user to mark the task as done
if (data.should_prompt_for_done) {
setIsCompletionModalVisible(true);
}
}
};
@@ -92,6 +75,11 @@ const TaskDrawerProgress = ({ task, form }: TaskDrawerProgressProps) => {
const handleProgressChange = (value: number | null) => {
if (connected && task.id && value !== null && !hasSubTasks) {
// Check if progress is set to 100% to show completion confirmation
if (value === 100) {
setIsCompletionModalVisible(true);
}
// Ensure parent_task_id is not undefined
const parent_task_id = task.parent_task_id || null;
@@ -136,6 +124,36 @@ const TaskDrawerProgress = ({ task, form }: TaskDrawerProgressProps) => {
}
};
const handleMarkTaskAsComplete = () => {
// Close the modal
setIsCompletionModalVisible(false);
// Find a "Done" status for this project
if (connected && task.id) {
// Emit socket event to get "done" category statuses
socket?.emit(SocketEvents.GET_DONE_STATUSES.toString(), task.project_id, (doneStatuses: any[]) => {
if (doneStatuses && doneStatuses.length > 0) {
// Use the first "done" status
const doneStatusId = doneStatuses[0].id;
// Emit socket event to update the task status
socket?.emit(
SocketEvents.TASK_STATUS_CHANGE.toString(),
JSON.stringify({
task_id: task.id,
status_id: doneStatusId,
project_id: task.project_id
})
);
console.log(`Task ${task.id} marked as done with status ${doneStatusId}`);
} else {
console.error(`No "done" statuses found for project ${task.project_id}`);
}
});
}
};
const percentFormatter = (value: number | undefined) => (value ? `${value}%` : '0%');
const percentParser = (value: string | undefined) => {
const parsed = parseInt(value?.replace('%', '') || '0', 10);
@@ -217,6 +235,17 @@ const TaskDrawerProgress = ({ task, form }: TaskDrawerProgressProps) => {
/>
</Form.Item>
)}
<Modal
title="Mark Task as Done?"
open={isCompletionModalVisible}
onOk={handleMarkTaskAsComplete}
onCancel={() => setIsCompletionModalVisible(false)}
okText="Yes, mark as done"
cancelText="No, keep current status"
>
<p>You've set the progress to 100%. Would you like to update the task status to "Done"?</p>
</Modal>
</>
);
};

View File

@@ -67,4 +67,7 @@ export enum SocketEvents {
// Task subtasks count events
GET_TASK_SUBTASKS_COUNT,
TASK_SUBTASKS_COUNT,
// Task completion events
GET_DONE_STATUSES,
}