68 lines
2.5 KiB
TypeScript
68 lines
2.5 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)
|
|
// Handle both string ('low', 'medium', 'high') and numeric (0, 1, 2) priority values
|
|
const getPriorityValue = (priority: any): number => {
|
|
if (typeof priority === 'number') {
|
|
// Backend numeric format: 0 = LOW, 1 = MEDIUM, 2 = HIGH
|
|
return priority;
|
|
}
|
|
// Frontend string format
|
|
const priorityOrder = { high: 2, medium: 1, low: 0 };
|
|
return priorityOrder[priority as keyof typeof priorityOrder] ?? -1;
|
|
};
|
|
|
|
const aPriority = getPriorityValue(a.priority);
|
|
const bPriority = getPriorityValue(b.priority);
|
|
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());
|
|
});
|
|
};
|