@shopbite-de/storefront 1.4.0 → 1.5.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.
@@ -3,14 +3,110 @@ import { mockNuxtImport } from "@nuxt/test-utils/runtime";
3
3
  import { ref } from "vue";
4
4
  import { useDeliveryTime } from "~/composables/useDeliveryTime";
5
5
 
6
- const { mockDeliveryTime } = vi.hoisted(() => ({
7
- mockDeliveryTime: { value: 45 }, // Use object to keep reference
8
- }));
6
+ const { mockDeliveryTime, mockBusinessHours, mockHolidays } = vi.hoisted(
7
+ () => ({
8
+ mockDeliveryTime: { value: 45 },
9
+ mockBusinessHours: {
10
+ value: [
11
+ { dayOfWeek: 1, openingTime: "11:30", closingTime: "14:30" },
12
+ { dayOfWeek: 1, openingTime: "17:30", closingTime: "23:00" },
13
+ { dayOfWeek: 3, openingTime: "11:30", closingTime: "14:30" },
14
+ { dayOfWeek: 3, openingTime: "17:30", closingTime: "23:00" },
15
+ { dayOfWeek: 4, openingTime: "11:30", closingTime: "14:30" },
16
+ { dayOfWeek: 4, openingTime: "17:30", closingTime: "23:00" },
17
+ { dayOfWeek: 5, openingTime: "11:30", closingTime: "14:30" },
18
+ { dayOfWeek: 5, openingTime: "17:30", closingTime: "23:00" },
19
+ { dayOfWeek: 6, openingTime: "17:30", closingTime: "23:30" },
20
+ { dayOfWeek: 0, openingTime: "11:30", closingTime: "14:30" },
21
+ { dayOfWeek: 0, openingTime: "17:30", closingTime: "23:00" },
22
+ ],
23
+ },
24
+ mockHolidays: { value: [] },
25
+ }),
26
+ );
9
27
 
10
28
  mockNuxtImport("useShopBiteConfig", () => () => ({
11
29
  deliveryTime: mockDeliveryTime,
12
30
  }));
13
31
 
