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:
@@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -67,4 +67,7 @@ export enum SocketEvents {
|
||||
// Task subtasks count events
|
||||
GET_TASK_SUBTASKS_COUNT,
|
||||
TASK_SUBTASKS_COUNT,
|
||||
|
||||
// Task completion events
|
||||
GET_DONE_STATUSES,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user