@perdieminc/time-slots 0.0.1 → 0.0.3

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.
Files changed (78) hide show
  1. package/README.md +9 -8
  2. package/lib/constants.d.ts +37 -0
  3. package/lib/constants.d.ts.map +1 -0
  4. package/lib/constants.js +37 -0
  5. package/lib/constants.js.map +1 -0
  6. package/lib/index.d.ts +11 -0
  7. package/lib/index.d.ts.map +1 -0
  8. package/lib/index.js +41 -0
  9. package/lib/index.js.map +1 -0
  10. package/lib/schedule/available-dates.d.ts +3 -0
  11. package/lib/schedule/available-dates.d.ts.map +1 -0
  12. package/lib/schedule/available-dates.js +84 -0
  13. package/lib/schedule/available-dates.js.map +1 -0
  14. package/lib/schedule/generate.d.ts +3 -0
  15. package/lib/schedule/generate.d.ts.map +1 -0
  16. package/lib/schedule/generate.js +155 -0
  17. package/lib/schedule/generate.js.map +1 -0
  18. package/lib/schedule/get-schedules.d.ts +3 -0
  19. package/lib/schedule/get-schedules.d.ts.map +1 -0
  20. package/lib/schedule/get-schedules.js +182 -0
  21. package/lib/schedule/get-schedules.js.map +1 -0
  22. package/lib/schedule/location.d.ts +3 -0
  23. package/lib/schedule/location.d.ts.map +1 -0
  24. package/lib/schedule/location.js +38 -0
  25. package/lib/schedule/location.js.map +1 -0
  26. package/lib/types/index.d.ts +7 -0
  27. package/lib/types/index.d.ts.map +1 -0
  28. package/lib/types/index.js +3 -0
  29. package/lib/types/index.js.map +1 -0
  30. package/lib/types.d.ts +24 -0
  31. package/lib/types.js +2 -0
  32. package/lib/utils/business-hours.d.ts +6 -0
  33. package/lib/utils/business-hours.d.ts.map +1 -0
  34. package/lib/utils/business-hours.js +82 -0
  35. package/lib/utils/business-hours.js.map +1 -0
  36. package/lib/utils/catering.d.ts +9 -0
  37. package/lib/utils/catering.d.ts.map +1 -0
  38. package/lib/utils/catering.js +56 -0
  39. package/lib/utils/catering.js.map +1 -0
  40. package/lib/utils/date.d.ts +15 -0
  41. package/lib/utils/date.d.ts.map +1 -0
  42. package/lib/utils/date.js +109 -0
  43. package/lib/utils/date.js.map +1 -0
  44. package/lib/utils/schedule-filter.d.ts +8 -0
  45. package/lib/utils/schedule-filter.d.ts.map +1 -0
  46. package/lib/utils/schedule-filter.js +95 -0
  47. package/lib/utils/schedule-filter.js.map +1 -0
  48. package/lib/utils/store-hours.d.ts +14 -0
  49. package/lib/utils/store-hours.d.ts.map +1 -0
  50. package/lib/utils/store-hours.js +120 -0
  51. package/lib/utils/store-hours.js.map +1 -0
  52. package/lib/utils/time.d.ts +12 -0
  53. package/lib/utils/time.d.ts.map +1 -0
  54. package/lib/utils/time.js +30 -0
  55. package/lib/utils/time.js.map +1 -0
  56. package/lib/utils.d.ts +8 -0
  57. package/lib/utils.js +18 -0
  58. package/package.json +8 -7
  59. package/src/constants.ts +0 -45
  60. package/src/index.ts +0 -23
  61. package/src/schedule/available-dates.ts +0 -129
  62. package/src/schedule/generate.ts +0 -276
  63. package/src/schedule/get-schedules.ts +0 -264
  64. package/src/schedule/location.ts +0 -58
  65. package/src/types/business-hours.d.ts +0 -32
  66. package/src/types/common.d.ts +0 -5
  67. package/src/types/get-schedules.d.ts +0 -122
  68. package/src/types/index.ts +0 -34
  69. package/src/types/location.d.ts +0 -25
  70. package/src/types/schedule-filter.d.ts +0 -27
  71. package/src/types/schedule.d.ts +0 -83
  72. package/src/types/timezone-support.d.ts +0 -31
  73. package/src/utils/business-hours.ts +0 -120
  74. package/src/utils/catering.ts +0 -85
  75. package/src/utils/date.ts +0 -163
  76. package/src/utils/schedule-filter.ts +0 -140
  77. package/src/utils/store-hours.ts +0 -223
  78. package/src/utils/time.ts +0 -38