32
+ mockNuxtImport("useBusinessHours", () => () => ({
33
+ businessHours: mockBusinessHours,
34
+ getServiceIntervals: (date: Date) => {
35
+ const dayOfWeek = date.getDay();
36
+ return mockBusinessHours.value
37
+ .filter((bh) => bh.dayOfWeek === dayOfWeek)
38
+ .map((bh) => {
39
+ const [startH, startM] = bh.openingTime.split(":").map(Number);
40
+ const [endH, endM] = bh.closingTime.split(":").map(Number);
41
+ const start = new Date(date);
42
+ start.setHours(startH, startM, 0, 0);
43
+ const end = new Date(date);
44
+ end.setHours(endH, endM, 0, 0);
45
+ return { start, end };
46
+ });
47
+ },
48
+ getEarliestSelectableTime: (
49
+ currentTime: Date,
50
+ currentDeliveryTime: number | null,
51
+ ) => {
52
+ const earliest = new Date(currentTime);
53
+ earliest.setMinutes(earliest.getMinutes() + (currentDeliveryTime ?? 30));
54
+ earliest.setSeconds(0, 0);
55
+ return earliest;
56
+ },
57
+ findActiveInterval: (
58
+ currentTime: Date,
59
+ currentDeliveryTime: number | null,
60
+ ) => {
61
+ const intervals = [
62
+ { dayOfWeek: 1, openingTime: "11:30", closingTime: "14:30" },
63
+ { dayOfWeek: 1, openingTime: "17:30", closingTime: "23:00" },
64
+ { dayOfWeek: 3, openingTime: "11:30", closingTime: "14:30" },
65
+ { dayOfWeek: 3, openingTime: "17:30", closingTime: "23:00" },
66
+ { dayOfWeek: 4, openingTime: "11:30", closingTime: "14:30" },
67
+ { dayOfWeek: 4, openingTime: "17:30", closingTime: "23:00" },
68
+ { dayOfWeek: 5, openingTime: "11:30", closingTime: "14:30" },
69
+ { dayOfWeek: 5, openingTime: "17:30", closingTime: "23:00" },
70
+ { dayOfWeek: 6, openingTime: "17:30", closingTime: "23:30" },
71
+ { dayOfWeek: 0, openingTime: "11:30", closingTime: "14:30" },
72
+ { dayOfWeek: 0, openingTime: "17:30", closingTime: "23:00" },
73
+ ]
74
+ .filter((bh) => bh.dayOfWeek === currentTime.getDay())
75
+ .map((bh) => {
76
+ const [startH, startM] = bh.openingTime.split(":").map(Number);
77
+ const [endH, endM] = bh.closingTime.split(":").map(Number);
78
+ const start = new Date(currentTime);
79
+ start.setHours(startH, startM, 0, 0);
80
+ const end = new Date(currentTime);
81
+ end.setHours(endH, endM, 0, 0);
82
+ return { start, end };
83
+ });
84
+
85
+ const earliest = new Date(currentTime);
86
+ earliest.setMinutes(earliest.getMinutes() + (currentDeliveryTime ?? 30));
87
+ earliest.setSeconds(0, 0);
88
+
89
+ if (intervals.length === 0) return null;
90
+ const current = intervals.find(
91
+ (i) => earliest >= i.start && earliest <= i.end,
92
+ );
93
+ if (current) return current;
94
+ return intervals.find((i) => i.start > earliest) ?? null;
95
+ },
96
+ }));
97
+
98
+ mockNuxtImport("useHolidays", () => () => ({
99
+ isClosedHoliday: (date: Date) => {
100
+ if (!mockHolidays.value) return undefined;
101
+ const formattedDate = date.toISOString().split("T")[0];
102
+ return mockHolidays.value.some((h: any) => {
103
+ const start = h.start.split("T")[0];
104
+ const end = h.end.split("T")[0];
105
+ return formattedDate >= start && formattedDate <= end;
106
+ });
107
+ },
108
+ }));
109
+
14
110
  describe("useDeliveryTime", () => {
15
111
  const now = ref(new Date("2023-10-27T12:00:00")); // A Friday
16
112
 
@@ -42,7 +138,9 @@ describe("useDeliveryTime", () => {
42
138
 
43
139
  it("should return error for invalid format", () => {
44
140
  const { validate } = useDeliveryTime(now);
45
- expect(validate("invalid")).toBe("Bitte eine gültige Uhrzeit im Format HH:MM eingeben.");
141
+ expect(validate("invalid")).toBe(
142
+ "Bitte eine gültige Uhrzeit im Format HH:MM eingeben.",
143
+ );
46
144
  });
47
145
 
48
146
  it("should return error for time before minTime", () => {
@@ -52,10 +150,22 @@ describe("useDeliveryTime", () => {
52
150
  const [hours, mins] = minTime.value.split(":").map(Number);
53
151
  const earlyTime = new Date(now.value);
54
152
  earlyTime.setHours(hours as number);
55
- earlyTime.setMinutes(mins as number - 5);
56
- const earlyTimeStr = earlyTime.getHours().toString().padStart(2, '0') + ":" + earlyTime.getMinutes().toString().padStart(2, '0');
57
-
58
- expect(validate(earlyTimeStr)).toContain("vor dem frühestmöglichen Zeitpunkt");
153
+ earlyTime.setMinutes((mins as number) - 5);
154
+ const earlyTimeStr =
155
+ earlyTime.getHours().toString().padStart(2, "0") +
156
+ ":" +
157
+ earlyTime.getMinutes().toString().padStart(2, "0");
158
+
159
+ expect(validate(earlyTimeStr)).toContain(
160
+ "vor dem frühestmöglichen Zeitpunkt",
161
+ );
59
162
  }
60
163
  });
164
+
165
+ it("should return loading message when holidays are not loaded", () => {
166
+ mockHolidays.value = null;
167
+ const { helperText } = useDeliveryTime(now);
168
+ expect(helperText.value).toBe("Lade Informationen...");
169
+ mockHolidays.value = []; // Reset for other tests
170
+ });
61
171
  });
@@ -1,12 +1,7 @@
1
1
  import { describe, it, expect, vi, beforeEach } from "vitest";
2
2
  import { useProductConfigurator } from "../../app/composables/useProductConfigurator";
3
3
 
4
-
5
- const {
6
- mockInvoke,
7
- mockConfigurator,
8
- mockProduct,
9
- } = vi.hoisted(() => ({
4
+ const { mockInvoke, mockConfigurator, mockProduct } = vi.hoisted(() => ({
10
5
  mockInvoke: vi.fn(),
11
6
  mockConfigurator: { value: [] },
12
7
  mockProduct: { value: { id: "p1", optionIds: [], options: [] } },
@@ -35,7 +30,7 @@ describe("useProductConfigurator", () => {
35
30
  mockProduct.value = {
36
31
  id: "p1",
37
32
  optionIds: [],
38
- options: []
33
+ options: [],
39
34
  } as any;
40
35
  });
41
36
 
@@ -44,14 +39,14 @@ describe("useProductConfigurator", () => {
44
39
  {
45
40
  id: "g1",
46
41
  name: "Size",
47
- options: [{ id: "o1", name: "Small" }]
48
- }
42
+ options: [{ id: "o1", name: "Small" }],
43
+ },
49
44
  ] as any;
50
45
  mockProduct.value = {
51
46
  id: "p1-v1",
52
47
  parentId: "p1",
53
48
  optionIds: ["o1"],
54
- options: [{ id: "o1" }]
49
+ options: [{ id: "o1" }],
55
50
  } as any;
56
51
 
57
52
  const { isLoadingOptions } = useProductConfigurator();
@@ -62,23 +57,26 @@ describe("useProductConfigurator", () => {
62
57
  mockProduct.value = { parentId: "parent-1" } as any;
63
58
  mockInvoke.mockResolvedValue({
64
59
  data: {
65
- elements: [{ id: "variant-1" }]
66
- }
60
+ elements: [{ id: "variant-1" }],
61
+ },
67
62
  });
68
63
 
69
64
  const { findVariantForSelectedOptions } = useProductConfigurator();
70
- const result = await findVariantForSelectedOptions({ "Size": "o1" });
65
+ const result = await findVariantForSelectedOptions({ Size: "o1" });
71
66
 
72
- expect(mockInvoke).toHaveBeenCalledWith("readProduct post /product", expect.any(Object));
67
+ expect(mockInvoke).toHaveBeenCalledWith(
68
+ "readProduct post /product",
69
+ expect.any(Object),
70
+ );
73
71
  expect(result).toEqual({ id: "variant-1" });
74
72
  });
75
73
 
76
74
  it("should return undefined on error in findVariantForSelectedOptions", async () => {
77
75
  mockInvoke.mockRejectedValue(new Error("API Error"));
78
- const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
76
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
79
77
 
80
78
  const { findVariantForSelectedOptions } = useProductConfigurator();
81
- const result = await findVariantForSelectedOptions({ "Size": "o1" });
79
+ const result = await findVariantForSelectedOptions({ Size: "o1" });
82
80
 
83
81
  expect(result).toBeUndefined();
84
82
  expect(consoleSpy).toHaveBeenCalled();
@@ -18,10 +18,10 @@ describe("useProductVariants", () => {
18
18
  group: {
19
19
  id: "group-size",
20
20
  name: "Size",
21
- translated: { name: "Größe" }
21
+ translated: { name: "Größe" },
22
22
  },
23
- translated: { name: "Klein" }
24
- }
23
+ translated: { name: "Klein" },
24
+ },
25
25
  },
26
26
  {
27
27
  option: {
@@ -30,10 +30,10 @@ describe("useProductVariants", () => {
30
30
  group: {
31
31
  id: "group-size",
32
32
  name: "Size",
33
- translated: { name: "Größe" }
33
+ translated: { name: "Größe" },
34
34
  },
35
- translated: { name: "Groß" }
36
- }
35
+ translated: { name: "Groß" },
36
+ },
37
37
  },
38
38
  {
39
39
  option: {
@@ -42,22 +42,22 @@ describe("useProductVariants", () => {
42
42
  group: {
43
43
  id: "group-color",
44
44
  name: "Color",
45
- translated: { name: "Farbe" }
45
+ translated: { name: "Farbe" },
46
46
  },
47
- translated: { name: "Rot" }
48
- }
49
- }
47
+ translated: { name: "Rot" },
48
+ },
49
+ },
50
50
  ]);
51
51
 
52
52
  const { variants } = useProductVariants(settings as any);
53
-
53
+
54
54
  expect(variants.value["group-size"]).toBeDefined();
55
55
  expect(variants.value["group-size"].name).toBe("Größe");
56
56
  expect(variants.value["group-size"].options).toHaveLength(2);
57
57
  expect(variants.value["group-size"].options[0]).toEqual({
58
58
  label: "Klein",
59
59
  value: "opt-1",
60
- productId: "opt-1"
60
+ productId: "opt-1",
61
61
  });
62
62
 
63
63
  expect(variants.value["group-color"]).toBeDefined();
@@ -71,16 +71,16 @@ describe("useProductVariants", () => {
71
71
  option: {
72
72
  id: "opt-1",
73
73
  name: "Small",
74
- group: { id: "group-size", name: "Size" }
75
- }
74
+ group: { id: "group-size", name: "Size" },
75
+ },
76
76
  },
77
77
  {
78
78
  option: {
79
79
  id: "opt-1",
80
80
  name: "Small",
81
- group: { id: "group-size", name: "Size" }
82
- }
83
- }
81
+ group: { id: "group-size", name: "Size" },
82
+ },
83
+ },
84
84
  ]);
85
85
 
86
86
  const { variants } = useProductVariants(settings as any);
@@ -17,13 +17,13 @@ describe("useProductVariantsZwei", () => {
17
17
  translated: { name: "Größe" },
18
18
  options: [
19
19
  { id: "opt-1", name: "Small", translated: { name: "Klein" } },
20
- { id: "opt-2", name: "Large", translated: { name: "Groß" } }
21
- ]
22
- }
20
+ { id: "opt-2", name: "Large", translated: { name: "Groß" } },
21
+ ],
22
+ },
23
23
  ]);
24
24
 
25
25
  const { variants } = useProductVariantsZwei(settings);
26
-
26
+
27
27
  expect(variants.value["group-size"]).toBeDefined();
28
28
  expect(variants.value["group-size"]?.name).toBe("Größe");
29
29
  expect(variants.value["group-size"]?.options).toHaveLength(2);
@@ -37,9 +37,9 @@ describe("useProductVariantsZwei", () => {
37
37
  name: "Size",
38
38
  options: [
39
39
  { id: "opt-1", name: "Small" },
40
- { id: "opt-1", name: "Small" }
41
- ]
42
- }
40
+ { id: "opt-1", name: "Small" },
41
+ ],
42
+ },
43
43
  ]);
