-
-
Notifications
You must be signed in to change notification settings - Fork 92
Expand file tree
/
Copy pathsorting.ts
More file actions
111 lines (92 loc) · 3.27 KB
/
sorting.ts
File metadata and controls
111 lines (92 loc) · 3.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import { parseAbsoluteToLocal } from "@internationalized/date";
import type { Task } from "@/data//task";
import { DueDate } from "@/data/dueDate";
import { SortingVariant } from "@/query/query";
export function sortTasks<T extends Task>(tasks: T[], sort: SortingVariant[]) {
tasks.sort((first, second) => {
for (const sorting of sort) {
const cmp = compareTask(first, second, sorting);
if (cmp === 0) {
continue;
}
return cmp;
}
return 0;
});
}
// Result of "LT zero" means that self is before other,
// Result of '0' means that they are equal
// Result of "GT zero" means that self is after other
function compareTask<T extends Task>(self: T, other: T, sorting: SortingVariant): number {
switch (sorting) {
case SortingVariant.Priority:
// Note that priority in the API is reversed to that of in the app.
return other.priority - self.priority;
case SortingVariant.PriorityAscending:
return self.priority - other.priority;
case SortingVariant.Date:
return compareTaskDate(self, other);
case SortingVariant.DateDescending:
return -compareTaskDate(self, other);
case SortingVariant.Order:
return self.order - other.order;
case SortingVariant.DateAdded:
return compareTaskDateAdded(self, other);
case SortingVariant.DateAddedDescending:
return -compareTaskDateAdded(self, other);
case SortingVariant.Alphabetical:
return compareTaskAlphabetical(self, other);
case SortingVariant.AlphabeticalDescending:
return -compareTaskAlphabetical(self, other);
default:
throw new Error(`Unexpected sorting type: '${sorting}'`);
}
}
function compareTaskDate<T extends Task>(self: T, other: T): number {
// We will sort items using the following algorithm:
// 1. Any items without a due date are always after those with.
// 2. Any items on the same day, but without time are always sorted after those with time.
if (self.due === undefined) {
if (other.due === undefined) {
return 0;
}
// Self doesn't have date, but other does
return 1;
}
// Self has date, but other doesn't
if (other.due === undefined) {
return -1;
}
const selfInfo = DueDate.parse(self.due).start;
const otherInfo = DueDate.parse(other.due).start;
// Then lets check if we are the same day, if not
// sort just based on the day.
if (!isSameDay(selfInfo.raw, otherInfo.raw)) {
return selfInfo.raw < otherInfo.raw ? -1 : 1;
}
if (selfInfo.hasTime && !otherInfo.hasTime) {
return -1;
}
if (!selfInfo.hasTime && otherInfo.hasTime) {
return 1;
}
if (!selfInfo.hasTime && !otherInfo.hasTime) {
return 0;
}
return selfInfo.raw < otherInfo.raw ? -1 : 1;
}
function compareTaskDateAdded<T extends Task>(self: T, other: T): number {
const selfDate = parseAbsoluteToLocal(self.createdAt);
const otherDate = parseAbsoluteToLocal(other.createdAt);
return selfDate.compare(otherDate) < 0 ? -1 : 1;
}
function compareTaskAlphabetical<T extends Task>(self: T, other: T): number {
return self.content.localeCompare(other.content, undefined, { sensitivity: "base" });
}
function isSameDay(a: Date, b: Date): boolean {
return (
a.getFullYear() === b.getFullYear() &&
a.getMonth() === b.getMonth() &&
a.getDate() === b.getDate()
);
}