@perdieminc/time-slots 0.0.1 → 0.0.2
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/README.md +2 -2
- package/lib/constants.d.ts +36 -0
- package/lib/constants.d.ts.map +1 -0
- package/lib/constants.js +36 -0
- package/lib/constants.js.map +1 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +41 -0
- package/lib/index.js.map +1 -0
- package/lib/schedule/available-dates.d.ts +3 -0
- package/lib/schedule/available-dates.d.ts.map +1 -0
- package/lib/schedule/available-dates.js +84 -0
- package/lib/schedule/available-dates.js.map +1 -0
- package/lib/schedule/generate.d.ts +3 -0
- package/lib/schedule/generate.d.ts.map +1 -0
- package/lib/schedule/generate.js +155 -0
- package/lib/schedule/generate.js.map +1 -0
- package/lib/schedule/get-schedules.d.ts +3 -0
- package/lib/schedule/get-schedules.d.ts.map +1 -0
- package/lib/schedule/get-schedules.js +161 -0
- package/lib/schedule/get-schedules.js.map +1 -0
- package/lib/schedule/location.d.ts +3 -0
- package/lib/schedule/location.d.ts.map +1 -0
- package/lib/schedule/location.js +38 -0
- package/lib/schedule/location.js.map +1 -0
- package/lib/types/index.d.ts +7 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +3 -0
- package/lib/types/index.js.map +1 -0
- package/lib/types.d.ts +24 -0
- package/lib/types.js +2 -0
- package/lib/utils/business-hours.d.ts +6 -0
- package/lib/utils/business-hours.d.ts.map +1 -0
- package/lib/utils/business-hours.js +82 -0
- package/lib/utils/business-hours.js.map +1 -0
- package/lib/utils/catering.d.ts +9 -0
- package/lib/utils/catering.d.ts.map +1 -0
- package/lib/utils/catering.js +56 -0
- package/lib/utils/catering.js.map +1 -0
- package/lib/utils/date.d.ts +15 -0
- package/lib/utils/date.d.ts.map +1 -0
- package/lib/utils/date.js +109 -0
- package/lib/utils/date.js.map +1 -0
- package/lib/utils/schedule-filter.d.ts +8 -0
- package/lib/utils/schedule-filter.d.ts.map +1 -0
- package/lib/utils/schedule-filter.js +95 -0
- package/lib/utils/schedule-filter.js.map +1 -0
- package/lib/utils/store-hours.d.ts +14 -0
- package/lib/utils/store-hours.d.ts.map +1 -0
- package/lib/utils/store-hours.js +120 -0
- package/lib/utils/store-hours.js.map +1 -0
- package/lib/utils/time.d.ts +12 -0
- package/lib/utils/time.d.ts.map +1 -0
- package/lib/utils/time.js +30 -0
- package/lib/utils/time.js.map +1 -0
- package/lib/utils.d.ts +8 -0
- package/lib/utils.js +18 -0
- package/package.json +8 -7
- package/src/constants.ts +0 -45
- package/src/index.ts +0 -23
- package/src/schedule/available-dates.ts +0 -129
- package/src/schedule/generate.ts +0 -276
- package/src/schedule/get-schedules.ts +0 -264
- package/src/schedule/location.ts +0 -58
- package/src/types/business-hours.d.ts +0 -32
- package/src/types/common.d.ts +0 -5
- package/src/types/get-schedules.d.ts +0 -122
- package/src/types/index.ts +0 -34
- package/src/types/location.d.ts +0 -25
- package/src/types/schedule-filter.d.ts +0 -27
- package/src/types/schedule.d.ts +0 -83
- package/src/types/timezone-support.d.ts +0 -31
- package/src/utils/business-hours.ts +0 -120
- package/src/utils/catering.ts +0 -85
- package/src/utils/date.ts +0 -163
- package/src/utils/schedule-filter.ts +0 -140
- package/src/utils/store-hours.ts +0 -223
- package/src/utils/time.ts +0 -38
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getOpeningClosingTimeOnDate = getOpeningClosingTimeOnDate;
|
|
4
|
+
exports.getOpeningClosingTime = getOpeningClosingTime;
|
|
5
|
+
const date_fns_1 = require("date-fns");
|
|
6
|
+
const timezone_support_1 = require("timezone-support");
|
|
7
|
+
const available_dates_1 = require("../schedule/available-dates");
|
|
8
|
+
const business_hours_1 = require("./business-hours");
|
|
9
|
+
const date_1 = require("./date");
|
|
10
|
+
function getAvailableBusinessHours({ businessHours = [], businessHoursOverrides = [], timeZone, nextAvailableDate, }) {
|
|
11
|
+
const zonedDate = (0, timezone_support_1.getZonedTime)(nextAvailableDate, (0, timezone_support_1.findTimeZone)(timeZone));
|
|
12
|
+
const dayBusinessHours = businessHours.filter((bh) => bh.day ===
|
|
13
|
+
(0, timezone_support_1.getZonedTime)(nextAvailableDate, (0, timezone_support_1.findTimeZone)(timeZone)).dayOfWeek);
|
|
14
|
+
const businessHoursOverride = businessHoursOverrides.find((override) => override.day === zonedDate.day && override.month === zonedDate.month);
|
|
15
|
+
const dayBusinessTimes = dayBusinessHours
|
|
16
|
+
.map((businessHour) => {
|
|
17
|
+
const effectiveHour = businessHoursOverride
|
|
18
|
+
? {
|
|
19
|
+
day: businessHour.day,
|
|
20
|
+
startTime: businessHoursOverride.startTime ?? "00:00",
|
|
21
|
+
endTime: businessHoursOverride.endTime ?? "23:59",
|
|
22
|
+
}
|
|
23
|
+
: businessHour;
|
|
24
|
+
const startDate = (0, date_1.setHmOnDate)(nextAvailableDate, effectiveHour.startTime, timeZone);
|
|
25
|
+
const endDate = (0, date_1.setHmOnDate)(nextAvailableDate, effectiveHour.endTime, timeZone);
|
|
26
|
+
if (!(0, date_fns_1.isBefore)(startDate, endDate)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
return { startDate, endDate };
|
|
30
|
+
})
|
|
31
|
+
.filter((time) => time !== null)
|
|
32
|
+
.sort((a, b) => (0, date_fns_1.compareAsc)(a.startDate, b.startDate));
|
|
33
|
+
return { dayBusinessTimes, businessHoursOverride };
|
|
34
|
+
}
|
|
35
|
+
// ── Public API ──────────────────────────────────────────────────────────────
|
|
36
|
+
function getOpeningClosingTimeOnDate({ date = new Date(), businessHours = [], businessHoursOverrides = [], timeZone, }) {
|
|
37
|
+
try {
|
|
38
|
+
const nextAvailableDates = (0, available_dates_1.getNextAvailableDates)({
|
|
39
|
+
startDate: date,
|
|
40
|
+
businessHours,
|
|
41
|
+
businessHoursOverrides,
|
|
42
|
+
timeZone,
|
|
43
|
+
datesCount: 7,
|
|
44
|
+
});
|
|
45
|
+
if (!Array.isArray(nextAvailableDates) || !nextAvailableDates.length) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
for (let nextDateIndex = 0; nextDateIndex < nextAvailableDates.length; ++nextDateIndex) {
|
|
49
|
+
const nextAvailableDate = nextAvailableDates[nextDateIndex];
|
|
50
|
+
const { dayBusinessTimes, businessHoursOverride } = getAvailableBusinessHours({
|
|
51
|
+
businessHours,
|
|
52
|
+
businessHoursOverrides,
|
|
53
|
+
timeZone,
|
|
54
|
+
nextAvailableDate,
|
|
55
|
+
});
|
|
56
|
+
if (!Array.isArray(dayBusinessTimes) || dayBusinessTimes.length === 0) {
|
|
57
|
+
if (businessHoursOverride?.startTime &&
|
|
58
|
+
businessHoursOverride?.endTime) {
|
|
59
|
+
const openingTime = (0, date_1.setHmOnDate)(nextAvailableDate, businessHoursOverride.startTime, timeZone);
|
|
60
|
+
const closingTime = (0, date_1.setHmOnDate)(nextAvailableDate, businessHoursOverride.endTime, timeZone);
|
|
61
|
+
if ((0, date_fns_1.isBefore)(closingTime, date)) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
return { openingTime, closingTime };
|
|
65
|
+
}
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const currentTime = date;
|
|
69
|
+
let currentSlot = null;
|
|
70
|
+
for (const slot of dayBusinessTimes) {
|
|
71
|
+
if ((0, date_fns_1.isBefore)(currentTime, slot.endDate)) {
|
|
72
|
+
currentSlot = slot;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (!currentSlot) {
|
|
77
|
+
currentSlot = dayBusinessTimes[0];
|
|
78
|
+
}
|
|
79
|
+
if ((0, date_fns_1.isBefore)(currentSlot.endDate, date)) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if ((0, date_1.isTodayInTimeZone)(nextAvailableDate, timeZone) &&
|
|
83
|
+
nextDateIndex + 1 < nextAvailableDates.length) {
|
|
84
|
+
const { dayBusinessTimes: nextDayTimes } = getAvailableBusinessHours({
|
|
85
|
+
businessHours,
|
|
86
|
+
businessHoursOverrides,
|
|
87
|
+
timeZone,
|
|
88
|
+
nextAvailableDate: nextAvailableDates[nextDateIndex + 1],
|
|
89
|
+
});
|
|
90
|
+
if (nextDayTimes.length) {
|
|
91
|
+
const firstNextDaySlot = nextDayTimes?.[0];
|
|
92
|
+
if (firstNextDaySlot &&
|
|
93
|
+
(0, date_1.isMidnightTransition)(currentSlot.endDate, firstNextDaySlot.startDate, timeZone)) {
|
|
94
|
+
currentSlot = {
|
|
95
|
+
...currentSlot,
|
|
96
|
+
endDate: firstNextDaySlot.endDate,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
openingTime: currentSlot.startDate,
|
|
103
|
+
closingTime: currentSlot.endDate,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function getOpeningClosingTime({ location, fulfillmentPreference, businessHoursOverrides, }) {
|
|
113
|
+
const businessHours = (0, business_hours_1.getLocationBusinessHoursForFulfillment)(location, fulfillmentPreference);
|
|
114
|
+
return getOpeningClosingTimeOnDate({
|
|
115
|
+
businessHours,
|
|
116
|
+
businessHoursOverrides: businessHoursOverrides?.[location.location_id] ?? [],
|
|
117
|
+
timeZone: location.timezone,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=store-hours.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-hours.js","sourceRoot":"","sources":["../../src/utils/store-hours.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare function parseTimeString(timeString: string | null | undefined): {
|
|
2
|
+
hours: number;
|
|
3
|
+
minutes: number;
|
|
4
|
+
};
|
|
5
|
+
export declare function isTimeInRange(schedule: {
|
|
6
|
+
start_time?: string;
|
|
7
|
+
end_time?: string;
|
|
8
|
+
}, time: {
|
|
9
|
+
hours: number;
|
|
10
|
+
minutes: number;
|
|
11
|
+
}): boolean;
|
|
12
|
+
//# sourceMappingURL=time.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/utils/time.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CAChB,CAQA;AAED,wBAAgB,aAAa,CAC5B,QAAQ,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EACpD,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtC,OAAO,CAqBT"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseTimeString = parseTimeString;
|
|
4
|
+
exports.isTimeInRange = isTimeInRange;
|
|
5
|
+
function parseTimeString(timeString) {
|
|
6
|
+
if (!timeString) {
|
|
7
|
+
return { hours: 0, minutes: 0 };
|
|
8
|
+
}
|
|
9
|
+
const [hours = 0, minutes = 0] = String(timeString).split(":");
|
|
10
|
+
return { hours: Number(hours), minutes: Number(minutes) };
|
|
11
|
+
}
|
|
12
|
+
function isTimeInRange(schedule, time) {
|
|
13
|
+
const startTime = parseTimeString(schedule?.start_time);
|
|
14
|
+
const endTime = parseTimeString(schedule?.end_time);
|
|
15
|
+
if (time.hours < startTime.hours || time.hours > endTime.hours) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
if (time.hours === startTime.hours) {
|
|
19
|
+
if (time.minutes < startTime.minutes) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (time.hours === endTime.hours) {
|
|
24
|
+
if (time.minutes > endTime.minutes) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=time.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time.js","sourceRoot":"","sources":["../../src/utils/time.ts"],"names":[],"mappings":";;AAAA,0CAWC;AAED,sCAwBC;AArCD,SAAgB,eAAe,CAAC,UAAqC;IAIpE,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACjC,CAAC;IAED,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAE/D,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;AAC3D,CAAC;AAED,SAAgB,aAAa,CAC5B,QAAoD,EACpD,IAAwC;IAExC,MAAM,SAAS,GAAG,eAAe,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEpD,IAAI,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;QAChE,OAAO,KAAK,CAAC;IACd,CAAC;IAED,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,KAAK,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;YACtC,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IAED,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;YACpC,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC"}
|
package/lib/utils.d.ts
ADDED
package/lib/utils.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addMinutes = addMinutes;
|
|
4
|
+
exports.isBefore = isBefore;
|
|
5
|
+
/**
|
|
6
|
+
* Add minutes to a date and return a new Date.
|
|
7
|
+
*/
|
|
8
|
+
function addMinutes(date, minutes) {
|
|
9
|
+
const result = new Date(date);
|
|
10
|
+
result.setMinutes(result.getMinutes() + minutes);
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Check if a date is before another (by time value).
|
|
15
|
+
*/
|
|
16
|
+
function isBefore(a, b) {
|
|
17
|
+
return a.getTime() < b.getTime();
|
|
18
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@perdieminc/time-slots",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Generate time slots for scheduling",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"time-slots",
|
|
@@ -9,18 +9,18 @@
|
|
|
9
9
|
],
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"author": "Per Diem Subscriptions Inc.",
|
|
12
|
-
"homepage": "https://github.com/PerDiemInc/
|
|
12
|
+
"homepage": "https://github.com/PerDiemInc/time-slots#readme",
|
|
13
13
|
"bugs": {
|
|
14
|
-
"url": "https://github.com/PerDiemInc/
|
|
14
|
+
"url": "https://github.com/PerDiemInc/time-slots/issues"
|
|
15
15
|
},
|
|
16
|
-
"main": "
|
|
17
|
-
"types": "
|
|
16
|
+
"main": "lib/index.js",
|
|
17
|
+
"types": "lib/index.d.ts",
|
|
18
18
|
"engines": {
|
|
19
19
|
"node": ">=20"
|
|
20
20
|
},
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|
|
23
|
-
"url": "git+https://github.com/PerDiemInc/
|
|
23
|
+
"url": "git+https://github.com/PerDiemInc/time-slots.git"
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
26
|
"lint": "biome lint .",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"format": "biome check --write .",
|
|
29
29
|
"clean": "rm -rf lib types coverage",
|
|
30
30
|
"build": "tsc -b .",
|
|
31
|
+
"prepublishOnly": "npm run build",
|
|
31
32
|
"build:watch": "tsc --watch",
|
|
32
33
|
"test": "vitest run",
|
|
33
34
|
"test:coverage": "vitest run --coverage",
|
|
@@ -51,7 +52,7 @@
|
|
|
51
52
|
"vitest": "^3.2.4"
|
|
52
53
|
},
|
|
53
54
|
"files": [
|
|
54
|
-
"
|
|
55
|
+
"lib"
|
|
55
56
|
],
|
|
56
57
|
"directories": {
|
|
57
58
|
"lib": "lib",
|
package/src/constants.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fulfillment types for pickup, delivery, curbside.
|
|
3
|
-
*/
|
|
4
|
-
export const FULFILLMENT_TYPES = {
|
|
5
|
-
PICKUP: "PICKUP",
|
|
6
|
-
DELIVERY: "DELIVERY",
|
|
7
|
-
CURBSIDE: "CURBSIDE",
|
|
8
|
-
} as const;
|
|
9
|
-
|
|
10
|
-
export const DEFAULT_TIMEZONE = "America/New_York";
|
|
11
|
-
export type FulfillmentType =
|
|
12
|
-
(typeof FULFILLMENT_TYPES)[keyof typeof FULFILLMENT_TYPES];
|
|
13
|
-
|
|
14
|
-
export const DEFAULT_GAP_IN_MINUTES = 15;
|
|
15
|
-
export const DEFAULT_PREP_TIME_IN_MINUTES = 5;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Prep time behaviour when computing first available slot.
|
|
19
|
-
*/
|
|
20
|
-
export const PrepTimeBehaviour = Object.freeze({
|
|
21
|
-
FIRST_SHIFT: 0,
|
|
22
|
-
EVERY_SHIFT: 1,
|
|
23
|
-
ROLL_FROM_FIRST_SHIFT: 2,
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
export type PrepTimeBehaviourType =
|
|
27
|
-
(typeof PrepTimeBehaviour)[keyof typeof PrepTimeBehaviour];
|
|
28
|
-
|
|
29
|
-
export const PREP_TIME_CADENCE = {
|
|
30
|
-
MINUTE: "minute",
|
|
31
|
-
DAY: "day",
|
|
32
|
-
HOUR: "hour",
|
|
33
|
-
} as const;
|
|
34
|
-
|
|
35
|
-
export type PrepTimeCadence =
|
|
36
|
-
(typeof PREP_TIME_CADENCE)[keyof typeof PREP_TIME_CADENCE];
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Platform for timezone handling (web uses @date-fns/tz; ios/android use timezone-support).
|
|
40
|
-
*/
|
|
41
|
-
export const PLATFORM = {
|
|
42
|
-
WEB: "web",
|
|
43
|
-
IOS: "ios",
|
|
44
|
-
ANDROID: "android",
|
|
45
|
-
} as const;
|
package/src/index.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export type { FulfillmentType, PrepTimeBehaviourType } from "./constants";
|
|
2
|
-
export {
|
|
3
|
-
DEFAULT_GAP_IN_MINUTES,
|
|
4
|
-
DEFAULT_PREP_TIME_IN_MINUTES,
|
|
5
|
-
FULFILLMENT_TYPES,
|
|
6
|
-
PLATFORM,
|
|
7
|
-
PrepTimeBehaviour,
|
|
8
|
-
} from "./constants";
|
|
9
|
-
export { getSchedules } from "./schedule/get-schedules";
|
|
10
|
-
export * from "./types";
|
|
11
|
-
export { getLocationsBusinessHoursOverrides } from "./utils/business-hours";
|
|
12
|
-
export { getCateringPrepTimeConfig } from "./utils/catering";
|
|
13
|
-
export {
|
|
14
|
-
getPreSalePickupDates,
|
|
15
|
-
isTodayInTimeZone,
|
|
16
|
-
isTomorrowInTimeZone,
|
|
17
|
-
overrideTimeZoneOnUTC,
|
|
18
|
-
} from "./utils/date";
|
|
19
|
-
export {
|
|
20
|
-
filterBusyTimesFromSchedule,
|
|
21
|
-
filterMenusFromSchedule,
|
|
22
|
-
} from "./utils/schedule-filter";
|
|
23
|
-
export { getOpeningClosingTime } from "./utils/store-hours";
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { tz } from "@date-fns/tz";
|
|
2
|
-
import { isAfter, isSameDay, startOfDay } from "date-fns";
|
|
3
|
-
import { findTimeZone, getUnixTime, getZonedTime } from "timezone-support";
|
|
4
|
-
|
|
5
|
-
import { PLATFORM } from "../constants";
|
|
6
|
-
import type { GetNextAvailableDatesParams, Platform } from "../types";
|
|
7
|
-
import { addDaysInTimeZone, setHmOnDate } from "../utils/date";
|
|
8
|
-
|
|
9
|
-
function getStartOfDayInZone(
|
|
10
|
-
startDate: Date,
|
|
11
|
-
timeZone: string,
|
|
12
|
-
platform: Platform,
|
|
13
|
-
): Date {
|
|
14
|
-
if (platform !== PLATFORM.ANDROID) {
|
|
15
|
-
return startOfDay(startDate, { in: tz(timeZone) });
|
|
16
|
-
}
|
|
17
|
-
const zoned = getZonedTime(startDate, findTimeZone(timeZone));
|
|
18
|
-
return new Date(
|
|
19
|
-
getUnixTime({
|
|
20
|
-
...zoned,
|
|
21
|
-
hours: 0,
|
|
22
|
-
minutes: 0,
|
|
23
|
-
seconds: 0,
|
|
24
|
-
milliseconds: 0,
|
|
25
|
-
}),
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function getNextAvailableDates({
|
|
30
|
-
startDate,
|
|
31
|
-
timeZone,
|
|
32
|
-
businessHours,
|
|
33
|
-
businessHoursOverrides = [],
|
|
34
|
-
datesCount = 1,
|
|
35
|
-
preSaleDates = [],
|
|
36
|
-
presalePickupWeekDays = [],
|
|
37
|
-
endDate = null,
|
|
38
|
-
isDaysCadence = false,
|
|
39
|
-
platform = PLATFORM.WEB,
|
|
40
|
-
}: GetNextAvailableDatesParams): Date[] {
|
|
41
|
-
const startOfDayInZone = getStartOfDayInZone(startDate, timeZone, platform);
|
|
42
|
-
const zonedStartTime = getZonedTime(startOfDayInZone, findTimeZone(timeZone));
|
|
43
|
-
|
|
44
|
-
const dates: Date[] = [];
|
|
45
|
-
|
|
46
|
-
for (
|
|
47
|
-
let date = new Date(
|
|
48
|
-
getUnixTime({
|
|
49
|
-
...zonedStartTime,
|
|
50
|
-
hours: 0,
|
|
51
|
-
minutes: 0,
|
|
52
|
-
seconds: 0,
|
|
53
|
-
milliseconds: 0,
|
|
54
|
-
}),
|
|
55
|
-
),
|
|
56
|
-
maxRuns = 0;
|
|
57
|
-
dates.length < datesCount && maxRuns <= 30;
|
|
58
|
-
date = addDaysInTimeZone(date, 1, timeZone), maxRuns += 1
|
|
59
|
-
) {
|
|
60
|
-
const lastDate = dates?.at(-1);
|
|
61
|
-
if (lastDate && isSameDay(lastDate, date)) {
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (endDate && isAfter(date, endDate)) {
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (date.getTime() < getUnixTime(zonedStartTime)) {
|
|
70
|
-
continue;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const zonedDate = getZonedTime(date, findTimeZone(timeZone));
|
|
74
|
-
const dayOfWeek = zonedDate.dayOfWeek ?? 0;
|
|
75
|
-
|
|
76
|
-
const todayBusinessHoursOverride = businessHoursOverrides.filter(
|
|
77
|
-
(override) =>
|
|
78
|
-
zonedDate.month === override.month && zonedDate.day === override.day,
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
const closedBusinessHoursOverride = todayBusinessHoursOverride.filter(
|
|
82
|
-
(override) => !override.startTime && !override.endTime,
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
if (closedBusinessHoursOverride.length) {
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const todayBusinessHours = businessHours.filter(
|
|
90
|
-
(bh) => bh.day === dayOfWeek,
|
|
91
|
-
);
|
|
92
|
-
// If days cadence, we dont need to skip date even if it is after the last shift end time
|
|
93
|
-
if (isDaysCadence) {
|
|
94
|
-
const lastShiftEndTime = todayBusinessHours.at(-1)?.endTime;
|
|
95
|
-
const shiftEndDate = lastShiftEndTime
|
|
96
|
-
? setHmOnDate(date, lastShiftEndTime, timeZone)
|
|
97
|
-
: null;
|
|
98
|
-
/**
|
|
99
|
-
* Skip current date if current time is after the last shift end time
|
|
100
|
-
*/
|
|
101
|
-
if (shiftEndDate && isAfter(startDate, shiftEndDate)) {
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Skip if today is closed by location hours or by override hours
|
|
107
|
-
*/
|
|
108
|
-
if (
|
|
109
|
-
!todayBusinessHours?.length &&
|
|
110
|
-
!todayBusinessHoursOverride.length &&
|
|
111
|
-
!endDate
|
|
112
|
-
) {
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (preSaleDates.length && presalePickupWeekDays.length) {
|
|
117
|
-
if (
|
|
118
|
-
preSaleDates.includes(zonedDate.day) &&
|
|
119
|
-
presalePickupWeekDays.includes(dayOfWeek)
|
|
120
|
-
) {
|
|
121
|
-
dates.push(date);
|
|
122
|
-
}
|
|
123
|
-
} else {
|
|
124
|
-
dates.push(date);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return dates;
|
|
129
|
-
}
|