44
44
 
45
45
  const { variants } = useProductVariantsZwei(settings);
@@ -15,12 +15,14 @@ describe("useScrollAnimation", () => {
15
15
  disconnectMock = vi.fn();
16
16
 
17
17
  // Mock IntersectionObserver
18
- global.IntersectionObserver = vi.fn().mockImplementation(function (callback) {
19
- intersectionCallback = callback;
20
- this.observe = observeMock;
21
- this.unobserve = unobserveMock;
22
- this.disconnect = disconnectMock;
23
- }) as any;
18
+ global.IntersectionObserver = vi
19
+ .fn()
20
+ .mockImplementation(function (callback) {
21
+ intersectionCallback = callback;
22
+ this.observe = observeMock;
23
+ this.unobserve = unobserveMock;
24
+ this.disconnect = disconnectMock;
25
+ }) as any;
24
26
  });
25
27
 
26
28
  it("should initialize with isVisible false", () => {
@@ -2,15 +2,13 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
2
2
  import { mockNuxtImport } from "@nuxt/test-utils/runtime";
3
3
  import { useShopBiteConfig } from "~/composables/useShopBiteConfig";
4
4
 
5
- const {
6
- mockInvoke,
7
- mockDeliveryTime,
8
- mockIsCheckoutEnabled,
9
- } = vi.hoisted(() => ({
10
- mockInvoke: vi.fn(),
11
- mockDeliveryTime: { value: 0 },
12
- mockIsCheckoutEnabled: { value: false },
13
- }));
5
+ const { mockInvoke, mockDeliveryTime, mockIsCheckoutEnabled } = vi.hoisted(
6
+ () => ({
7
+ mockInvoke: vi.fn(),
8
+ mockDeliveryTime: { value: 0 },
9
+ mockIsCheckoutEnabled: { value: false },
10
+ }),
11
+ );
14
12
 
15
13
  mockNuxtImport("useShopwareContext", () => () => ({
16
14
  apiClient: {
@@ -43,8 +41,8 @@ describe("useShopBiteConfig", () => {
43
41
  mockInvoke.mockResolvedValue({
44
42
  data: {
45
43
  deliveryTime: 45,
46
- isCheckoutEnabled: true
47
- }
44
+ isCheckoutEnabled: true,
45
+ },
48
46
  });
49
47
 
50
48
  const { refresh, deliveryTime, isCheckoutEnabled } = useShopBiteConfig();
@@ -30,15 +30,18 @@ describe("useTopSellers", () => {
30
30
  const { loadTopSellers } = useTopSellers();
31
31
  const result = await loadTopSellers();
32
32
 
33
- expect(mockInvoke).toHaveBeenCalledWith("getTopSellers post /product", expect.any(Object));
33
+ expect(mockInvoke).toHaveBeenCalledWith(
34
+ "getTopSellers post /product",
35
+ expect.any(Object),
36
+ );
34
37
  expect(result).toEqual(mockElements);
35
38
  });
36
39
 
37
40
  it("should return empty array on error", async () => {
38
41
  mockInvoke.mockRejectedValue(new Error("Network error"));
39
-
42
+
40
43
  // Silence console.error for this test
41
- const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
44
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
42
45
 
43
46
  const { loadTopSellers } = useTopSellers();
44
47
  const result = await loadTopSellers();
@@ -2,7 +2,6 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
2
2
  import { mockNuxtImport } from "@nuxt/test-utils/runtime";
3
3
  import { useWishlistActions } from "../../app/composables/useWishlistActions";
4
4
 
5
-
6
5
  const {
7
6
  mockAddProducts,
8
7
  mockRefreshCart,
@@ -53,7 +52,9 @@ describe("useWishlistActions", () => {
53
52
  const { clearWishlistHandler, isLoading } = useWishlistActions();
54
53
  await clearWishlistHandler();
55
54
  expect(mockClearWishlist).toHaveBeenCalled();
56
- expect(mockToastAdd).toHaveBeenCalledWith(expect.objectContaining({ title: "Merkliste geleert" }));
55
+ expect(mockToastAdd).toHaveBeenCalledWith(
56
+ expect.objectContaining({ title: "Merkliste geleert" }),
57
+ );
57
58
  expect(isLoading.value).toBe(false);
58
59
  });
59
60
 
@@ -63,11 +64,18 @@ describe("useWishlistActions", () => {
63
64
 
64
65
  await addSingleItemToCart(mockProduct);
65
66
 
66
- expect(mockAddProducts).toHaveBeenCalledWith([{ id: "prod-1", quantity: 1, type: "product" }]);
67
+ expect(mockAddProducts).toHaveBeenCalledWith([
68
+ { id: "prod-1", quantity: 1, type: "product" },
69
+ ]);
67
70
  expect(mockRefreshCart).toHaveBeenCalled();
68
71
  expect(mockTriggerProductAdded).toHaveBeenCalled();
69
- expect(mockToastAdd).toHaveBeenCalledWith(expect.objectContaining({ title: "In den Warenkorb gelegt" }));
70
- expect(mockTrackEvent).toHaveBeenCalledWith("add_to_cart", expect.any(Object));
72
+ expect(mockToastAdd).toHaveBeenCalledWith(
73
+ expect.objectContaining({ title: "In den Warenkorb gelegt" }),
74
+ );
75
+ expect(mockTrackEvent).toHaveBeenCalledWith(
76
+ "add_to_cart",
77
+ expect.any(Object),
78
+ );
71
79
  });
72
80
 
73
81
  it("should warn when adding a base product with variants", async () => {
@@ -77,7 +85,9 @@ describe("useWishlistActions", () => {
77
85
  await addSingleItemToCart(baseProduct);
78
86
 
79
87
  expect(mockAddProducts).not.toHaveBeenCalled();
80
- expect(mockToastAdd).toHaveBeenCalledWith(expect.objectContaining({ title: "Variante erforderlich" }));
88
+ expect(mockToastAdd).toHaveBeenCalledWith(
89
+ expect.objectContaining({ title: "Variante erforderlich" }),
90
+ );
81
91
  });
82
92
 
83
93
  it("should add all items to cart", async () => {
@@ -94,7 +104,9 @@ describe("useWishlistActions", () => {
94
104
  { id: "p1", quantity: 1, type: "product" },
95
105
  { id: "p2", quantity: 1, type: "product" },
96
106
  ]);
97
- expect(mockToastAdd).toHaveBeenCalledWith(expect.objectContaining({ title: "Produkte hinzugefügt" }));
107
+ expect(mockToastAdd).toHaveBeenCalledWith(
108
+ expect.objectContaining({ title: "Produkte hinzugefügt" }),
109
+ );
98
110
  expect(isAddingToCart.value).toBe(false);
99
111
  });
100
112
 
@@ -117,8 +129,12 @@ describe("useWishlistActions", () => {
117
129
  expect(mockAddProducts).toHaveBeenCalledWith([
118
130
  { id: "p1", quantity: 1, type: "product" },
119
131
  ]);
120
- expect(mockToastAdd).toHaveBeenCalledWith(expect.objectContaining({
121
- description: expect.stringContaining("1 Produkte hinzugefügt. 1 Produkt(e) übersprungen")
122
- }));
132
+ expect(mockToastAdd).toHaveBeenCalledWith(
133
+ expect.objectContaining({
134
+ description: expect.stringContaining(
135
+ "1 Produkte hinzugefügt. 1 Produkt(e) übersprungen",
136
+ ),
137
+ }),
138
+ );
123
139
  });
124
140
  });
@@ -1,119 +0,0 @@
1
- import { setTime } from "./time";
2
- import { isClosedHoliday } from "~/utils/holidays";
3
-
4
- export type ServiceInterval = { start: Date; end: Date };
5
-
6
- export function isTuesday(date: Date): boolean {
7
- return date.getDay() === 2;
8
- }
9
-
10
- export function isSaturday(date: Date): boolean {
11
- return date.getDay() === 6;
12
- }
13
-
14
- export function getServiceIntervals(date: Date): Array<ServiceInterval> {
15
- if (isTuesday(date)) return [];
16
-
17
- const lunchStart = setTime(date, 11, 30);
18
- const lunchEnd = setTime(date, 14, 30);
19
- const dinnerStart = setTime(date, 17, 30);
20
- const dinnerEnd = isSaturday(date)
21
- ? setTime(date, 23, 30)
22
- : setTime(date, 23, 0);
23
-
24
- if (isSaturday(date)) {
25
- // Saturday: only dinner, no lunch
26
- return [{ start: dinnerStart, end: dinnerEnd }];
27
- }
28
-
29
- return [
30
- { start: lunchStart, end: lunchEnd },
31
- { start: dinnerStart, end: dinnerEnd },
32
- ];
33
- }
34
-
35
- export function getEarliestSelectableTime(
36
- currentTime: Date,
37
- currentDeliveryTime: number | null,
38
- ): Date {
39
- const earliest = new Date(currentTime);
40
- earliest.setMinutes(earliest.getMinutes() + (currentDeliveryTime ?? 30));
41
- earliest.setSeconds(0, 0);
42
- return earliest;
43
- }
44
-
45
- export function getNextOpeningTime(now: Ref<Date>): string | null {
46
- const currentDate = now.value;
47
-
48
- // Check if closed for holiday
49
- if (isClosedHoliday(currentDate)) {
50
- return "13.08."; // Based on your existing code
51
- }
52
-
53
- // Check today's intervals
54
- const todayIntervals = getServiceIntervals(currentDate);
55
- const currentTime = currentDate.getTime();
56
-
57
- // Find next opening today
58
- for (const interval of todayIntervals) {
59
- if (interval.start.getTime() > currentTime) {
60
- const hours = interval.start.getHours().toString().padStart(2, "0");
61
- const minutes = interval.start.getMinutes().toString().padStart(2, "0");
62
- return `${hours}:${minutes} Uhr`;
63
- }
64
- }
65
-
66
- // Check tomorrow
67
- const tomorrow = new Date(currentDate);
68
- tomorrow.setDate(tomorrow.getDate() + 1);
69
- tomorrow.setHours(0, 0, 0, 0);
70
-
71
- // Try up to 7 days ahead to find next opening
72
- for (let i = 0; i < 7; i++) {
73
- const checkDate = new Date(tomorrow);
74
- checkDate.setDate(checkDate.getDate() + i);
75
-
76
- const intervals = getServiceIntervals(checkDate);
77
- if (intervals.length > 0) {
78
- const nextOpen = intervals[0].start;
79
- const dayName = [
80
- "Sonntag",
81
- "Montag",
82
- "Dienstag",
83
- "Mittwoch",
84
- "Donnerstag",
85
- "Freitag",
86
- "Samstag",
87
- ][nextOpen.getDay()];
88
- const hours = nextOpen.getHours().toString().padStart(2, "0");
89
- const minutes = nextOpen.getMinutes().toString().padStart(2, "0");
90
-
91
- if (i === 0) {
92
- return `morgen um ${hours}:${minutes} Uhr`;
93
- }
94
- return `${dayName} um ${hours}:${minutes} Uhr`;
95
- }
96
- }
97
-
98
- return null;
99
- }
100
-
101
- export function findActiveInterval(
102
- currentTime: Date,
103
- currentDeliveryTime: number | null,
104
- ): ServiceInterval | null {
105
- const intervals = getServiceIntervals(currentTime);
106
- const earliest = getEarliestSelectableTime(
107
- currentTime,
108
- currentDeliveryTime ?? 30,
109
- );
110
-
111
- if (intervals.length === 0) return null;
112
-
113
- const current = intervals.find(
114
- (interval) => earliest >= interval.start && earliest <= interval.end,
115
- );
116
- if (current) return current;
117
-
118
- return intervals.find((interval) => interval.start > earliest) ?? null;
119
- }
@@ -1,43 +0,0 @@
1
- export function isClosedHoliday(date: Date): boolean {
2
- // Format date as YYYY-MM-DD for comparison
3
- const formattedDate = formatDateYYYYMMDD(date);
4
-
5
- // List of holidays (YYYY-MM-DD format)
6
- const holidays = [
7
- "2025-07-21",
8
- "2025-07-22",
9
- "2025-07-23",
10
- "2025-07-24",
11
- "2025-07-25",
12
- "2025-07-26",
13
- "2025-07-27",
14
- "2025-07-28",
15
- "2025-07-29",
16
- "2025-07-30",
17
- "2025-07-31",
18
- "2025-08-01",
19
- "2025-08-02",
20
- "2025-08-03",
21
- "2025-08-04",
22
- "2025-08-05",
23
- "2025-08-06",
24
- "2025-08-07",
25
- "2025-08-08",
26
- "2025-08-09",
27
- ];
28
-
29
- return holidays.includes(formattedDate);
30
- }
31
-
32
- /**
33
- * Formats a date as YYYY-MM-DD
34
- * @param date The date to format
35
- * @returns The formatted date string
36
- */
37
- function formatDateYYYYMMDD(date: Date): string {
38
- const year = date.getFullYear();
39
- const month = String(date.getMonth() + 1).padStart(2, "0");
40
- const day = String(date.getDate()).padStart(2, "0");
41
-
42
- return `${year}-${month}-${day}`;
43
- }
@@ -1,8 +0,0 @@
1
- // utils/storeHours.ts
2
- import { getServiceIntervals } from "~/utils/businessHours";
3
-
4
- export function isStoreOpen(date: Date = new Date()): boolean {
5
- const intervals = getServiceIntervals(date);
6
- if (intervals.length === 0) return false;
7
- return intervals.some(({ start, end }) => date >= start && date <= end);
8
- }