@@ -1,276 +0,0 @@
1
- import {
2
- addMinutes,
3
- compareAsc,
4
- eachMinuteOfInterval,
5
- isAfter,
6
- isBefore,
7
- max,
8
- } from "date-fns";
9
- import { findTimeZone, getZonedTime } from "timezone-support";
10
- import type { PrepTimeBehaviourType } from "../constants";
11
- import {
12
- DEFAULT_PREP_TIME_IN_MINUTES,
13
- PREP_TIME_CADENCE,
14
- PrepTimeBehaviour,
15
- } from "../constants";
16
- import type {
17
- BusinessHour,
18
- BusinessHoursOverrideOutput,
19
- DaySchedule,
20
- GenerateScheduleParams,
21
- } from "../types";
22
- import {
23
- isTodayInTimeZone,
24
- isZeroPrepTimeForMidnightShift,
25
- setHmOnDate,
26
- } from "../utils/date";
27
-
28
- // ── Private helpers ─────────────────────────────────────────────────────────
29
-
30
- interface GetSelectedBusinessHoursParams {
31
- businessHours?: BusinessHour[];
32
- businessHoursOverrides?: BusinessHoursOverrideOutput[];
33
- date?: Date;
34
- timeZone?: string;
35
- preSaleHoursOverride?: Array<{
36
- startTime: string;
37
- endTime: string;
38
- month?: number;
39
- day?: number;
40
- }> | null;
41
- }
42
-
43
- function getSelectedBusinessHours({
44
- businessHours = [],
45
- businessHoursOverrides = [],
46
- date,
47
- timeZone,
48
- preSaleHoursOverride,
49
- }: GetSelectedBusinessHoursParams): [
50
- BusinessHour[],
51
- ReturnType<typeof getZonedTime>,
52
- ] {
53
- if (!date || !timeZone) {
54
- return [[], getZonedTime(new Date(), findTimeZone(timeZone ?? "UTC"))];
55
- }
56
-
57
- const zonedDate = getZonedTime(date, findTimeZone(timeZone));
58
- const dayOfWeek = zonedDate.dayOfWeek ?? 0;
59
-
60
- const dayBusinessHours = businessHours?.filter((bh) => bh.day === dayOfWeek);
61
-
62
- const businessHoursOverride = businessHoursOverrides?.filter(
63
- (override) =>
64
- zonedDate.month === override.month && zonedDate.day === override.day,
65
- );
66
-
67
- const selectedBusinessHours: BusinessHour[] = preSaleHoursOverride
68
- ? preSaleHoursOverride.map((o) => ({
69
- day: dayOfWeek,
70
- startTime: o.startTime,
71
- endTime: o.endTime,
72
- }))
73
- : businessHoursOverride.length
74
- ? businessHoursOverride.map((o) => ({
75
- day: dayOfWeek,
76
- startTime: o.startTime ?? "00:00",
77
- endTime: o.endTime ?? "23:59",
78
- }))
79
- : (dayBusinessHours ?? []);
80
-
81
- return [selectedBusinessHours, zonedDate];
82
- }
83
-
84
- // ── Public API ──────────────────────────────────────────────────────────────
85
-
86
- export function generateSchedule({
87
- currentDate = new Date(),
88
- prepTimeBehaviour = PrepTimeBehaviour.ROLL_FROM_FIRST_SHIFT,
89
- weekDayPrepTimes = {},
90
- timeZone,
91
- dates = [],
92
- businessHours = [],
93
- businessHoursOverrides = [],
94
- preSaleHoursOverride,
95
- gapInMinutes = 15,
96
- prepTimeCadence = null,
97
- }: GenerateScheduleParams): DaySchedule[] {
98
- const isMinutesCadence = prepTimeCadence === PREP_TIME_CADENCE.MINUTE;
99
- let shiftStartDateWithPrepTime: Date | null = null;
100
- return dates
101
- .map((date, index) => {
102
- const lastDate = dates?.[index - 1];
103
-
104
- const [selectedBusinessHours, zonedDate] = getSelectedBusinessHours({
105
- businessHours,
106
- businessHoursOverrides,
107
- date,
108
- timeZone,
109
- preSaleHoursOverride,
110
- });
111
-
112
- const [prevSelectedBusinessHours] = getSelectedBusinessHours({
113
- businessHours,
114
- businessHoursOverrides,
115
- date: lastDate,
116
- timeZone,
117
- preSaleHoursOverride,
118
- });
119
-
120
- const weekDayPrepTime =
121
- weekDayPrepTimes[zonedDate.dayOfWeek] ?? DEFAULT_PREP_TIME_IN_MINUTES;
122
-
123
- const storeTimes = {
124
- openingTime: null as Date | null,
125
- closingTime: null as Date | null,
126
- remainingShifts: 0,
127
- totalShifts: 0,
128
- };
129
-
130
- let isPrevDayMidnightTransition = false;
131
-
132
- const slots = selectedBusinessHours
133
- .flatMap((businessHour, i) => {
134
- const startDate = setHmOnDate(date, businessHour.startTime, timeZone);
135
- const shiftStartDate =
136
- isMinutesCadence && shiftStartDateWithPrepTime
137
- ? max([shiftStartDateWithPrepTime, startDate])
138
- : startDate;
139
- const shiftEndDate = setHmOnDate(
140
- date,
141
- businessHour.endTime,
142
- timeZone,
143
- );
144
-
145
- if (i === 0) {
146
- storeTimes.openingTime = shiftStartDate;
147
- }
148
-
149
- if (i === selectedBusinessHours.length - 1) {
150
- storeTimes.closingTime = shiftEndDate;
151
- }
152
-
153
- if (!isBefore(shiftStartDate, shiftEndDate)) {
154
- if (isMinutesCadence) {
155
- shiftStartDateWithPrepTime = null;
156
- }
157
- return [];
158
- }
159
-
160
- storeTimes.totalShifts += 1;
161
-
162
- const fixedSlots = eachMinuteOfInterval(
163
- { start: shiftStartDate, end: shiftEndDate },
164
- { step: gapInMinutes },
165
- );
166
-
167
- if (isTodayInTimeZone(date, timeZone)) {
168
- const openingTime = storeTimes.openingTime ?? new Date(0);
169
- const baseDate =
170
- currentDate instanceof Date ? currentDate : new Date(currentDate);
171
- const currentDateWithPrepTime = addMinutes(
172
- new Date(Math.max(baseDate.getTime(), openingTime.getTime())),
173
- Math.max(DEFAULT_PREP_TIME_IN_MINUTES, weekDayPrepTime),
174
- );
175
-
176
- if (isAfter(currentDateWithPrepTime, shiftEndDate)) {
177
- // If the prep time cadence is minutes, we need to set the shift start date with the prep time
178
- if (isMinutesCadence) {
179
- shiftStartDateWithPrepTime = currentDateWithPrepTime;
180
- }
181
- return [];
182
- }
183
-
184
- if (isBefore(currentDateWithPrepTime, shiftStartDate)) {
185
- storeTimes.remainingShifts += 1;
186
-
187
- if (
188
- (prepTimeBehaviour as PrepTimeBehaviourType) ===
189
- PrepTimeBehaviour.EVERY_SHIFT
190
- ) {
191
- const shiftStartDateWithPrepTime = addMinutes(
192
- shiftStartDate,
193
- weekDayPrepTime,
194
- );
195
-
196
- const slotDates = fixedSlots.filter((d) =>
197
- isAfter(d, shiftStartDateWithPrepTime),
198
- );
199
-
200
- slotDates.unshift(shiftStartDateWithPrepTime);
201
- return slotDates;
202
- }
203
-
204
- return fixedSlots;
205
- }
206
-
207
- const slotDates = fixedSlots.filter((d) =>
208
- isAfter(d, currentDateWithPrepTime),
209
- );
210
-
211
- slotDates.unshift(currentDateWithPrepTime);
212
- storeTimes.remainingShifts += 1;
213
- return slotDates;
214
- }
215
-
216
- if (prepTimeBehaviour === PrepTimeBehaviour.FIRST_SHIFT && i !== 0) {
217
- storeTimes.remainingShifts += 1;
218
- return fixedSlots;
219
- }
220
-
221
- const allowZeroPrepTimeForMidnightShift =
222
- isZeroPrepTimeForMidnightShift({
223
- prevDayBusinessHours: prevSelectedBusinessHours,
224
- businessHour,
225
- });
226
-
227
- const prepTimeSlot = addMinutes(
228
- prepTimeBehaviour === PrepTimeBehaviour.ROLL_FROM_FIRST_SHIFT &&
229
- !isPrevDayMidnightTransition &&
230
- storeTimes.openingTime
231
- ? storeTimes.openingTime
232
- : shiftStartDate,
233
- allowZeroPrepTimeForMidnightShift ? 0 : weekDayPrepTime,
234
- );
235
-
236
- isPrevDayMidnightTransition = allowZeroPrepTimeForMidnightShift;
237
-
238
- if (prepTimeSlot > shiftEndDate) {
239
- if (isMinutesCadence) {
240
- shiftStartDateWithPrepTime = prepTimeSlot;
241
- }
242
- shiftStartDateWithPrepTime = prepTimeSlot;
243
- return [];
244
- }
245
-
246
- if (prepTimeSlot < shiftStartDate) {
247
- storeTimes.remainingShifts += 1;
248
- return fixedSlots;
249
- }
250
-
251
- const slotDates = fixedSlots.filter((d) => isAfter(d, prepTimeSlot));
252
-
253
- slotDates.unshift(prepTimeSlot);
254
- storeTimes.remainingShifts += 1;
255
- shiftStartDateWithPrepTime = null; //reset the shift start date with prep time
256
- return slotDates;
257
- })
258
- .sort(compareAsc);
259
-
260
- const currentDateMs =
261
- currentDate instanceof Date ? currentDate.getTime() : currentDate;
262
- const availableSlots = slots.filter((d) => d.getTime() >= currentDateMs);
263
-
264
- return {
265
- date,
266
- originalStoreOpeningTime: storeTimes.openingTime,
267
- originalStoreClosingTime: storeTimes.closingTime,
268
- remainingShifts: storeTimes.remainingShifts,
269
- openingTime: slots[0],
270
- closingTime: slots[slots.length - 1],
271
- firstAvailableSlot: availableSlots[0],
272
- slots: availableSlots,
273
- };
274
- })
275
- .filter((a) => a.slots.length);
276
- }
@@ -1,264 +0,0 @@
1
- import { differenceInDays } from "date-fns";
2
- import {
3
- DEFAULT_TIMEZONE,
4
- FULFILLMENT_TYPES,
5
- PLATFORM,
6
- PREP_TIME_CADENCE,
7
- } from "../constants";
8
- import type {
9
- CartItem,
10
- FulfillmentSchedule,
11
- GetSchedulesParams,
12
- GetSchedulesResult,
13
- PrepTimeSettings,
14
- PreSaleConfig,
15
- } from "../types";
16
- import { getLocationsBusinessHoursOverrides } from "../utils/business-hours";
17
- import { getCateringPrepTimeConfig } from "../utils/catering";
18
- import { getPreSalePickupDates, overrideTimeZoneOnUTC } from "../utils/date";
19
- import { filterBusyTimesFromSchedule } from "../utils/schedule-filter";
20
- import { generateLocationFulfillmentSchedule } from "./location";
21
-
22
- // ── Helpers ─────────────────────────────────────────────────────────────────
23
-
24
- function deriveCartInfo(cartItems: CartItem[]) {
25
- return {
26
- hasPreSaleItem: cartItems.some((item) => item.preSale),
27
- hasWeeklyPreSaleItem: cartItems.some((item) => item.weeklyPreSale),
28
- categoryIds: Array.from(
29
- new Set(
30
- cartItems
31
- .map((item) => item.internalCategoryId)
32
- .filter((id): id is string => Boolean(id)),
33
- ),
34
- ),
35
- };
36
- }
37
-
38
- function resolvePreSaleDates(
39
- preSaleConfig: PreSaleConfig | undefined,
40
- timezone: string,
41
- ) {
42
- return {
43
- startDate: preSaleConfig?.due_start_date
44
- ? overrideTimeZoneOnUTC(preSaleConfig.due_start_date, timezone)
45
- : new Date(),
46
- endDate: preSaleConfig?.due_end_date
47
- ? overrideTimeZoneOnUTC(preSaleConfig.due_end_date, timezone)
48
- : new Date(),
49
- };
50
- }
51
-
52
- function getPreSaleHoursOverride(
53
- preSaleConfig: PreSaleConfig | undefined,
54
- hasPreSaleItem: boolean,
55
- ) {
56
- if (
57
- preSaleConfig &&
58
- !preSaleConfig.use_store_hours_due &&
59
- hasPreSaleItem &&
60
- preSaleConfig.due_start_time &&
61
- preSaleConfig.due_end_time
62
- ) {
63
- return [
64
- {
65
- startTime: preSaleConfig.due_start_time,
66
- endTime: preSaleConfig.due_end_time,
67
- },
68
- ];
69
- }
70
- return null;
71
- }
72
-
73
- function resolveStartDate(
74
- zonedDueStartDate: Date,
75
- hasPreSaleItem: boolean,
76
- ): Date {
77
- if (hasPreSaleItem) {
78
- return new Date(Math.max(zonedDueStartDate.getTime(), Date.now()));
79
- }
80
- return new Date();
81
- }
82
- const WEEKDAY_KEYS = [0, 1, 2, 3, 4, 5, 6] as const;
83
-
84
- function addEstimatedDeliveryToWeekDays(
85
- weekDayPrepTimes: Record<number, number>,
86
- estimatedDeliveryMinutes: number,
87
- ): Record<number, number> {
88
- const result: Record<number, number> = {};
89
- for (const day of WEEKDAY_KEYS) {
90
- result[day] = (weekDayPrepTimes[day] ?? 0) + estimatedDeliveryMinutes;
91
- }
92
- return result;
93
- }
94
-
95
- /**
96
- * Resolves prep time config: for catering flow uses cart-derived cadence/frequency;
97
- * when fulfillment is DELIVERY, adds estimatedDeliveryMinutes to all weekday prep times.
98
- */
99
- function resolvePrepTimeConfig(
100
- prepTimeSettings: PrepTimeSettings,
101
- cartItems: CartItem[],
102
- isCateringFlow: boolean,
103
- fulfillmentPreference: "PICKUP" | "DELIVERY" | "CURBSIDE",
104
- timezone: string = DEFAULT_TIMEZONE,
105
- ): PrepTimeSettings {
106
- let resolved: PrepTimeSettings;
107
-
108
- if (!isCateringFlow) {
109
- const isDayCadence =
110
- prepTimeSettings.prepTimeCadence === PREP_TIME_CADENCE.DAY;
111
- resolved = {
112
- ...prepTimeSettings,
113
- ...(isDayCadence && { weekDayPrepTimes: {} }),
114
- };
115
- } else {
116
- const cateringPrepTimeConfig = getCateringPrepTimeConfig({
117
- items: cartItems,
118
- prepTimeCadence: prepTimeSettings.prepTimeCadence,
119
- prepTimeFrequency: prepTimeSettings.prepTimeFrequency,
120
- timezone,
121
- });
122
- resolved = {
123
- ...prepTimeSettings,
124
- ...cateringPrepTimeConfig,
125
- };
126
- }
127
- const { estimatedDeliveryMinutes = 0 } = prepTimeSettings;
128
- if (
129
- fulfillmentPreference === FULFILLMENT_TYPES.DELIVERY &&
130
- estimatedDeliveryMinutes > 0
131
- ) {
132
- const baseWeekDays = resolved.weekDayPrepTimes ?? {};
133
- resolved = {
134
- ...resolved,
135
- weekDayPrepTimes: addEstimatedDeliveryToWeekDays(
136
- baseWeekDays,
137
- prepTimeSettings.estimatedDeliveryMinutes ?? 0,
138
- ),
139
- };
140
- }
141
-
142
- return resolved;
143
- }
144
-
145
- // ── Main ────────────────────────────────────────────────────────────────────
146
-
147
- export function getSchedules({
148
- store,
149
- locations,
150
- cartItems,
151
- fulfillmentPreference,
152
- prepTimeSettings,
153
- currentLocation,
154
- isCateringFlow = false,
155
- platform = PLATFORM.WEB,
156
- }: GetSchedulesParams): GetSchedulesResult {
157
- const {
158
- isAsapOrders,
159
- isSameDayOrders,
160
- max_future_order_days: daysCount = 7,
161
- weeklyPreSaleConfig,
162
- preSaleConfig,
163
- } = store;
164
-
165
- const cart = deriveCartInfo(cartItems);
166
- const resolvedPrepTime = resolvePrepTimeConfig(
167
- prepTimeSettings,
168
- cartItems,
169
- isCateringFlow,
170
- fulfillmentPreference,
171
- currentLocation?.timezone,
172
- );
173
- const {
174
- gapInMinutes,
175
- busyTimes: busyTimesByLocationId,
176
- prepTimeFrequency,
177
- prepTimeCadence,
178
- weekDayPrepTimes,
179
- } = resolvedPrepTime;
180
-
181
- const busyTimes = busyTimesByLocationId?.[currentLocation.location_id] ?? [];
182
-
183
- const businessHoursOverrides =
184
- getLocationsBusinessHoursOverrides(store.businessHoursOverrides, locations)[
185
- currentLocation.location_id
186
- ] ?? [];
187
-
188
- const filterSchedule = (schedule: FulfillmentSchedule) =>
189
- filterBusyTimesFromSchedule({
190
- schedule,
191
- busyTimes,
192
- cartCategoryIds: cart.categoryIds,
193
- });
194
-
195
- // ── Weekly pre-sale path (early return) ─────────────────────────────────
196
- if (
197
- cart.hasWeeklyPreSaleItem &&
198
- weeklyPreSaleConfig?.active &&
199
- !isCateringFlow
200
- ) {
201
- const weeklyPickupDates = getPreSalePickupDates(
202
- weeklyPreSaleConfig?.pickup_days,
203
- weeklyPreSaleConfig?.ordering_days,
204
- );
205
-
206
- if (weeklyPickupDates.length > 0) {
207
- const schedule = generateLocationFulfillmentSchedule({
208
- startDate: weeklyPickupDates[0],
209
- location: currentLocation,
210
- fulfillmentPreference,
211
- businessHoursOverrides,
212
- gapInMinutes,
213
- daysCount: 7,
214
- preSaleDates: weeklyPickupDates.map((d) => d.getDate()),
215
- presalePickupWeekDays: weeklyPreSaleConfig.pickup_days,
216
- platform,
217
- });
218
-
219
- return {
220
- schedule: filterSchedule(schedule),
221
- isWeeklyPreSaleAvailable: true,
222
- };
223
- }
224
- }
225
-
226
- // ── Main schedule path ──────────────────────────────────────────────────
227
- const isPreSaleEnabled =
228
- (preSaleConfig?.active ?? false) && cart.hasPreSaleItem && !isCateringFlow;
229
- const preSaleDates = resolvePreSaleDates(
230
- preSaleConfig,
231
- currentLocation.timezone,
232
- );
233
- const preSaleHoursOverride = getPreSaleHoursOverride(
234
- preSaleConfig,
235
- cart.hasPreSaleItem,
236
- );
237
-
238
- const schedule = generateLocationFulfillmentSchedule({
239
- startDate: resolveStartDate(preSaleDates.startDate, cart.hasPreSaleItem),
240
- prepTimeFrequency,
241
- prepTimeCadence,
242
- location: currentLocation,
243
- fulfillmentPreference,
244
- businessHoursOverrides,
245
- gapInMinutes,
246
- daysCount: isPreSaleEnabled
247
- ? differenceInDays(preSaleDates.endDate, preSaleDates.startDate) + 1
248
- : !isAsapOrders && !isSameDayOrders
249
- ? daysCount
250
- : 1,
251
- platform,
252
-
253
- ...(!isPreSaleEnabled && {
254
- weekDayPrepTimes,
255
- }),
256
- ...(preSaleHoursOverride && { preSaleHoursOverride }),
257
- ...(isPreSaleEnabled && { endDate: preSaleDates.endDate }),
258
- });
259
-
260
- return {
261
- schedule: filterSchedule(schedule),
262
- isWeeklyPreSaleAvailable: false,
263
- };
264
- }
@@ -1,58 +0,0 @@
1
- import { roundToNearestMinutes } from "date-fns";
2
- import { PLATFORM, PREP_TIME_CADENCE } from "../constants";
3
- import type {
4
- FulfillmentSchedule,
5
- GenerateLocationFulfillmentScheduleParams,
6
- } from "../types";
7
- import { getLocationBusinessHoursForFulfillment } from "../utils/business-hours";
8
- import { getNextAvailableDates } from "./available-dates";
9
- import { generateSchedule } from "./generate";
10
-
11
- export function generateLocationFulfillmentSchedule({
12
- startDate,
13
- prepTimeFrequency = 0,
14
- prepTimeCadence = PREP_TIME_CADENCE.MINUTE,
15
- weekDayPrepTimes,
16
- location,
17
- fulfillmentPreference,
18
- businessHoursOverrides = [],
19
- preSaleHoursOverride,
20
- gapInMinutes,
21
- daysCount = 1,
22
- preSaleDates = [],
23
- presalePickupWeekDays = [],
24
- endDate = null,
25
- platform = PLATFORM.WEB,
26
- }: GenerateLocationFulfillmentScheduleParams): FulfillmentSchedule {
27
- const isDaysCadence = prepTimeCadence === PREP_TIME_CADENCE.DAY;
28
- const businessHours = getLocationBusinessHoursForFulfillment(
29
- location,
30
- fulfillmentPreference,
31
- );
32
-
33
- const dates = getNextAvailableDates({
34
- startDate,
35
- businessHours,
36
- businessHoursOverrides,
37
- timeZone: location.timezone,
38
- datesCount: daysCount,
39
- preSaleDates,
40
- endDate,
41
- presalePickupWeekDays,
42
- isDaysCadence,
43
- platform,
44
- });
45
- // If prepTimeCadence is days, we need to skip opening days by prepTimeFrequency
46
- const availableDates = isDaysCadence ? dates.slice(prepTimeFrequency) : dates;
47
- return generateSchedule({
48
- currentDate: roundToNearestMinutes(startDate),
49
- weekDayPrepTimes,
50
- timeZone: location.timezone,
51
- dates: availableDates,
52
- businessHours,
53
- businessHoursOverrides,
54
- preSaleHoursOverride,
55
- gapInMinutes,
56
- prepTimeCadence,
57
- });
58
- }
@@ -1,32 +0,0 @@
1
- /** Raw business-hour record from the API (snake_case keys). */
2
- export interface BusinessHourInput {
3
- day: number;
4
- start_time: string;
5
- end_time: string;
6
- }
7
-
8
- /** Normalised business-hour used internally (camelCase keys). */
9
- export interface BusinessHour {
10
- day: number;
11
- startTime: string;
12
- endTime: string;
13
- }
14
-
15
- /** Raw business-hours override coming from the API. */
16
- export interface BusinessHoursOverrideInput {
17
- all_locations?: boolean;
18
- location_ids?: string[];
19
- month: number;
20
- day: number;
21
- start_time: string | null;
22
- end_time: string | null;
23
- is_open?: boolean;
24
- }
25
-
26
- /** Normalised business-hours override. */
27
- export interface BusinessHoursOverrideOutput {
28
- month: number;
29
- day: number;
30
- startTime: string | null;
31
- endTime: string | null;
32
- }
@@ -1,5 +0,0 @@
1
- export interface BusyTimeItem {
2
- startTime: string;
3
- endTime: string;
4
- threshold?: { categoryIds?: string[] };
5
- }