@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,122 +0,0 @@
1
- import type { PrepTimeCadence } from "../constants";
2
-
3
- export interface GetCateringPrepTimeParams {
4
- items: CartItem[];
5
- prepTimeCadence?: PrepTimeCadence;
6
- prepTimeFrequency?: number;
7
- timezone?: string;
8
- }
9
-
10
- import type {
11
- BusinessHoursOverrideInput,
12
- BusinessHoursOverrideOutput,
13
- } from "./business-hours";
14
- import type { BusyTimeItem } from "./common";
15
- import type { FulfillmentPreference, LocationLike } from "./location";
16
- import type { FulfillmentSchedule, Platform } from "./schedule";
17
-
18
- // ── High-level input objects ────────────────────────────────────────────────
19
-
20
- export interface PreSaleConfig {
21
- active: boolean;
22
- due_start_date?: string | Date;
23
- due_end_date?: string | Date;
24
- use_store_hours_due?: boolean;
25
- due_start_time?: string | null;
26
- due_end_time?: string | null;
27
- }
28
-
29
- export interface WeeklyPreSaleConfig {
30
- active: boolean;
31
- pickup_days: number[];
32
- ordering_days: number[];
33
- }
34
-
35
- export interface StoreConfig {
36
- isAsapOrders: boolean;
37
- isSameDayOrders: boolean;
38
- max_future_order_days?: number;
39
- businessHoursOverrides: BusinessHoursOverrideInput[];
40
- preSaleConfig?: PreSaleConfig;
41
- weeklyPreSaleConfig?: WeeklyPreSaleConfig;
42
- }
43
- export type CateringServiceType = {
44
- min_quantity: number;
45
- max_quantity: number;
46
- serve_count: number;
47
- prep_time: {
48
- cadence: PrepTimeCadence;
49
- frequency: number;
50
- };
51
- };
52
- export interface CartItem {
53
- preSale?: boolean;
54
- weeklyPreSale?: boolean;
55
- internalCategoryId?: string;
56
- cateringService?: CateringServiceType;
57
- }
58
- export interface CateringPrepTimeResult {
59
- prepTimeCadence: PrepTimeCadence;
60
- prepTimeFrequency: number;
61
- /** Only set when prepTimeCadence is not DAY (e.g. HOUR). */
62
- weekDayPrepTimes?: Record<number, number>;
63
- }
64
-
65
- export interface PrepTimeSettings {
66
- prepTimeInMinutes: number;
67
- weekDayPrepTimes: Record<number, number>;
68
- gapInMinutes: number;
69
- busyTimes: Record<string, BusyTimeItem[]>;
70
- prepTimeFrequency: number;
71
- prepTimeCadence: PrepTimeCadence;
72
- /** When fulfillment is DELIVERY, added to each weekday prep time so slots reflect when order is received. */
73
- estimatedDeliveryMinutes?: number;
74
- }
75
-
76
- // ── getSchedules params / result ────────────────────────────────────────────
77
-
78
- export interface GetSchedulesParams {
79
- store: StoreConfig;
80
- locations: LocationLike[];
81
- cartItems: CartItem[];
82
- fulfillmentPreference: FulfillmentPreference;
83
- prepTimeSettings: PrepTimeSettings;
84
- currentLocation: LocationLike;
85
- isCateringFlow?: boolean;
86
- /** Platform for timezone handling in next-available-date logic. Default "web". */
87
- platform?: Platform;
88
- }
89
-
90
- export interface GetSchedulesResult {
91
- schedule: FulfillmentSchedule;
92
- isWeeklyPreSaleAvailable: boolean;
93
- }
94
-
95
- // ── Legacy flat params (kept for backward-compat if needed) ─────────────────
96
-
97
- export interface InitScheduleParams {
98
- isAsapOrders: boolean;
99
- isSameDayOrders: boolean;
100
- preSalePickupDays: number[];
101
- isWeeklyPreSaleActive: boolean;
102
- preSaleOrderingDays: number[];
103
- locations: LocationLike[];
104
- daysCount?: number;
105
- fulfillmentPreference: FulfillmentPreference;
106
- prepTimeInMinutes: number;
107
- weekDayPrepTimes: Record<number, number>;
108
- hasCartWeeklyPreSaleItem: boolean;
109
- busyTimes: BusyTimeItem[];
110
- cartCategoryIds: string[];
111
- gapInMinutes: number;
112
- businessHoursOverrides: Record<string, BusinessHoursOverrideOutput[]>;
113
- currentLocation: LocationLike;
114
- }
115
-
116
- export interface InitScheduleResult {
117
- businessHoursOverrides: Record<string, BusinessHoursOverrideOutput[]>;
118
- locationId: string;
119
- fulfillmentPreference: FulfillmentPreference;
120
- schedule: FulfillmentSchedule;
121
- isWeeklyPreSaleAvailable: boolean;
122
- }
@@ -1,34 +0,0 @@
1
- export type {
2
- BusinessHour,
3
- BusinessHourInput,
4
- BusinessHoursOverrideInput,
5
- BusinessHoursOverrideOutput,
6
- } from "./business-hours";
7
- export type { BusyTimeItem } from "./common";
8
- export type {
9
- CartItem,
10
- CateringPrepTimeResult,
11
- GetCateringPrepTimeParams,
12
- GetSchedulesParams,
13
- GetSchedulesResult,
14
- InitScheduleParams,
15
- InitScheduleResult,
16
- PrepTimeSettings,
17
- PreSaleConfig,
18
- StoreConfig,
19
- WeeklyPreSaleConfig,
20
- } from "./get-schedules";
21
- export type { FulfillmentPreference, LocationLike } from "./location";
22
- export type {
23
- DaySchedule,
24
- FulfillmentSchedule,
25
- GenerateLocationFulfillmentScheduleParams,
26
- GenerateScheduleParams,
27
- GetNextAvailableDatesParams,
28
- GetOpeningClosingTimeOnDateParams,
29
- Platform,
30
- } from "./schedule";
31
- export type {
32
- FilterBusyTimesFromScheduleParams,
33
- MenuType,
34
- } from "./schedule-filter";
@@ -1,25 +0,0 @@
1
- import type { BusinessHourInput } from "./business-hours";
2
-
3
- export type FulfillmentPreference = "PICKUP" | "DELIVERY" | "CURBSIDE";
4
- export type BusinessHourType = {
5
- day: number;
6
- start_time: string;
7
- end_time: string;
8
- };
9
- export interface LocationLike {
10
- location_id: string;
11
- id?: string;
12
- timezone: string;
13
- pickup_hours?: BusinessHourInput[];
14
- delivery_hours?: BusinessHourInput[];
15
- curbside_hours?: {
16
- use_pickup_hours?: boolean;
17
- times?: BusinessHourInput[];
18
- };
19
- catering?: {
20
- enabled: boolean | string;
21
- pickup: Omit<BusinessHourType, "day">;
22
- delivery: Omit<BusinessHourType, "day">;
23
- };
24
- [key: string]: unknown;
25
- }
@@ -1,27 +0,0 @@
1
- import type { BusyTimeItem } from "./common";
2
- import type { FulfillmentSchedule } from "./schedule";
3
- export type MenuTimeSlot = {
4
- all_day: boolean;
5
- end_time: string | null;
6
- start_time: string | null;
7
- };
8
-
9
- export type MenuType = {
10
- menu_id: string;
11
- store_id: string;
12
- location_id: string | null;
13
- all_locations: boolean;
14
- display_name: string;
15
- description: string | null;
16
- times: Record<string, MenuTimeSlot>;
17
- category_ids: string[];
18
- last_modified_by: string;
19
- created_at: string;
20
- updated_at: string;
21
- };
22
-
23
- export interface FilterBusyTimesFromScheduleParams {
24
- schedule: FulfillmentSchedule;
25
- busyTimes?: BusyTimeItem[];
26
- cartCategoryIds?: string[];
27
- }
@@ -1,83 +0,0 @@
1
- import type { PLATFORM } from "../constants";
2
- import type {
3
- BusinessHour,
4
- BusinessHoursOverrideOutput,
5
- } from "./business-hours";
6
- import type { FulfillmentPreference, LocationLike } from "./location";
7
-
8
- export interface DaySchedule {
9
- date: Date;
10
- originalStoreOpeningTime: Date | null;
11
- originalStoreClosingTime: Date | null;
12
- remainingShifts: number;
13
- openingTime: Date;
14
- closingTime: Date;
15
- firstAvailableSlot: Date;
16
- slots: Date[];
17
- [key: string]: unknown;
18
- }
19
-
20
- export type FulfillmentSchedule = DaySchedule[];
21
-
22
- export interface GenerateScheduleParams {
23
- currentDate?: Date;
24
- prepTimeBehaviour?: number;
25
- prepTimeInMinutes?: number;
26
- weekDayPrepTimes?: Record<number, number>;
27
- timeZone: string;
28
- dates?: Date[];
29
- businessHours?: BusinessHour[];
30
- businessHoursOverrides?: BusinessHoursOverrideOutput[];
31
- preSaleHoursOverride?: Array<{
32
- startTime: string;
33
- endTime: string;
34
- month?: number;
35
- day?: number;
36
- }> | null;
37
- gapInMinutes?: number;
38
- prepTimeCadence?: PrepTimeCadence;
39
- }
40
- export type Platform = (typeof PLATFORM)[keyof typeof PLATFORM];
41
- export interface GetNextAvailableDatesParams {
42
- startDate: Date;
43
- timeZone: string;
44
- businessHours: BusinessHour[];
45
- businessHoursOverrides?: BusinessHoursOverrideOutput[];
46
- datesCount?: number;
47
- preSaleDates?: number[];
48
- presalePickupWeekDays?: number[];
49
- endDate?: Date | null;
50
- isDaysCadence?: boolean;
51
- /** Platform for timezone handling. Web uses @date-fns/tz; ios/android use timezone-support. Default "web". */
52
- platform?: Platform;
53
- }
54
-
55
- export interface GenerateLocationFulfillmentScheduleParams {
56
- startDate: Date;
57
- prepTimeFrequency?: number;
58
- prepTimeCadence?: PrepTimeCadence;
59
- weekDayPrepTimes?: Record<number, number>;
60
- location: LocationLike;
61
- fulfillmentPreference: FulfillmentPreference;
62
- /** Overrides for this location only (not keyed by location_id). */
63
- businessHoursOverrides?: BusinessHoursOverrideOutput[];
64
- preSaleHoursOverride?: Array<{
65
- startTime: string;
66
- endTime: string;
67
- month?: number;
68
- day?: number;
69
- }> | null;
70
- gapInMinutes?: number;
71
- daysCount?: number;
72
- preSaleDates?: number[];
73
- presalePickupWeekDays?: number[];
74
- endDate?: Date | null;
75
- platform?: Platform;
76
- }
77
-
78
- export interface GetOpeningClosingTimeOnDateParams {
79
- date?: Date;
80
- businessHours?: BusinessHour[];
81
- businessHoursOverrides?: BusinessHoursOverrideOutput[];
82
- timeZone: string;
83
- }
@@ -1,31 +0,0 @@
1
- declare module "timezone-support" {
2
- export function findTimeZone(timezone: string): string;
3
- export function getUnixTime(time: {
4
- zone: string;
5
- year: number;
6
- month: number;
7
- day: number;
8
- hours: number | string;
9
- minutes: number | string;
10
- seconds: number | string;
11
- milliseconds: number | string;
12
- }): number;
13
- export function getZonedTime(
14
- date: Date | number,
15
- timezone: string,
16
- ): {
17
- zone: string;
18
- year: number;
19
- month: number;
20
- day: number;
21
- hours: number | string;
22
- minutes: number | string;
23
- seconds: number | string;
24
- milliseconds: number | string;
25
- dayOfWeek: number;
26
- };
27
- export function toZonedTime(
28
- date: Date | number | string,
29
- timezone: string,
30
- ): Date;
31
- }
@@ -1,120 +0,0 @@
1
- import { FULFILLMENT_TYPES } from "../constants";
2
- import type {
3
- BusinessHour,
4
- BusinessHoursOverrideInput,
5
- BusinessHoursOverrideOutput,
6
- FulfillmentPreference,
7
- LocationLike,
8
- } from "../types";
9
-
10
- export function toBusinessHoursOverride(
11
- businessHoursOverride: BusinessHoursOverrideInput,
12
- ): BusinessHoursOverrideOutput {
13
- const {
14
- month,
15
- day,
16
- start_time: startTime,
17
- end_time: endTime,
18
- is_open: isOpen,
19
- } = businessHoursOverride;
20
-
21
- return {
22
- month,
23
- day,
24
- startTime: isOpen ? startTime : null,
25
- endTime: isOpen ? endTime : null,
26
- };
27
- }
28
-
29
- export function getLocationsBusinessHoursOverrides(
30
- businessHoursOverrides: BusinessHoursOverrideInput[],
31
- locations: LocationLike[],
32
- ): Record<string, BusinessHoursOverrideOutput[]> {
33
- const result: Record<string, BusinessHoursOverrideOutput[]> = {};
34
-
35
- for (const override of businessHoursOverrides) {
36
- const { all_locations: allLocations, location_ids: locationIds } =
37
- override || {};
38
-
39
- if (allLocations === true) {
40
- for (const location of locations || []) {
41
- const id = location.location_id;
42
- result[id] ??= [];
43
- result[id].push(toBusinessHoursOverride(override));
44
- }
45
- } else {
46
- for (const id of locationIds || []) {
47
- const location = locations.find((loc) => loc.location_id === id);
48
- if (location) {
49
- result[id] ??= [];
50
- result[id].push(toBusinessHoursOverride(override));
51
- }
52
- }
53
- }
54
- }
55
-
56
- return result;
57
- }
58
-
59
- export const isLocationCateringEnabled = (
60
- location: LocationLike | undefined,
61
- ): boolean => {
62
- if (!location) return false;
63
- return (
64
- !!location?.catering?.enabled && location?.catering?.enabled !== "false"
65
- );
66
- };
67
-
68
- export function getLocationBusinessHoursForFulfillment(
69
- location: LocationLike,
70
- fulfillmentPreference: FulfillmentPreference,
71
- isCatering = false,
72
- ): BusinessHour[] {
73
- const fulfillmentBusinessHours: Record<
74
- string,
75
- Array<{ day: number; start_time: string; end_time: string }> | undefined
76
- > = {
77
- [FULFILLMENT_TYPES.PICKUP]: location?.pickup_hours,
78
- [FULFILLMENT_TYPES.DELIVERY]: location?.delivery_hours,
79
- [FULFILLMENT_TYPES.CURBSIDE]: location?.curbside_hours?.use_pickup_hours
80
- ? location?.pickup_hours
81
- : location?.curbside_hours?.times,
82
- };
83
-
84
- const cateringBusinessTimings: Partial<
85
- Record<FulfillmentPreference, { start_time: string; end_time: string }>
86
- > = {
87
- [FULFILLMENT_TYPES.PICKUP]: location?.catering?.pickup,
88
- [FULFILLMENT_TYPES.DELIVERY]: location?.catering?.delivery,
89
- };
90
-
91
- const businessHours = fulfillmentBusinessHours[fulfillmentPreference];
92
-
93
- const cateringBusinessTiming =
94
- isCatering && isLocationCateringEnabled(location)
95
- ? cateringBusinessTimings[fulfillmentPreference]
96
- : null;
97
-
98
- if (isCatering && !cateringBusinessTiming) {
99
- //if catering is enabled but no business hours are set, return empty arrayif
100
- return [];
101
- }
102
-
103
- return (
104
- businessHours?.map((businessHour) => {
105
- if (isCatering && cateringBusinessTiming) {
106
- //if catering is enabled and catering business hours are set, return catering business hours
107
- return {
108
- day: businessHour.day,
109
- startTime: cateringBusinessTiming.start_time,
110
- endTime: cateringBusinessTiming.end_time,
111
- };
112
- }
113
- return {
114
- day: businessHour.day,
115
- startTime: businessHour.start_time,
116
- endTime: businessHour.end_time,
117
- };
118
- }) ?? []
119
- );
120
- }
@@ -1,85 +0,0 @@
1
- import { findTimeZone, getZonedTime } from "timezone-support";
2
- import { DEFAULT_TIMEZONE, PREP_TIME_CADENCE } from "../constants";
3
- import type {
4
- CateringPrepTimeResult,
5
- GetCateringPrepTimeParams,
6
- } from "../types";
7
-
8
- function buildCateringPrepTimeResult(
9
- prepTimeCadence: CateringPrepTimeResult["prepTimeCadence"],
10
- prepTimeFrequency: number,
11
- timezone: string = DEFAULT_TIMEZONE,
12
- ): CateringPrepTimeResult {
13
- const result: CateringPrepTimeResult = {
14
- prepTimeCadence,
15
- prepTimeFrequency,
16
- };
17
- if (prepTimeCadence === PREP_TIME_CADENCE.DAY) {
18
- result.weekDayPrepTimes = {};
19
- } else {
20
- result.weekDayPrepTimes = {
21
- [getZonedTime(new Date(), findTimeZone(timezone)).dayOfWeek]:
22
- prepTimeCadence === PREP_TIME_CADENCE.HOUR
23
- ? prepTimeFrequency * 60
24
- : prepTimeFrequency,
25
- };
26
- }
27
- return result;
28
- }
29
-
30
- /**
31
- * Derives prep time config (cadence, frequency, weekDayPrepTimes) from cart items for catering flow.
32
- * DAY cadence has priority; if any item uses days, returns max day frequency.
33
- * Otherwise returns HOUR cadence with max hour frequency across items.
34
- * When items are empty or have no catering prep time, falls back to params (e.g. from prepTimeSettings).
35
- */
36
- export function getCateringPrepTimeConfig(
37
- params: GetCateringPrepTimeParams,
38
- ): CateringPrepTimeResult {
39
- const { items, timezone = DEFAULT_TIMEZONE } = params;
40
-
41
- if (items.length === 0) {
42
- return buildCateringPrepTimeResult(
43
- params.prepTimeCadence ?? PREP_TIME_CADENCE.HOUR,
44
- params.prepTimeFrequency ?? 1,
45
- timezone,
46
- );
47
- }
48
-
49
- const dayFrequencies: number[] = [];
50
- const hourFrequencies: number[] = [];
51
-
52
- for (const item of items) {
53
- const cadence = item.cateringService?.prep_time?.cadence;
54
- const frequency = item.cateringService?.prep_time?.frequency;
55
- if (cadence == null || frequency == null) continue;
56
-
57
- if (cadence === PREP_TIME_CADENCE.DAY) {
58
- dayFrequencies.push(frequency);
59
- } else if (cadence === PREP_TIME_CADENCE.HOUR) {
60
- hourFrequencies.push(frequency);
61
- }
62
- }
63
-
64
- if (dayFrequencies.length > 0) {
65
- return buildCateringPrepTimeResult(
66
- PREP_TIME_CADENCE.DAY,
67
- Math.max(...dayFrequencies),
68
- timezone,
69
- );
70
- }
71
-
72
- if (hourFrequencies.length > 0) {
73
- return buildCateringPrepTimeResult(
74
- PREP_TIME_CADENCE.HOUR,
75
- Math.max(...hourFrequencies),
76
- timezone,
77
- );
78
- }
79
-
80
- return buildCateringPrepTimeResult(
81
- params.prepTimeCadence ?? PREP_TIME_CADENCE.HOUR,
82
- params.prepTimeFrequency ?? 1,
83
- timezone,
84
- );
85
- }
package/src/utils/date.ts DELETED
@@ -1,163 +0,0 @@
1
- import { addDays, compareAsc } from "date-fns";
2
- import { findTimeZone, getUnixTime, getZonedTime } from "timezone-support";
3
-
4
- import type { BusinessHour } from "../types";
5
-
6
- export function setHmOnDate(date: Date, hm: string, timeZone: string): Date {
7
- const [hours, minutes] = String(hm).split(":");
8
-
9
- const zonedTime = getZonedTime(new Date(date), findTimeZone(timeZone));
10
-
11
- return new Date(
12
- getUnixTime({
13
- zone: zonedTime.zone,
14
- year: zonedTime.year,
15
- month: zonedTime.month,
16
- day: zonedTime.day,
17
- hours: hours === "24" ? 23 : Number(hours),
18
- minutes: hours === "24" ? 59 : Number(minutes),
19
- seconds: 0,
20
- milliseconds: 0,
21
- }),
22
- );
23
- }
24
-
25
- export function getNextDateForDayOfWeek(
26
- targetDayIndex: number,
27
- referenceDate: Date = new Date(),
28
- ): Date {
29
- const currentDayIndex = referenceDate.getDay();
30
- const daysUntilTarget = (targetDayIndex - currentDayIndex + 7) % 7;
31
- return addDays(referenceDate, daysUntilTarget);
32
- }
33
-
34
- export function getPreSalePickupDates(
35
- preSalePickupDays: number[] = [],
36
- preSaleOrderingDays: number[] = [],
37
- ): Date[] {
38
- const today = new Date();
39
- const currentDayIndex = today.getDay();
40
-
41
- if (preSalePickupDays.includes(currentDayIndex)) {
42
- return [];
43
- }
44
-
45
- if (!preSaleOrderingDays.includes(currentDayIndex)) {
46
- return [];
47
- }
48
-
49
- return preSalePickupDays
50
- .map((day) => getNextDateForDayOfWeek(day))
51
- .sort(compareAsc);
52
- }
53
-
54
- export function overrideTimeZoneOnUTC(
55
- date: Date | string,
56
- timeZoneB: string,
57
- ): Date {
58
- const timeZoneATime = getZonedTime(new Date(date), findTimeZone("UTC"));
59
- const timeZoneBTime = getZonedTime(new Date(date), findTimeZone(timeZoneB));
60
-
61
- return new Date(
62
- getUnixTime({
63
- ...timeZoneATime,
64
- zone: timeZoneBTime.zone,
65
- }),
66
- );
67
- }
68
-
69
- export function isTodayInTimeZone(date: Date, timeZone: string): boolean {
70
- if (!date) {
71
- return false;
72
- }
73
- const zonedNow = getZonedTime(Date.now(), findTimeZone(timeZone));
74
- const zonedTime = getZonedTime(date, findTimeZone(timeZone));
75
-
76
- return zonedNow.day === zonedTime.day && zonedNow.month === zonedTime.month;
77
- }
78
-
79
- export function isTomorrowInTimeZone(date: Date, timeZone: string): boolean {
80
- const zonedNow = getZonedTime(addDays(Date.now(), 1), findTimeZone(timeZone));
81
- const zonedTime = getZonedTime(date, findTimeZone(timeZone));
82
-
83
- return zonedNow.day === zonedTime.day && zonedNow.month === zonedTime.month;
84
- }
85
-
86
- export function isSameDateInTimeZone(
87
- dateLeft: Date,
88
- dateRight: Date,
89
- timeZone: string,
90
- ): boolean {
91
- const zonedDateLeft = getZonedTime(dateLeft, findTimeZone(timeZone));
92
- const zonedDateRight = getZonedTime(dateRight, findTimeZone(timeZone));
93
-
94
- return (
95
- zonedDateLeft.year === zonedDateRight.year &&
96
- zonedDateLeft.month === zonedDateRight.month &&
97
- zonedDateLeft.day === zonedDateRight.day
98
- );
99
- }
100
-
101
- export function isMidnightTransition(
102
- endDate: Date,
103
- startDateNextDay: Date,
104
- timeZone: string,
105
- ): boolean {
106
- if (!endDate || !startDateNextDay) {
107
- return false;
108
- }
109
- const zonedEndDate = getZonedTime(endDate, findTimeZone(timeZone));
110
- const zonedStartDate = getZonedTime(startDateNextDay, findTimeZone(timeZone));
111
-
112
- return (
113
- zonedEndDate.hours === 23 &&
114
- zonedEndDate.minutes === 59 &&
115
- zonedStartDate.hours === 0 &&
116
- zonedStartDate.minutes === 0
117
- );
118
- }
119
-
120
- export function addDaysInTimeZone(
121
- date: Date,
122
- days: number,
123
- timeZone: string,
124
- ): Date {
125
- const zonedTime = getZonedTime(addDays(date, days), findTimeZone(timeZone));
126
- return new Date(
127
- getUnixTime({
128
- ...zonedTime,
129
- hours: 0,
130
- minutes: 0,
131
- seconds: 0,
132
- milliseconds: 0,
133
- }),
134
- );
135
- }
136
-
137
- export function isZeroPrepTimeForMidnightShift({
138
- prevDayBusinessHours,
139
- businessHour,
140
- }: {
141
- prevDayBusinessHours: BusinessHour[];
142
- businessHour: BusinessHour;
143
- }): boolean {
144
- if (
145
- !Array.isArray(prevDayBusinessHours) ||
146
- prevDayBusinessHours.length === 0
147
- ) {
148
- return false;
149
- }
150
-
151
- if (!businessHour || businessHour.startTime !== "00:00") {
152
- return false;
153
- }
154
-
155
- const currentDay = businessHour.day;
156
- const prevDay = (currentDay + 6) % 7;
157
-
158
- const prevDayHas24End = prevDayBusinessHours.some(
159
- (bh) =>
160
- bh.day === prevDay && (bh.endTime === "24:00" || bh.endTime === "23:59"),
161
- );
162
- return prevDayHas24End;
163
- }