-
-
Notifications
You must be signed in to change notification settings - Fork 119
/
Copy pathCreateRecurringTodo.tsx
92 lines (74 loc) · 3.64 KB
/
CreateRecurringTodo.tsx
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
import { Item } from 'jstodotxt';
import dayjs from 'dayjs';
import { writeTodoObjectToFile } from '../File/Write';
enum RecurrenceInterval {
Daily = 'd',
BusinessDays = 'b',
Weekly = 'w',
Monthly = 'm',
Annually = 'y',
}
const addBusinessDays = (date: Date, days: number): Date => {
const result = new Date(date);
let remainingDays = days;
while (remainingDays > 0) {
result.setDate(result.getDate() + 1);
if(result.getDay() !== 0 && result.getDay() !== 6) {
remainingDays--;
}
}
return result;
};
const addRecurrenceToDate = (date: Date, recurrenceInterval: string, recurrenceValue: number): Date | null => {
const validRecurrenceValue = isNaN(recurrenceValue) || recurrenceValue === undefined ? 1 : recurrenceValue;
switch (recurrenceInterval) {
case RecurrenceInterval.Daily:
return dayjs(date).add(validRecurrenceValue, 'day').toDate();
case RecurrenceInterval.BusinessDays:
return addBusinessDays(date, validRecurrenceValue);
case RecurrenceInterval.Weekly:
return dayjs(date).add(validRecurrenceValue, 'week').toDate();
case RecurrenceInterval.Monthly:
return dayjs(date).add(validRecurrenceValue, 'month').toDate();
case RecurrenceInterval.Annually:
return dayjs(date).add(validRecurrenceValue, 'year').toDate();
default:
return date;
}
};
const createRecurringTodo = async (string: string, recurrence: string): Promise<string> => {
let updatedString = (string || '').replaceAll(/[\x10\r\n]/g, ` ${String.fromCharCode(16)} `);
const JsTodoTxtObject = new Item(updatedString);
const creationDate = new Date();
JsTodoTxtObject.setCreated(creationDate);
if(recurrence) {
const strictRecurrence: boolean = recurrence.startsWith('+');
const updatedRecurrence: any = strictRecurrence ? recurrence.slice(1) : recurrence;
const recurrenceInterval = updatedRecurrence.slice(-1) as RecurrenceInterval;
const recurrenceValue = parseInt(updatedRecurrence.slice(0, -1));
const oldDueDate: any = JsTodoTxtObject?.extensions()?.find((item) => item.key === 'due')?.value;
const oldThresholdDate: any = JsTodoTxtObject?.extensions()?.find((item) => item.key === 't')?.value;
const daysBetween: number = (oldDueDate && oldThresholdDate) ? dayjs(oldDueDate, 'YYYY-MM-DD').diff(oldThresholdDate, 'day') : 0
const newDueDate =
oldDueDate === undefined && recurrenceValue === 0
? null
: strictRecurrence
? addRecurrenceToDate(dayjs(oldDueDate).toDate(), recurrenceInterval, recurrenceValue)
: addRecurrenceToDate(dayjs(creationDate).toDate(), recurrenceInterval, recurrenceValue);
const newThresholdDate = strictRecurrence
? addRecurrenceToDate(dayjs(oldThresholdDate).toDate(), recurrenceInterval, recurrenceValue)
: daysBetween > 0
? dayjs(newDueDate).subtract(daysBetween, 'day').toDate()
: addRecurrenceToDate(dayjs(creationDate).toDate(), recurrenceInterval, recurrenceValue);
// If the user only uses threshold date and no due date, the recurrence should not create a due date:
const recurrenceOnlyForThresholdDate = oldThresholdDate && !oldDueDate;
if(newDueDate && creationDate && !recurrenceOnlyForThresholdDate) JsTodoTxtObject.setExtension('due', dayjs(newDueDate).format('YYYY-MM-DD'));
if(oldThresholdDate) JsTodoTxtObject.setExtension('t', dayjs(newThresholdDate).format('YYYY-MM-DD'));
JsTodoTxtObject.setComplete(false);
JsTodoTxtObject.setCompleted(null);
await writeTodoObjectToFile(-1, JsTodoTxtObject.toString());
return 'Recurring todo created';
}
return 'No recurring todo created';
};
export { createRecurringTodo, addRecurrenceToDate };