@bash-app/bash-common 30.57.0 → 30.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/extendedSchemas.d.ts +44 -0
- package/dist/extendedSchemas.d.ts.map +1 -1
- package/dist/extendedSchemas.js +6 -0
- package/dist/extendedSchemas.js.map +1 -1
- package/dist/utils/dateTimeUtils.d.ts +1 -17
- package/dist/utils/dateTimeUtils.d.ts.map +1 -1
- package/dist/utils/dateTimeUtils.js +1 -114
- package/dist/utils/dateTimeUtils.js.map +1 -1
- package/dist/utils/luxonUtils.d.ts +17 -6
- package/dist/utils/luxonUtils.d.ts.map +1 -1
- package/dist/utils/luxonUtils.js +31 -3
- package/dist/utils/luxonUtils.js.map +1 -1
- package/dist/utils/recurrenceUtils.d.ts +1 -1
- package/dist/utils/recurrenceUtils.d.ts.map +1 -1
- package/dist/utils/recurrenceUtils.js +24 -49
- package/dist/utils/recurrenceUtils.js.map +1 -1
- package/dist/utils/service/apiServiceBookingApiUtils.d.ts +14 -2
- package/dist/utils/service/apiServiceBookingApiUtils.d.ts.map +1 -1
- package/dist/utils/service/apiServiceBookingApiUtils.js +36 -2
- package/dist/utils/service/apiServiceBookingApiUtils.js.map +1 -1
- package/dist/utils/service/frontendServiceBookingUtils.d.ts +10 -3
- package/dist/utils/service/frontendServiceBookingUtils.d.ts.map +1 -1
- package/dist/utils/service/frontendServiceBookingUtils.js +86 -40
- package/dist/utils/service/frontendServiceBookingUtils.js.map +1 -1
- package/dist/utils/service/serviceBookingTypes.d.ts +4 -2
- package/dist/utils/service/serviceBookingTypes.d.ts.map +1 -1
- package/dist/utils/ticketListUtils.d.ts.map +1 -1
- package/dist/utils/ticketListUtils.js +10 -13
- package/dist/utils/ticketListUtils.js.map +1 -1
- package/dist/utils/typeUtils.d.ts +5 -0
- package/dist/utils/typeUtils.d.ts.map +1 -1
- package/dist/utils/typeUtils.js.map +1 -1
- package/package.json +1 -1
- package/prisma/schema.prisma +31 -41
- package/src/extendedSchemas.ts +9 -0
- package/src/utils/dateTimeUtils.ts +7 -190
- package/src/utils/luxonUtils.ts +56 -10
- package/src/utils/recurrenceUtils.ts +97 -77
- package/src/utils/service/apiServiceBookingApiUtils.ts +64 -7
- package/src/utils/service/frontendServiceBookingUtils.ts +120 -49
- package/src/utils/service/serviceBookingTypes.ts +30 -2
- package/src/utils/ticketListUtils.ts +40 -27
- package/src/utils/typeUtils.ts +15 -8
|
@@ -4,12 +4,6 @@ import { DateTimeArgType } from "../definitions";
|
|
|
4
4
|
|
|
5
5
|
const PARSE_TIME_REG = /^(\d{1,2}):(\d{2}) ?([APM]{0,2})$/i;
|
|
6
6
|
|
|
7
|
-
export const DATETIME_FORMAT_STANDARD = "MMM d, yyyy - h:mm a";
|
|
8
|
-
export const DATETIME_FORMAT_ISO_LIKE = "yyyy-MM-dd HH:mm";
|
|
9
|
-
export const DATE_FORMAT_STANDARD = "MM/dd/yyyy";
|
|
10
|
-
export const DATE_FORMAT_ISO = "yyyy-MM-dd";
|
|
11
|
-
export const TIME_FORMAT_AM_PM = "h:mm a";
|
|
12
|
-
|
|
13
7
|
export interface ITime {
|
|
14
8
|
hours: number;
|
|
15
9
|
minutes: number;
|
|
@@ -20,84 +14,6 @@ export function getLocalTimezoneName(): string {
|
|
|
20
14
|
return DateTime.local().zoneName;
|
|
21
15
|
}
|
|
22
16
|
|
|
23
|
-
export function formatDateRangeBasic(
|
|
24
|
-
startDateTimeArg: Date | null,
|
|
25
|
-
endDateTimeArg: Date | null
|
|
26
|
-
): string {
|
|
27
|
-
const userTimezone = getLocalTimezoneName();
|
|
28
|
-
const startDateTime = DateTime.fromJSDate(startDateTimeArg || new Date()).setZone(userTimezone);
|
|
29
|
-
const endDateTime = DateTime.fromJSDate(endDateTimeArg || new Date()).setZone(userTimezone);
|
|
30
|
-
|
|
31
|
-
if (startDateTime.hasSame(endDateTime, "day")) {
|
|
32
|
-
return `${startDateTime.toFormat(
|
|
33
|
-
DATETIME_FORMAT_STANDARD
|
|
34
|
-
)} to ${endDateTime.toFormat(TIME_FORMAT_AM_PM)}`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return `${startDateTime.toFormat(
|
|
38
|
-
DATETIME_FORMAT_STANDARD
|
|
39
|
-
)} to ${endDateTime.toFormat(DATETIME_FORMAT_STANDARD)}`;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function formatDateRangeBasicWithTimezone(
|
|
43
|
-
startDateTimeArg: Date | null,
|
|
44
|
-
endDateTimeArg: Date | null,
|
|
45
|
-
timezone?: string
|
|
46
|
-
): string {
|
|
47
|
-
const targetTimezone = timezone || getLocalTimezoneName();
|
|
48
|
-
const startDateTime = DateTime.fromJSDate(startDateTimeArg || new Date()).setZone(targetTimezone);
|
|
49
|
-
const endDateTime = DateTime.fromJSDate(endDateTimeArg || new Date()).setZone(targetTimezone);
|
|
50
|
-
|
|
51
|
-
if (startDateTime.hasSame(endDateTime, "day")) {
|
|
52
|
-
return `${startDateTime.toFormat(
|
|
53
|
-
DATETIME_FORMAT_STANDARD
|
|
54
|
-
)} to ${endDateTime.toFormat(TIME_FORMAT_AM_PM)}`;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return `${startDateTime.toFormat(
|
|
58
|
-
DATETIME_FORMAT_STANDARD
|
|
59
|
-
)} to ${endDateTime.toFormat(DATETIME_FORMAT_STANDARD)}`;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function formatDateRange(
|
|
63
|
-
startDateTimeArg: Date | null,
|
|
64
|
-
endDateTimeArg: Date | null
|
|
65
|
-
): string {
|
|
66
|
-
const userTimezone = getLocalTimezoneName();
|
|
67
|
-
const startDateTime = ensureDateTimeIsLocalDateTime(startDateTimeArg).setZone(userTimezone);
|
|
68
|
-
const endDateTime = ensureDateTimeIsLocalDateTime(endDateTimeArg).setZone(userTimezone);
|
|
69
|
-
|
|
70
|
-
if (startDateTime.hasSame(endDateTime, "day")) {
|
|
71
|
-
return `${startDateTime.toFormat(
|
|
72
|
-
DATETIME_FORMAT_STANDARD
|
|
73
|
-
)} to ${endDateTime.toFormat(TIME_FORMAT_AM_PM)}`;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return `${startDateTime.toFormat(
|
|
77
|
-
DATETIME_FORMAT_STANDARD
|
|
78
|
-
)} to ${endDateTime.toFormat(DATETIME_FORMAT_STANDARD)}`;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function formatDateRangeWithTimezone(
|
|
82
|
-
startDateTimeArg: Date | null,
|
|
83
|
-
endDateTimeArg: Date | null,
|
|
84
|
-
timezone?: string
|
|
85
|
-
): string {
|
|
86
|
-
const targetTimezone = timezone || getLocalTimezoneName();
|
|
87
|
-
const startDateTime = ensureDateTimeIsLocalDateTime(startDateTimeArg).setZone(targetTimezone);
|
|
88
|
-
const endDateTime = ensureDateTimeIsLocalDateTime(endDateTimeArg).setZone(targetTimezone);
|
|
89
|
-
|
|
90
|
-
if (startDateTime.hasSame(endDateTime, "day")) {
|
|
91
|
-
return `${startDateTime.toFormat(
|
|
92
|
-
DATETIME_FORMAT_STANDARD
|
|
93
|
-
)} to ${endDateTime.toFormat(TIME_FORMAT_AM_PM)}`;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return `${startDateTime.toFormat(
|
|
97
|
-
DATETIME_FORMAT_STANDARD
|
|
98
|
-
)} to ${endDateTime.toFormat(DATETIME_FORMAT_STANDARD)}`;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
17
|
export function ensureIsDateTime(
|
|
102
18
|
possiblyADate: DateTimeArgType
|
|
103
19
|
): Date | undefined {
|
|
@@ -134,23 +50,17 @@ export function normalizeDates(
|
|
|
134
50
|
.filter((date): date is Date => !!date); // Filter out invalid dates
|
|
135
51
|
}
|
|
136
52
|
|
|
137
|
-
export function formatDateTimeToISODateTimeString(
|
|
138
|
-
date: DateTimeArgType
|
|
139
|
-
): string | undefined {
|
|
140
|
-
if (!date) {
|
|
141
|
-
return undefined;
|
|
142
|
-
}
|
|
143
|
-
date = new Date(date);
|
|
144
|
-
return date.toISOString();
|
|
145
|
-
}
|
|
146
|
-
|
|
147
53
|
export function dateWithinDateRange(
|
|
148
54
|
date: DateTimeArgType,
|
|
149
55
|
dateRange: DateValueType | undefined
|
|
150
56
|
): boolean {
|
|
151
|
-
const startDate = DateTime.fromJSDate(
|
|
152
|
-
|
|
153
|
-
|
|
57
|
+
const startDate = DateTime.fromJSDate(
|
|
58
|
+
dateRange?.startDate || new Date()
|
|
59
|
+
).startOf("day");
|
|
60
|
+
const endDate = DateTime.fromJSDate(dateRange?.endDate || new Date()).endOf(
|
|
61
|
+
"day"
|
|
62
|
+
);
|
|
63
|
+
const checkDate = DateTime.fromJSDate(new Date(date || ""));
|
|
154
64
|
|
|
155
65
|
return checkDate >= startDate && checkDate < endDate;
|
|
156
66
|
}
|
|
@@ -221,99 +131,6 @@ export function compareDateTime(
|
|
|
221
131
|
}
|
|
222
132
|
}
|
|
223
133
|
|
|
224
|
-
export function setDateButPreserveTime(
|
|
225
|
-
dateArg: DateType,
|
|
226
|
-
dateWithTheTimeYouWantToKeep: DateType | undefined
|
|
227
|
-
): Date {
|
|
228
|
-
if (!dateArg || !dateWithTheTimeYouWantToKeep) {
|
|
229
|
-
console.error("Invalid arguments:", {
|
|
230
|
-
dateArg,
|
|
231
|
-
dateWithTheTimeYouWantToKeep,
|
|
232
|
-
});
|
|
233
|
-
throw new Error(
|
|
234
|
-
"Both dateArg and dateWithTheTimeYouWantToKeep are required."
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Get local timezone
|
|
239
|
-
const localTimeZone = getLocalTimezoneName();
|
|
240
|
-
|
|
241
|
-
// Extract date and time components using Luxon
|
|
242
|
-
const dateOnly = DateTime.fromJSDate(new Date(dateArg)).setZone(localTimeZone);
|
|
243
|
-
const timeOnly = DateTime.fromJSDate(new Date(dateWithTheTimeYouWantToKeep)).setZone(localTimeZone);
|
|
244
|
-
|
|
245
|
-
// Combine date from first argument with time from second argument
|
|
246
|
-
const combinedDateTime = dateOnly.set({
|
|
247
|
-
hour: timeOnly.hour,
|
|
248
|
-
minute: timeOnly.minute,
|
|
249
|
-
second: 0,
|
|
250
|
-
millisecond: 0
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
console.log("Combining date and time:", {
|
|
254
|
-
dateOnly: dateOnly.toISO(),
|
|
255
|
-
timeOnly: timeOnly.toFormat("HH:mm"),
|
|
256
|
-
combinedDateTime: combinedDateTime.toISO(),
|
|
257
|
-
localTimeZone,
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
const result = combinedDateTime.toJSDate();
|
|
261
|
-
if (isNaN(result.getTime())) {
|
|
262
|
-
console.error("Invalid combined datetime:", combinedDateTime.toISO());
|
|
263
|
-
throw new Error("Invalid date or time format.");
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
console.log("Final combined DateTime (UTC):", result);
|
|
267
|
-
return result;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
export function setTimeOnDate(
|
|
271
|
-
date: DateType | Date | undefined,
|
|
272
|
-
parsedTime: ITime | null
|
|
273
|
-
): Date {
|
|
274
|
-
const dateTime = DateTime.fromJSDate(date ? new Date(date) : new Date());
|
|
275
|
-
|
|
276
|
-
if (parsedTime) {
|
|
277
|
-
const updatedDateTime = dateTime.set({
|
|
278
|
-
hour: parsedTime.hours,
|
|
279
|
-
minute: parsedTime.minutes,
|
|
280
|
-
second: 0,
|
|
281
|
-
millisecond: 0
|
|
282
|
-
});
|
|
283
|
-
return setDateButPreserveTime(dateTime.toJSDate(), updatedDateTime.toJSDate());
|
|
284
|
-
}
|
|
285
|
-
return dateTime.toJSDate();
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
export function ensureDateTimeIsLocalDateTime(
|
|
289
|
-
dateArg: DateType | DateTime | undefined
|
|
290
|
-
): DateTime {
|
|
291
|
-
if (!dateArg) {
|
|
292
|
-
return DateTime.local();
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (dateArg instanceof DateTime) {
|
|
296
|
-
return dateArg.setZone(getLocalTimezoneName());
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const dt = DateTime.fromJSDate(new Date(dateArg));
|
|
300
|
-
return dt.setZone(getLocalTimezoneName());
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
export function formatDateTimeToTimeString(
|
|
304
|
-
date: Date | string | undefined | null
|
|
305
|
-
): string {
|
|
306
|
-
const dt = DateTime.fromJSDate(new Date(date ?? Date.now()));
|
|
307
|
-
return dt.toFormat("h:mm a");
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
export function formatDateTimeToTimeString24hr(
|
|
311
|
-
date: Date | string | undefined | null
|
|
312
|
-
): string {
|
|
313
|
-
const dt = DateTime.fromJSDate(new Date(date ?? Date.now()));
|
|
314
|
-
return dt.toFormat("H:mm");
|
|
315
|
-
}
|
|
316
|
-
|
|
317
134
|
export function parseTimeString(timeStr: string): ITime | null {
|
|
318
135
|
const match = timeStr.match(PARSE_TIME_REG);
|
|
319
136
|
|
package/src/utils/luxonUtils.ts
CHANGED
|
@@ -8,11 +8,11 @@ import {
|
|
|
8
8
|
} from "./generalDateTimeUtils";
|
|
9
9
|
import { roundToNearestDivisor } from "./mathUtils";
|
|
10
10
|
|
|
11
|
-
const PARSE_TIME_REG = /^(\d{1,2}):(\d{2}) ?([APM]{0,2})$/i;
|
|
12
|
-
|
|
13
11
|
// export const LUXON_DATETIME_FORMAT_STANDARD = "MM/dd/yyyy - hh:mm a";
|
|
14
12
|
export const LUXON_DATETIME_FORMAT_STANDARD = "D t";
|
|
13
|
+
export const LUXON_DATETIME_FORMAT_ISO = "D t"; //"D t";
|
|
15
14
|
export const LUXON_DATETIME_FORMAT_ISO_LIKE = "D t"; //"D t";
|
|
15
|
+
export const LUXON_DATETIME_FORMAT_STANDARD_EXTENDED = "cccc D T";
|
|
16
16
|
// export const LUXON_DATE_FORMAT_STANDARD = "yyyy/MM/dd";
|
|
17
17
|
// export const LUXON_DATE_FORMAT_ISO = "yyyy/MM/dd";
|
|
18
18
|
export const LUXON_DATETIME_FORMAT_DATE = "D"; //"D t";
|
|
@@ -20,6 +20,19 @@ export const LUXON_TIME_FORMAT_AM_PM = "h:mm a";
|
|
|
20
20
|
|
|
21
21
|
export const MINUTES_PER_DAY = 1440;
|
|
22
22
|
|
|
23
|
+
export const INVALID_DATETIME_STR = "Invalid date";
|
|
24
|
+
export const INVALID_DATETIME_RANGE_STR = "Invalid date range";
|
|
25
|
+
|
|
26
|
+
export interface LuxonDateRange {
|
|
27
|
+
start: DateTime;
|
|
28
|
+
end: DateTime;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface LuxonDateRangeN {
|
|
32
|
+
start?: DateTime | undefined | null;
|
|
33
|
+
end?: DateTime | undefined | null;
|
|
34
|
+
}
|
|
35
|
+
|
|
23
36
|
export function dayOfWeekGetIdx(dayOfWeek: DayOfWeek | DayOfWeekIdx) {
|
|
24
37
|
if (typeof dayOfWeek === "number") {
|
|
25
38
|
return dayOfWeek as DayOfWeekIdx;
|
|
@@ -30,6 +43,16 @@ export function dayOfWeekGetIdx(dayOfWeek: DayOfWeek | DayOfWeekIdx) {
|
|
|
30
43
|
}
|
|
31
44
|
}
|
|
32
45
|
|
|
46
|
+
export function dayOfWeekFromIdx(dayOfWeek: DayOfWeek | DayOfWeekIdx) {
|
|
47
|
+
if (typeof dayOfWeek === "number") {
|
|
48
|
+
return dayOfWeekIdxToDayOfWeek[dayOfWeek as DayOfWeekIdx];
|
|
49
|
+
} else if (typeof dayOfWeek === "string") {
|
|
50
|
+
return dayOfWeek as DayOfWeek;
|
|
51
|
+
} else {
|
|
52
|
+
throw new Error(`dayOfWeekToIdx: unhandled case`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
33
56
|
export function dateTimeFromDayTime(
|
|
34
57
|
dayOfWeek: DayOfWeek | DayOfWeekIdx,
|
|
35
58
|
hour: number = 0,
|
|
@@ -192,12 +215,25 @@ export function dateRangeGetDateTimeTIme(dateRange: LuxonDateRange) {
|
|
|
192
215
|
};
|
|
193
216
|
}
|
|
194
217
|
|
|
195
|
-
export function dateTimeFormat(dateTime?: DateTime | null) {
|
|
218
|
+
export function dateTimeFormat(dateTime?: DateTime | undefined | null) {
|
|
196
219
|
return dateTime?.toFormat(LUXON_DATETIME_FORMAT_STANDARD) ?? "";
|
|
197
220
|
}
|
|
198
221
|
|
|
199
|
-
export function
|
|
200
|
-
|
|
222
|
+
export function dateTimeFormatExt(
|
|
223
|
+
dateTime?: DateTime | undefined | null
|
|
224
|
+
): string {
|
|
225
|
+
return dateTime
|
|
226
|
+
? `${dateTime.toFormat(LUXON_DATETIME_FORMAT_STANDARD_EXTENDED)}`
|
|
227
|
+
: "";
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function dateTimeFormatISO(
|
|
231
|
+
dateTime?: DateTime | undefined | null
|
|
232
|
+
): string | null {
|
|
233
|
+
if (!dateTime) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
return dateTime.toISO();
|
|
201
237
|
}
|
|
202
238
|
|
|
203
239
|
export function dateTimeFormatWeek(dateTime?: DateTime | null) {
|
|
@@ -296,6 +332,21 @@ export function dateTimeFormatDateRange(
|
|
|
296
332
|
)}`;
|
|
297
333
|
}
|
|
298
334
|
|
|
335
|
+
export function dateTimeFormatDateRangeExt(
|
|
336
|
+
startDateTimeArg: DateTime | null,
|
|
337
|
+
endDateTimeArg: DateTime | null
|
|
338
|
+
): string {
|
|
339
|
+
if (startDateTimeArg?.day === endDateTimeArg?.day) {
|
|
340
|
+
return `${dateTimeFormatExt(startDateTimeArg)} to ${dateTimeFormatTime(
|
|
341
|
+
endDateTimeArg
|
|
342
|
+
)}`;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return `${dateTimeFormatExt(startDateTimeArg)} to ${dateTimeFormat(
|
|
346
|
+
endDateTimeArg
|
|
347
|
+
)}`;
|
|
348
|
+
}
|
|
349
|
+
|
|
299
350
|
export function dateTimeFormatDateRangeDate(
|
|
300
351
|
startDateTimeArg: DateTime | null,
|
|
301
352
|
endDateTimeArg: DateTime | null
|
|
@@ -333,11 +384,6 @@ export function dateTimeFormatDateRangeList(
|
|
|
333
384
|
};
|
|
334
385
|
}
|
|
335
386
|
|
|
336
|
-
export interface LuxonDateRange {
|
|
337
|
-
start: DateTime;
|
|
338
|
-
end: DateTime;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
387
|
export type LuxonDayOfWeekHours = {
|
|
342
388
|
[key in DayOfWeekIdx]: LuxonDateRange[];
|
|
343
389
|
};
|
|
@@ -1,27 +1,54 @@
|
|
|
1
1
|
import { DayOfWeek, Recurrence, RecurringFrequency } from "@prisma/client";
|
|
2
2
|
import { DateTime, WeekdayNumbers } from "luxon";
|
|
3
3
|
import { DateTimeArgType } from "../definitions";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
dateTimeFromDate,
|
|
6
|
+
dateTimeSetTime,
|
|
7
|
+
dayOfWeekGetIdx,
|
|
8
|
+
LUXON_DATETIME_FORMAT_ISO_LIKE,
|
|
9
|
+
} from "./luxonUtils";
|
|
10
|
+
import { compareDateTime } from "./dateTimeUtils";
|
|
11
|
+
import { dayOfWeekToIdx } from "./generalDateTimeUtils";
|
|
5
12
|
|
|
6
|
-
export function getRecurringBashEventPossibleDateTimes(
|
|
7
|
-
|
|
8
|
-
|
|
13
|
+
export function getRecurringBashEventPossibleDateTimes(
|
|
14
|
+
startDateTime: DateTimeArgType,
|
|
15
|
+
recurrence: Recurrence | undefined | null
|
|
16
|
+
): Date[] {
|
|
17
|
+
return getRecurringBashEventPossibleDatesTimesInternal(
|
|
18
|
+
startDateTime,
|
|
19
|
+
recurrence,
|
|
20
|
+
true
|
|
21
|
+
) as Date[];
|
|
9
22
|
}
|
|
10
23
|
|
|
11
|
-
export function
|
|
12
|
-
|
|
13
|
-
|
|
24
|
+
export function getRecurringBashEventPossibleLuxonTimes(
|
|
25
|
+
startDateTime: DateTimeArgType,
|
|
26
|
+
recurrence: Recurrence | undefined | null
|
|
27
|
+
): DateTime[] {
|
|
28
|
+
return getRecurringBashEventPossibleDatesTimesInternal(
|
|
29
|
+
startDateTime,
|
|
30
|
+
recurrence,
|
|
31
|
+
false
|
|
32
|
+
) as DateTime[];
|
|
14
33
|
}
|
|
15
34
|
|
|
16
|
-
function getRecurringBashEventPossibleDatesTimesInternal(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
35
|
+
function getRecurringBashEventPossibleDatesTimesInternal(
|
|
36
|
+
startDateTime: DateTimeArgType,
|
|
37
|
+
recurrence: Recurrence | undefined | null,
|
|
38
|
+
toDate: boolean
|
|
39
|
+
): (DateTime | Date)[] {
|
|
40
|
+
if (
|
|
41
|
+
!recurrence ||
|
|
42
|
+
!recurrence.frequency ||
|
|
43
|
+
recurrence.frequency === RecurringFrequency.Never
|
|
44
|
+
) {
|
|
20
45
|
return [];
|
|
21
46
|
}
|
|
22
47
|
|
|
23
48
|
let recurrenceDates: DateTime[] = [];
|
|
24
|
-
const beginningDate = findEarliestPossibleBashEventDate(
|
|
49
|
+
const beginningDate = findEarliestPossibleBashEventDate(
|
|
50
|
+
startDateTime
|
|
51
|
+
) as DateTime; // Don't allow dates before the current date
|
|
25
52
|
|
|
26
53
|
switch (recurrence.frequency) {
|
|
27
54
|
case RecurringFrequency.Weekly:
|
|
@@ -30,17 +57,22 @@ function getRecurringBashEventPossibleDatesTimesInternal(startDateTime: DateTime
|
|
|
30
57
|
default:
|
|
31
58
|
console.error(`Only weekly frequency is currently supported`);
|
|
32
59
|
}
|
|
33
|
-
return recurrenceDates
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
60
|
+
return recurrenceDates
|
|
61
|
+
.map((date: DateTime): string =>
|
|
62
|
+
date.toFormat(LUXON_DATETIME_FORMAT_ISO_LIKE)
|
|
63
|
+
)
|
|
64
|
+
.sort()
|
|
65
|
+
.map((dateStr: string): DateTime | Date => {
|
|
66
|
+
const luxonDate = DateTime.fromFormat(
|
|
67
|
+
dateStr,
|
|
68
|
+
LUXON_DATETIME_FORMAT_ISO_LIKE
|
|
69
|
+
);
|
|
70
|
+
if (toDate) {
|
|
71
|
+
return luxonDate.toJSDate();
|
|
72
|
+
} else {
|
|
73
|
+
return luxonDate;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
44
76
|
}
|
|
45
77
|
|
|
46
78
|
/**
|
|
@@ -48,15 +80,20 @@ function getRecurringBashEventPossibleDatesTimesInternal(startDateTime: DateTime
|
|
|
48
80
|
* @param beginningDateTime The beginning DateTime of the event, adjusted to be no earlier than now.
|
|
49
81
|
* @param recurrence
|
|
50
82
|
*/
|
|
51
|
-
function getWeeklyRecurringDates(
|
|
83
|
+
function getWeeklyRecurringDates(
|
|
84
|
+
beginningDateTime: DateTime,
|
|
85
|
+
recurrence: Recurrence
|
|
86
|
+
): DateTime[] {
|
|
52
87
|
if (recurrence.frequency !== RecurringFrequency.Weekly) {
|
|
53
|
-
throw new Error(
|
|
88
|
+
throw new Error(
|
|
89
|
+
`Cannot do a weekly recurrence if the frequency isn't weekly.`
|
|
90
|
+
);
|
|
54
91
|
}
|
|
55
92
|
|
|
56
93
|
const interval = recurrence.interval ?? 1;
|
|
57
|
-
const recurrenceEnds =
|
|
58
|
-
const numberOfDays = recurrenceEnds.diff(beginningDateTime,
|
|
59
|
-
const numberOfWeeks = Math.ceil(
|
|
94
|
+
const recurrenceEnds = dateTimeFromDate(recurrence.ends).endOf("day"); // Get the end of the day to not miss the last day
|
|
95
|
+
const numberOfDays = recurrenceEnds.diff(beginningDateTime, "days").days;
|
|
96
|
+
const numberOfWeeks = Math.ceil(numberOfDays / 7 / interval); // Get the number of days and then round up so that we include the ending date
|
|
60
97
|
|
|
61
98
|
const recurrenceDates: DateTime[] = [];
|
|
62
99
|
let theNextWeekOfRecurrences = beginningDateTime;
|
|
@@ -65,13 +102,15 @@ function getWeeklyRecurringDates(beginningDateTime: DateTime, recurrence: Recurr
|
|
|
65
102
|
for (let i = 0; i < numberOfWeeks; i++) {
|
|
66
103
|
let weekday: DateTime | null = null;
|
|
67
104
|
for (const dayOfWeekEnum of recurrence.repeatOnDays) {
|
|
68
|
-
const dayOfWeekNum =
|
|
69
|
-
|
|
105
|
+
const dayOfWeekNum = dayOfWeekGetIdx(dayOfWeekEnum);
|
|
106
|
+
weekday = theNextWeekOfRecurrences.set({
|
|
107
|
+
weekday: dayOfWeekNum as WeekdayNumbers,
|
|
108
|
+
});
|
|
70
109
|
if (weekday > recurrenceEnds || weekday < beginningDateTime) {
|
|
71
110
|
continue; // Continue because repeatOnDays isn't sorted by the day of the week
|
|
72
111
|
}
|
|
73
112
|
// Set the time on the date so that it matches the time when the event starts
|
|
74
|
-
weekday =
|
|
113
|
+
weekday = dateTimeSetTime(weekday, beginningDateTime);
|
|
75
114
|
recurrenceDates.push(weekday);
|
|
76
115
|
}
|
|
77
116
|
if (weekday) {
|
|
@@ -81,54 +120,28 @@ function getWeeklyRecurringDates(beginningDateTime: DateTime, recurrence: Recurr
|
|
|
81
120
|
return recurrenceDates;
|
|
82
121
|
}
|
|
83
122
|
|
|
84
|
-
function copyTimeToDate(dateWithTimeToCopy: DateTime, dateWhoseTimeToChange: DateTime): DateTime {
|
|
85
|
-
if (dateWithTimeToCopy.second !== 0) {
|
|
86
|
-
console.warn(`dateWithTimeToCopy has non-zero seconds: ${dateWithTimeToCopy.toString()} \nFixing...`);
|
|
87
|
-
dateWithTimeToCopy = dateWithTimeToCopy.set({second: 0});
|
|
88
|
-
}
|
|
89
|
-
return dateWhoseTimeToChange.set({
|
|
90
|
-
hour: dateWithTimeToCopy.hour,
|
|
91
|
-
minute: dateWithTimeToCopy.minute,
|
|
92
|
-
second: 0
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function dayOfWeekEnumToDayNumber(dayEnum: DayOfWeek): number {
|
|
97
|
-
switch (dayEnum) {
|
|
98
|
-
case DayOfWeek.Sunday:
|
|
99
|
-
return 7; // Luxon uses 1-7 where 7 is Sunday
|
|
100
|
-
case DayOfWeek.Monday:
|
|
101
|
-
return 1;
|
|
102
|
-
case DayOfWeek.Tuesday:
|
|
103
|
-
return 2;
|
|
104
|
-
case DayOfWeek.Wednesday:
|
|
105
|
-
return 3;
|
|
106
|
-
case DayOfWeek.Thursday:
|
|
107
|
-
return 4;
|
|
108
|
-
case DayOfWeek.Friday:
|
|
109
|
-
return 5;
|
|
110
|
-
case DayOfWeek.Saturday:
|
|
111
|
-
return 6;
|
|
112
|
-
default:
|
|
113
|
-
throw new Error(`How did this happen? Invalid DayOfWeek: ${dayEnum}`); // Shouldn't happen
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
123
|
/**
|
|
118
124
|
* Get the next week determined by the interval by going to the end of the week interval and adding one day
|
|
119
125
|
* @param date
|
|
120
126
|
* @param interval
|
|
121
127
|
*/
|
|
122
|
-
function getBeginningOfWeekInterval(
|
|
128
|
+
function getBeginningOfWeekInterval(
|
|
129
|
+
date: DateTime,
|
|
130
|
+
interval: number
|
|
131
|
+
): DateTime {
|
|
123
132
|
if (!interval) {
|
|
124
133
|
interval = 1; // Avoid 0
|
|
125
134
|
}
|
|
126
135
|
// An interval of 2 would be (2 - 1) * 7 + 1 = 8 days to add to skip a week and go into the next week
|
|
127
136
|
const numberOfDaysToAdd = interval > 1 ? (interval - 1) * 7 + 1 : 1;
|
|
128
|
-
return date.endOf(
|
|
137
|
+
return date.endOf("week").plus({ days: numberOfDaysToAdd });
|
|
129
138
|
}
|
|
130
139
|
|
|
131
|
-
export function freqToGrammarString(
|
|
140
|
+
export function freqToGrammarString(
|
|
141
|
+
freq: RecurringFrequency,
|
|
142
|
+
interval: number | undefined,
|
|
143
|
+
toLowerCase: boolean = false
|
|
144
|
+
): string {
|
|
132
145
|
if (!interval) {
|
|
133
146
|
return freq;
|
|
134
147
|
}
|
|
@@ -136,37 +149,44 @@ export function freqToGrammarString(freq: RecurringFrequency, interval: number |
|
|
|
136
149
|
let result: string = freq;
|
|
137
150
|
switch (freq) {
|
|
138
151
|
case RecurringFrequency.Daily:
|
|
139
|
-
result = isPlural ?
|
|
152
|
+
result = isPlural ? "Days" : "Day";
|
|
140
153
|
break;
|
|
141
154
|
case RecurringFrequency.Weekly:
|
|
142
|
-
result = isPlural ?
|
|
155
|
+
result = isPlural ? "Weeks" : "Week";
|
|
143
156
|
break;
|
|
144
157
|
case RecurringFrequency.Monthly:
|
|
145
|
-
result = isPlural ?
|
|
158
|
+
result = isPlural ? "Months" : "Month";
|
|
146
159
|
break;
|
|
147
160
|
case RecurringFrequency.Yearly:
|
|
148
|
-
result = isPlural ?
|
|
161
|
+
result = isPlural ? "Years" : "Year";
|
|
149
162
|
break;
|
|
150
163
|
}
|
|
151
164
|
return toLowerCase ? result.toLowerCase() : result;
|
|
152
165
|
}
|
|
153
166
|
|
|
154
|
-
export function findEarliestPossibleBashEventDate(
|
|
167
|
+
export function findEarliestPossibleBashEventDate(
|
|
168
|
+
startDateTimeArg: DateTimeArgType
|
|
169
|
+
): DateTime | undefined {
|
|
155
170
|
return findEarliestOrLatestPossibleBashEventDate(startDateTimeArg, true);
|
|
156
171
|
}
|
|
157
172
|
|
|
158
|
-
function findEarliestOrLatestPossibleBashEventDate(
|
|
173
|
+
function findEarliestOrLatestPossibleBashEventDate(
|
|
174
|
+
startDateTimeArg: DateTimeArgType,
|
|
175
|
+
findEarly: boolean
|
|
176
|
+
): DateTime | undefined {
|
|
159
177
|
if (!startDateTimeArg) {
|
|
160
178
|
return;
|
|
161
179
|
}
|
|
162
180
|
// Don't allow dates before the current date
|
|
163
|
-
const startDateTime =
|
|
181
|
+
const startDateTime = dateTimeFromDate(startDateTimeArg);
|
|
164
182
|
const currentDateTime = DateTime.local();
|
|
165
|
-
const comparedDateTime = compareDateTime(
|
|
183
|
+
const comparedDateTime = compareDateTime(
|
|
184
|
+
currentDateTime.toJSDate(),
|
|
185
|
+
startDateTimeArg
|
|
186
|
+
);
|
|
166
187
|
if (findEarly) {
|
|
167
188
|
return comparedDateTime > 0 ? currentDateTime : startDateTime;
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
189
|
+
} else {
|
|
170
190
|
return comparedDateTime < 0 ? currentDateTime : startDateTime;
|
|
171
191
|
}
|
|
172
192
|
}
|