Skip to content

Commit 2e363b2

Browse files
committed
refactor: rename sorting functions for clarity and consistency
1 parent 6af6906 commit 2e363b2

File tree

2 files changed

+170
-4
lines changed

2 files changed

+170
-4
lines changed

config/default/tasks.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,14 @@ function checkTaskResolvedForHomeVisit(contact, report, event, dueDate) {
4848
return isFormArraySubmittedInWindow(contact.reports, ['pregnancy_home_visit'], startTime, endTime);
4949
}
5050

51-
module.exports = [
51+
function getPriorityCategory(score) {
52+
if (score < 6){ return 'Low priority';}
53+
else if (score >= 6 && score <= 8){ return 'Medium priority';}
54+
else if (score > 8){ return 'High priority';}
55+
return '';
56+
}
5257

58+
module.exports = [
5359
//ANC Home Visit: 12, 20, 26, 30, 34, 36, 38, 40 weeks (Known LMP)
5460
{
5561
name: 'anc.pregnancy_home_visit.known_lmp',
@@ -97,7 +103,17 @@ module.exports = [
97103
},
98104

99105
resolvedIf: checkTaskResolvedForHomeVisit,
100-
106+
priority: function(contact, report) {
107+
console.warn('CONTACT', contact);
108+
console.warn('REPORT', report);
109+
const taskTypeScore = 8;
110+
const individualScore = 2;
111+
const score = taskTypeScore + individualScore;
112+
return {
113+
level: score,
114+
label: getPriorityCategory(score),
115+
};
116+
},
101117
actions: [
102118
{
103119
type: 'report',
@@ -129,6 +145,14 @@ module.exports = [
129145
return isFormArraySubmittedInWindow(contact.reports, ['pregnancy_facility_visit_reminder'], startTime, endTime);
130146

131147
},
148+
priority: function(contact, report) {
149+
console.warn('CONTACT', contact);
150+
console.warn('REPORT', report);
151+
return {
152+
level: 'medium',
153+
label: '',
154+
};
155+
},
132156
actions: [{
133157
type: 'report',
134158
form: 'pregnancy_facility_visit_reminder',

webapp/src/ts/reducers/tasks.ts

Lines changed: 144 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ const initialState = {
1414
},
1515
};
1616

17-
const orderByDueDate = (t1, t2) => {
17+
18+
const orderByDueDateAndPriority1 = (t1, t2) => {
1819
const lhs = t1?.dueDate;
1920
const rhs = t2?.dueDate;
2021
if (!lhs && !rhs) {
@@ -30,14 +31,155 @@ const orderByDueDate = (t1, t2) => {
3031
return lhs < rhs ? -1 : 1;
3132
};
3233

34+
/**
35+
* Task prioritization algorithm that combines:
36+
* 1. Overdue status (most urgent)
37+
* 2. Due today status (high urgency)
38+
* 3. Priority (importance)
39+
* 4. Due date (soonest first)
40+
* 5. Tasks without due dates (lowest priority)
41+
*
42+
* Sorting rules (in order):
43+
* 1. Overdue tasks appear first (most urgent)
44+
* 2. Tasks due today appear next
45+
* 3. Then sort by priority (high to low)
46+
* 4. For equal priority, sort by due date (earlier first)
47+
* 5. Tasks without due dates appear last
48+
*/
49+
const orderByDueDateAndPriority2 = (t1, t2) => {
50+
51+
const p1 = t1?.priority ?? 0;
52+
const p2 = t2?.priority ?? 0;
53+
54+
const now = new Date();
55+
const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
56+
57+
// Due date handling (Infinity for missing dates)
58+
const d1 = t1?.dueDate ? new Date(t1.dueDate).getTime() : Infinity;
59+
const d2 = t2?.dueDate ? new Date(t2.dueDate).getTime() : Infinity;
60+
61+
// Calculate days until due (negative = overdue)
62+
const daysUntilDue1 = Math.floor((d1 - startOfToday) / (1000 * 60 * 60 * 24));
63+
const daysUntilDue2 = Math.floor((d2 - startOfToday) / (1000 * 60 * 60 * 24));
64+
65+
// Status flags
66+
const isOverdue1 = daysUntilDue1 < 0;
67+
const isOverdue2 = daysUntilDue2 < 0;
68+
const isDueToday1 = daysUntilDue1 === 0;
69+
const isDueToday2 = daysUntilDue2 === 0;
70+
const hasNoDueDate1 = d1 === Infinity;
71+
const hasNoDueDate2 = d2 === Infinity;
72+
73+
// 1. Overdue tasks come first (most urgent)
74+
if (isOverdue1 && !isOverdue2) return -1;
75+
if (isOverdue2 && !isOverdue1) return 1;
76+
if (isOverdue1 && isOverdue2) {
77+
// If both overdue, more overdue comes first
78+
return daysUntilDue1 - daysUntilDue2;
79+
}
80+
81+
// 2. Tasks due today come next
82+
if (isDueToday1 && !isDueToday2) return -1;
83+
if (isDueToday2 && !isDueToday1) return 1;
84+
85+
// 3. Then sort by priority (higher first)
86+
if (p1 !== p2) return p2 - p1;
87+
88+
// 4. For equal priority, sort by due date (earlier first)
89+
if (d1 !== d2) return d1 - d2;
90+
91+
// 5. Tasks without due dates come last
92+
if (hasNoDueDate1 && !hasNoDueDate2) return 1;
93+
if (hasNoDueDate2 && !hasNoDueDate1) return -1;
94+
95+
// 6. All else being equal, maintain original order
96+
return 0;
97+
};
98+
99+
/**
100+
* Task prioritization algorithm that combines:
101+
* 1. Overdue status (most urgent)
102+
* 2. Due today status (high urgency)
103+
* 3. Priority (importance)
104+
* 4. Due date (soonest first)
105+
* 5. Tasks without due dates (lowest priority)
106+
*
107+
* Sorting rules (in order):
108+
* 1. Overdue tasks appear first (most urgent), sorted by priority (higher first)
109+
* 2. Tasks due today appear next, sorted by priority (higher first)
110+
* 3. Then sort other dates too by date and priority (high to low)
111+
* 4. For equal priority, sort by due date (earlier first)
112+
* 5. Tasks without due dates appear last
113+
*/
114+
115+
const orderByDueDateAndPriority = (t1, t2) => {
116+
// Normalize priority to a number
117+
const getPriority = (t) =>
118+
t?.priority === 'high' ? 10 :
119+
t?.priority === 'medium' ? 6 :
120+
typeof t?.priority === 'string' ? 0 :
121+
t?.priority ?? 0;
122+
123+
const p1 = getPriority(t1);
124+
const p2 = getPriority(t2);
125+
126+
// Normalize due dates
127+
const d1 = t1?.dueDate ? new Date(t1.dueDate).getTime() : Infinity;
128+
const d2 = t2?.dueDate ? new Date(t2.dueDate).getTime() : Infinity;
129+
130+
const now = new Date();
131+
const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
132+
133+
const daysUntilDue1 = Math.floor((d1 - startOfToday) / (1000 * 60 * 60 * 24));
134+
const daysUntilDue2 = Math.floor((d2 - startOfToday) / (1000 * 60 * 60 * 24));
135+
136+
const isOverdue1 = daysUntilDue1 < 0;
137+
const isOverdue2 = daysUntilDue2 < 0;
138+
const isDueToday1 = daysUntilDue1 === 0;
139+
const isDueToday2 = daysUntilDue2 === 0;
140+
const hasNoDueDate1 = d1 === Infinity;
141+
const hasNoDueDate2 = d2 === Infinity;
142+
143+
// 1. Overdue tasks first, sorted by priority (higher first), then by due date (earlier first)
144+
if (isOverdue1 && !isOverdue2) return -1;
145+
if (isOverdue2 && !isOverdue1) return 1;
146+
if (isOverdue1 && isOverdue2) {
147+
if (p1 !== p2) return p2 - p1;
148+
return d1 - d2;
149+
}
150+
151+
// 2. Tasks due today next, sorted by priority (higher first)
152+
if (isDueToday1 && !isDueToday2) return -1;
153+
if (isDueToday2 && !isDueToday1) return 1;
154+
if (isDueToday1 && isDueToday2) {
155+
if (p1 !== p2) return p2 - p1;
156+
return d1 - d2;
157+
}
158+
159+
// 3. Other tasks: sort by due date (earlier first), then by priority (higher first)
160+
if (!hasNoDueDate1 && !hasNoDueDate2) {
161+
if (d1 !== d2) return d1 - d2;
162+
if (p1 !== p2) return p2 - p1;
163+
}
164+
165+
// 4. Tasks without due dates come last
166+
if (hasNoDueDate1 && !hasNoDueDate2) return 1;
167+
if (hasNoDueDate2 && !hasNoDueDate1) return -1;
168+
169+
// 5. All else being equal, maintain original order
170+
return 0;
171+
};
172+
173+
174+
33175
const _tasksReducer = createReducer(
34176
initialState,
35177
on(GlobalActions.clearSelected, (state) => ({ ...state, selected: null })),
36178

37179
on(Actions.setTasksList, (state, { payload: { tasks } }) => {
38180
return {
39181
...state,
40-
tasksList: [...tasks].sort(orderByDueDate),
182+
tasksList: [...tasks].sort(orderByDueDateAndPriority),
41183
};
42184
}),
43185

0 commit comments

Comments
 (0)