tududi/frontend/utils/taskSortUtils.ts
Chris a8548b045b
Introduce sort utils (#709)
* Introduce sort utils

* Fix test issues
2025-12-14 01:13:57 +02:00

60 lines
2.2 KiB
TypeScript

import { Task } from '../entities/Task';
interface SortOptions {
excludeFutureDeferred?: boolean;
}
/**
* Multi-criteria sorting for tasks in Today view sections.
* Sorting order:
* 1. Priority (High → Medium → Low → None)
* 2. Due date (earlier first, null/undefined last)
* 3. Project (tasks with same priority and due date grouped by project)
*
* This function is used to ensure consistent task ordering across all Today sections
* (Planned, Due Today, Overdue, Suggested) as per issue #653.
*/
export const sortTasksByPriorityDueDateProject = (
tasks: Task[],
options: SortOptions = {}
): Task[] => {
if (!tasks || tasks.length === 0) return [];
const shouldExcludeDeferred = options.excludeFutureDeferred;
const now = Date.now();
const filteredTasks = shouldExcludeDeferred
? tasks.filter((task) => {
if (!task.defer_until) return true;
const deferUntil = new Date(task.defer_until).getTime();
if (Number.isNaN(deferUntil)) return true;
return deferUntil <= now;
})
: tasks;
if (filteredTasks.length === 0) return [];
return [...filteredTasks].sort((a, b) => {
// 1. Priority (High → Medium → Low → None)
const priorityOrder = { high: 3, medium: 2, low: 1 };
const aPriority =
priorityOrder[a.priority as keyof typeof priorityOrder] || 0;
const bPriority =
priorityOrder[b.priority as keyof typeof priorityOrder] || 0;
if (aPriority !== bPriority) {
return bPriority - aPriority; // Higher priority first
}
// 2. Due date (earlier first, null/undefined last)
const aDueDate = a.due_date ? new Date(a.due_date).getTime() : Infinity;
const bDueDate = b.due_date ? new Date(b.due_date).getTime() : Infinity;
if (aDueDate !== bDueDate) {
return aDueDate - bDueDate;
}
// 3. Project (tasks with same priority and due date grouped by project)
const aProject = a.project_id || '';
const bProject = b.project_id || '';
return aProject.toString().localeCompare(bProject.toString());
});
};