Fix test issues
This commit is contained in:
parent
dbe724f1a7
commit
a4e2a97cb1
2 changed files with 107 additions and 43 deletions
|
|
@ -1683,7 +1683,77 @@ router.patch('/task/:id', async (req, res) => {
|
|||
taskAttributes.parent_task_id = null;
|
||||
}
|
||||
|
||||
// Check if any recurrence settings are changing and cleanup future instances if needed
|
||||
const recurrenceFields = [
|
||||
'recurrence_type',
|
||||
'recurrence_interval',
|
||||
'recurrence_end_date',
|
||||
'recurrence_weekday',
|
||||
'recurrence_month_day',
|
||||
'recurrence_week_of_month',
|
||||
'completion_based',
|
||||
];
|
||||
|
||||
const recurrenceChanged = recurrenceFields.some((field) => {
|
||||
const newValue = req.body[field];
|
||||
return newValue !== undefined && newValue !== task[field];
|
||||
});
|
||||
|
||||
// Only cleanup if recurrence changed AND the old task was recurring (not 'none')
|
||||
// This prevents cleanup when changing TO 'none' from 'none'
|
||||
if (recurrenceChanged && task.recurrence_type !== 'none') {
|
||||
// Find child instances of this recurring task
|
||||
const childTasks = await Task.findAll({
|
||||
where: { recurring_parent_id: task.id },
|
||||
});
|
||||
|
||||
if (childTasks.length > 0) {
|
||||
const now = new Date();
|
||||
|
||||
// Separate future and past instances
|
||||
const futureInstances = childTasks.filter((child) => {
|
||||
if (!child.due_date) return true; // Tasks without due_date are considered future (not yet scheduled)
|
||||
return new Date(child.due_date) > now;
|
||||
});
|
||||
|
||||
// Only cleanup future instances if not changing to 'none'
|
||||
const newRecurrenceType =
|
||||
recurrence_type !== undefined
|
||||
? recurrence_type
|
||||
: task.recurrence_type;
|
||||
if (newRecurrenceType !== 'none') {
|
||||
// Delete future instances since recurrence changed
|
||||
for (const futureInstance of futureInstances) {
|
||||
await futureInstance.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// Past instances remain as orphaned instances (no changes needed)
|
||||
// This allows users to keep their completed/in-progress work
|
||||
}
|
||||
}
|
||||
|
||||
await task.update(taskAttributes);
|
||||
|
||||
// Generate new recurring tasks after updating recurrence settings (if still recurring)
|
||||
if (recurrenceChanged && task.recurrence_type !== 'none') {
|
||||
const newRecurrenceType =
|
||||
recurrence_type !== undefined
|
||||
? recurrence_type
|
||||
: task.recurrence_type;
|
||||
if (newRecurrenceType !== 'none') {
|
||||
try {
|
||||
// Generate new recurring tasks for the updated pattern
|
||||
await generateRecurringTasks(req.currentUser.id, 7);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
'Error generating new recurring tasks after update:',
|
||||
error
|
||||
);
|
||||
// Don't fail the update if regeneration fails
|
||||
}
|
||||
}
|
||||
}
|
||||
await updateTaskTags(task, tagsData, req.currentUser.id);
|
||||
|
||||
// Handle subtasks updates
|
||||
|
|
@ -2147,16 +2217,45 @@ router.delete('/task/:id', async (req, res) => {
|
|||
return res.status(404).json({ error: 'Task not found.' });
|
||||
}
|
||||
|
||||
// Check for child tasks - prevent deletion of parent tasks with children
|
||||
// Check for child tasks and handle smart deletion for recurring tasks
|
||||
const childTasks = await Task.findAll({
|
||||
where: { recurring_parent_id: req.params.id },
|
||||
});
|
||||
|
||||
// If this is a recurring parent task with children, prevent deletion
|
||||
// If this is a recurring parent task with children, implement smart deletion
|
||||
if (childTasks.length > 0) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: 'There was a problem deleting the task.' });
|
||||
const now = new Date();
|
||||
|
||||
// Separate past and future instances
|
||||
const futureInstances = childTasks.filter((child) => {
|
||||
if (!child.due_date) return true; // Tasks without due_date are considered future (not yet scheduled)
|
||||
return new Date(child.due_date) > now;
|
||||
});
|
||||
|
||||
const pastInstances = childTasks.filter((child) => {
|
||||
if (!child.due_date) return false; // Tasks without due_date are considered future, not past
|
||||
return new Date(child.due_date) <= now;
|
||||
});
|
||||
|
||||
// Delete future instances
|
||||
for (const futureInstance of futureInstances) {
|
||||
await futureInstance.destroy();
|
||||
}
|
||||
|
||||
// Orphan past instances (remove parent relationship)
|
||||
for (const pastInstance of pastInstances) {
|
||||
await pastInstance.update({
|
||||
recurring_parent_id: null,
|
||||
recurrence_type: 'none',
|
||||
recurrence_interval: null,
|
||||
recurrence_end_date: null,
|
||||
last_generated_date: null,
|
||||
recurrence_weekday: null,
|
||||
recurrence_month_day: null,
|
||||
recurrence_week_of_month: null,
|
||||
completion_based: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const taskEvents = await TaskEvent.findAll({
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useParams, Link, useNavigate } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
|
|
@ -393,31 +393,6 @@ const TaskDetails: React.FC = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const handleSubtaskClick = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.nativeEvent.stopImmediatePropagation();
|
||||
|
||||
// Store the intent to open modal in sessionStorage (survives re-mounts)
|
||||
const modalState = {
|
||||
isOpen: true,
|
||||
focusSubtasks: true,
|
||||
taskId: uid,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
sessionStorage.setItem(
|
||||
'pendingModalState',
|
||||
JSON.stringify(modalState)
|
||||
);
|
||||
|
||||
// Set state immediately
|
||||
setFocusSubtasks(true);
|
||||
setIsTaskModalOpen(true);
|
||||
},
|
||||
[uid]
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
return <LoadingScreen />;
|
||||
}
|
||||
|
|
@ -700,8 +675,7 @@ const TaskDetails: React.FC = () => {
|
|||
className="group"
|
||||
>
|
||||
<div
|
||||
onClick={handleSubtaskClick}
|
||||
className={`rounded-lg shadow-sm bg-white dark:bg-gray-900 border-2 cursor-pointer transition-all duration-200 ${
|
||||
className={`rounded-lg shadow-sm bg-white dark:bg-gray-900 border-2 transition-all duration-200 ${
|
||||
subtask.status ===
|
||||
'in_progress' ||
|
||||
subtask.status === 1
|
||||
|
|
@ -813,10 +787,7 @@ const TaskDetails: React.FC = () => {
|
|||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
onClick={handleSubtaskClick}
|
||||
className="rounded-lg shadow-sm bg-white dark:bg-gray-900 border-2 border-gray-50 dark:border-gray-800 p-6 cursor-pointer hover:border-blue-200 dark:hover:border-blue-700 transition-colors duration-200"
|
||||
>
|
||||
<div className="rounded-lg shadow-sm bg-white dark:bg-gray-900 border-2 border-gray-50 dark:border-gray-800 p-6">
|
||||
<div className="flex flex-col items-center justify-center py-8 text-gray-500 dark:text-gray-400">
|
||||
<ListBulletIcon className="h-12 w-12 mb-3 opacity-50" />
|
||||
<span className="text-sm text-center">
|
||||
|
|
@ -825,12 +796,6 @@ const TaskDetails: React.FC = () => {
|
|||
'No subtasks yet'
|
||||
)}
|
||||
</span>
|
||||
<span className="text-xs text-center mt-2 text-blue-500 dark:text-blue-400">
|
||||
{t(
|
||||
'task.clickToAddSubtasks',
|
||||
'Click to add subtasks'
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue