@happychef/algorithm 1.2.13 → 1.2.15

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.
@@ -1,247 +1,247 @@
1
- const {
2
- parseTime,
3
- getMealTypeByTime,
4
- getAllTables,
5
- isTemporaryTableValid,
6
- shifts
7
- } = require('../tableHelpers');
8
-
9
- describe('tableHelpers - parseTime', () => {
10
- test('should parse valid time string correctly', () => {
11
- expect(parseTime('12:30')).toBe(750); // 12*60 + 30 = 750
12
- expect(parseTime('00:00')).toBe(0);
13
- expect(parseTime('23:59')).toBe(1439);
14
- });
15
-
16
- test('should return NaN for invalid time strings', () => {
17
- expect(parseTime('')).toBeNaN();
18
- expect(parseTime(null)).toBeNaN();
19
- expect(parseTime(undefined)).toBeNaN();
20
- expect(parseTime('25:00')).toBeNaN(); // Invalid hour
21
- expect(parseTime('12:60')).toBeNaN(); // Invalid minute
22
- expect(parseTime('12')).toBeNaN(); // Missing colon
23
- expect(parseTime('ab:cd')).toBeNaN(); // Not numbers
24
- });
25
-
26
- test('should handle edge cases', () => {
27
- expect(parseTime('0:0')).toBe(0);
28
- expect(parseTime('1:1')).toBe(61);
29
- });
30
- });
31
-
32
- describe('tableHelpers - getMealTypeByTime', () => {
33
- test('should identify breakfast times correctly', () => {
34
- expect(getMealTypeByTime('07:00')).toBe('breakfast');
35
- expect(getMealTypeByTime('09:30')).toBe('breakfast');
36
- expect(getMealTypeByTime('10:59')).toBe('breakfast');
37
- });
38
-
39
- test('should identify lunch times correctly', () => {
40
- expect(getMealTypeByTime('11:00')).toBe('lunch');
41
- expect(getMealTypeByTime('12:30')).toBe('lunch');
42
- expect(getMealTypeByTime('15:59')).toBe('lunch');
43
- });
44
-
45
- test('should identify dinner times correctly', () => {
46
- expect(getMealTypeByTime('16:00')).toBe('dinner');
47
- expect(getMealTypeByTime('18:30')).toBe('dinner');
48
- expect(getMealTypeByTime('22:59')).toBe('dinner');
49
- });
50
-
51
- test('should return null for times outside defined shifts', () => {
52
- expect(getMealTypeByTime('06:59')).toBeNull();
53
- expect(getMealTypeByTime('23:00')).toBeNull();
54
- expect(getMealTypeByTime('02:00')).toBeNull();
55
- });
56
-
57
- test('should return null for invalid time strings', () => {
58
- expect(getMealTypeByTime('invalid')).toBeNull();
59
- expect(getMealTypeByTime('')).toBeNull();
60
- expect(getMealTypeByTime(null)).toBeNull();
61
- });
62
- });
63
-
64
- describe('tableHelpers - getAllTables', () => {
65
- test('should extract tables correctly from restaurant data', () => {
66
- const restaurantData = {
67
- floors: [
68
- {
69
- tables: [
70
- {
71
- objectType: 'Tafel',
72
- id: 'table1',
73
- tableNumber: 1,
74
- minCapacity: 2,
75
- maxCapacity: 4,
76
- priority: 1,
77
- x: 10,
78
- y: 20,
79
- isTemporary: false
80
- },
81
- {
82
- objectType: 'Tafel',
83
- id: 'table2',
84
- tableNumber: { $numberInt: '2' },
85
- minCapacity: { $numberInt: '4' },
86
- maxCapacity: { $numberInt: '6' },
87
- priority: { $numberInt: '2' },
88
- x: { $numberInt: '30' },
89
- y: { $numberInt: '40' },
90
- isTemporary: false
91
- }
92
- ]
93
- }
94
- ]
95
- };
96
-
97
- const tables = getAllTables(restaurantData);
98
- expect(tables).toHaveLength(2);
99
- expect(tables[0].tableNumber).toBe(1);
100
- expect(tables[0].maxCapacity).toBe(4);
101
- expect(tables[1].tableNumber).toBe(2);
102
- expect(tables[1].maxCapacity).toBe(6);
103
- });
104
-
105
- test('should sort tables by maxCapacity, priority, and minCapacity', () => {
106
- const restaurantData = {
107
- floors: [
108
- {
109
- tables: [
110
- {
111
- objectType: 'Tafel',
112
- id: 'table1',
113
- tableNumber: 1,
114
- minCapacity: 2,
115
- maxCapacity: 6,
116
- priority: 1,
117
- x: 10,
118
- y: 20
119
- },
120
- {
121
- objectType: 'Tafel',
122
- id: 'table2',
123
- tableNumber: 2,
124
- minCapacity: 2,
125
- maxCapacity: 4,
126
- priority: 1,
127
- x: 30,
128
- y: 40
129
- }
130
- ]
131
- }
132
- ]
133
- };
134
-
135
- const tables = getAllTables(restaurantData);
136
- expect(tables[0].tableNumber).toBe(2); // Smaller maxCapacity comes first
137
- expect(tables[1].tableNumber).toBe(1);
138
- });
139
-
140
- test('should handle empty or missing data gracefully', () => {
141
- expect(getAllTables({})).toEqual([]);
142
- expect(getAllTables({ floors: [] })).toEqual([]);
143
- expect(getAllTables(null)).toEqual([]);
144
- });
145
-
146
- test('should filter out non-Tafel objects', () => {
147
- const restaurantData = {
148
- floors: [
149
- {
150
- tables: [
151
- {
152
- objectType: 'Wall',
153
- id: 'wall1',
154
- tableNumber: 1
155
- },
156
- {
157
- objectType: 'Tafel',
158
- id: 'table1',
159
- tableNumber: 2,
160
- minCapacity: 2,
161
- maxCapacity: 4,
162
- priority: 1,
163
- x: 10,
164
- y: 20
165
- }
166
- ]
167
- }
168
- ]
169
- };
170
-
171
- const tables = getAllTables(restaurantData);
172
- expect(tables).toHaveLength(1);
173
- expect(tables[0].tableNumber).toBe(2);
174
- });
175
- });
176
-
177
- describe('tableHelpers - isTemporaryTableValid', () => {
178
- test('should return true for non-temporary tables', () => {
179
- const table = {
180
- tableNumber: 1,
181
- isTemporary: false
182
- };
183
- expect(isTemporaryTableValid(table, '2025-06-15', '12:00')).toBe(true);
184
- });
185
-
186
- test('should validate temporary table within date range and correct meal type', () => {
187
- const table = {
188
- tableNumber: 1,
189
- isTemporary: true,
190
- startDate: '2025-06-01',
191
- endDate: '2025-06-30',
192
- application: 'lunch'
193
- };
194
- expect(isTemporaryTableValid(table, '2025-06-15', '12:00')).toBe(true);
195
- });
196
-
197
- test('should reject temporary table outside date range', () => {
198
- const table = {
199
- tableNumber: 1,
200
- isTemporary: true,
201
- startDate: '2025-06-01',
202
- endDate: '2025-06-30',
203
- application: 'lunch'
204
- };
205
- expect(isTemporaryTableValid(table, '2025-07-01', '12:00')).toBe(false);
206
- expect(isTemporaryTableValid(table, '2025-05-31', '12:00')).toBe(false);
207
- });
208
-
209
- test('should reject temporary table with wrong meal type', () => {
210
- const table = {
211
- tableNumber: 1,
212
- isTemporary: true,
213
- startDate: '2025-06-01',
214
- endDate: '2025-06-30',
215
- application: 'dinner'
216
- };
217
- expect(isTemporaryTableValid(table, '2025-06-15', '12:00')).toBe(false); // lunch time
218
- });
219
-
220
- test('should reject temporary table with missing date range', () => {
221
- const table = {
222
- tableNumber: 1,
223
- isTemporary: true,
224
- application: 'lunch'
225
- };
226
- expect(isTemporaryTableValid(table, '2025-06-15', '12:00')).toBe(false);
227
- });
228
-
229
- test('should reject temporary table with invalid time', () => {
230
- const table = {
231
- tableNumber: 1,
232
- isTemporary: true,
233
- startDate: '2025-06-01',
234
- endDate: '2025-06-30',
235
- application: 'lunch'
236
- };
237
- expect(isTemporaryTableValid(table, '2025-06-15', 'invalid')).toBe(false);
238
- });
239
- });
240
-
241
- describe('tableHelpers - shifts constant', () => {
242
- test('should have correct shift definitions', () => {
243
- expect(shifts.breakfast).toEqual({ start: '07:00', end: '11:00' });
244
- expect(shifts.lunch).toEqual({ start: '11:00', end: '16:00' });
245
- expect(shifts.dinner).toEqual({ start: '16:00', end: '23:00' });
246
- });
247
- });
1
+ const {
2
+ parseTime,
3
+ getMealTypeByTime,
4
+ getAllTables,
5
+ isTemporaryTableValid,
6
+ shifts
7
+ } = require('../tableHelpers');
8
+
9
+ describe('tableHelpers - parseTime', () => {
10
+ test('should parse valid time string correctly', () => {
11
+ expect(parseTime('12:30')).toBe(750); // 12*60 + 30 = 750
12
+ expect(parseTime('00:00')).toBe(0);
13
+ expect(parseTime('23:59')).toBe(1439);
14
+ });
15
+
16
+ test('should return NaN for invalid time strings', () => {
17
+ expect(parseTime('')).toBeNaN();
18
+ expect(parseTime(null)).toBeNaN();
19
+ expect(parseTime(undefined)).toBeNaN();
20
+ expect(parseTime('25:00')).toBeNaN(); // Invalid hour
21
+ expect(parseTime('12:60')).toBeNaN(); // Invalid minute
22
+ expect(parseTime('12')).toBeNaN(); // Missing colon
23
+ expect(parseTime('ab:cd')).toBeNaN(); // Not numbers
24
+ });
25
+
26
+ test('should handle edge cases', () => {
27
+ expect(parseTime('0:0')).toBe(0);
28
+ expect(parseTime('1:1')).toBe(61);
29
+ });
30
+ });
31
+
32
+ describe('tableHelpers - getMealTypeByTime', () => {
33
+ test('should identify breakfast times correctly', () => {
34
+ expect(getMealTypeByTime('07:00')).toBe('breakfast');
35
+ expect(getMealTypeByTime('09:30')).toBe('breakfast');
36
+ expect(getMealTypeByTime('10:59')).toBe('breakfast');
37
+ });
38
+
39
+ test('should identify lunch times correctly', () => {
40
+ expect(getMealTypeByTime('11:00')).toBe('lunch');
41
+ expect(getMealTypeByTime('12:30')).toBe('lunch');
42
+ expect(getMealTypeByTime('15:59')).toBe('lunch');
43
+ });
44
+
45
+ test('should identify dinner times correctly', () => {
46
+ expect(getMealTypeByTime('16:00')).toBe('dinner');
47
+ expect(getMealTypeByTime('18:30')).toBe('dinner');
48
+ expect(getMealTypeByTime('22:59')).toBe('dinner');
49
+ });
50
+
51
+ test('should return null for times outside defined shifts', () => {
52
+ expect(getMealTypeByTime('06:59')).toBeNull();
53
+ expect(getMealTypeByTime('23:00')).toBeNull();
54
+ expect(getMealTypeByTime('02:00')).toBeNull();
55
+ });
56
+
57
+ test('should return null for invalid time strings', () => {
58
+ expect(getMealTypeByTime('invalid')).toBeNull();
59
+ expect(getMealTypeByTime('')).toBeNull();
60
+ expect(getMealTypeByTime(null)).toBeNull();
61
+ });
62
+ });
63
+
64
+ describe('tableHelpers - getAllTables', () => {
65
+ test('should extract tables correctly from restaurant data', () => {
66
+ const restaurantData = {
67
+ floors: [
68
+ {
69
+ tables: [
70
+ {
71
+ objectType: 'Tafel',
72
+ id: 'table1',
73
+ tableNumber: 1,
74
+ minCapacity: 2,
75
+ maxCapacity: 4,
76
+ priority: 1,
77
+ x: 10,
78
+ y: 20,
79
+ isTemporary: false
80
+ },
81
+ {
82
+ objectType: 'Tafel',
83
+ id: 'table2',
84
+ tableNumber: { $numberInt: '2' },
85
+ minCapacity: { $numberInt: '4' },
86
+ maxCapacity: { $numberInt: '6' },
87
+ priority: { $numberInt: '2' },
88
+ x: { $numberInt: '30' },
89
+ y: { $numberInt: '40' },
90
+ isTemporary: false
91
+ }
92
+ ]
93
+ }
94
+ ]
95
+ };
96
+
97
+ const tables = getAllTables(restaurantData);
98
+ expect(tables).toHaveLength(2);
99
+ expect(tables[0].tableNumber).toBe(1);
100
+ expect(tables[0].maxCapacity).toBe(4);
101
+ expect(tables[1].tableNumber).toBe(2);
102
+ expect(tables[1].maxCapacity).toBe(6);
103
+ });
104
+
105
+ test('should sort tables by maxCapacity, priority, and minCapacity', () => {
106
+ const restaurantData = {
107
+ floors: [
108
+ {
109
+ tables: [
110
+ {
111
+ objectType: 'Tafel',
112
+ id: 'table1',
113
+ tableNumber: 1,
114
+ minCapacity: 2,
115
+ maxCapacity: 6,
116
+ priority: 1,
117
+ x: 10,
118
+ y: 20
119
+ },
120
+ {
121
+ objectType: 'Tafel',
122
+ id: 'table2',
123
+ tableNumber: 2,
124
+ minCapacity: 2,
125
+ maxCapacity: 4,
126
+ priority: 1,
127
+ x: 30,
128
+ y: 40
129
+ }
130
+ ]
131
+ }
132
+ ]
133
+ };
134
+
135
+ const tables = getAllTables(restaurantData);
136
+ expect(tables[0].tableNumber).toBe(2); // Smaller maxCapacity comes first
137
+ expect(tables[1].tableNumber).toBe(1);
138
+ });
139
+
140
+ test('should handle empty or missing data gracefully', () => {
141
+ expect(getAllTables({})).toEqual([]);
142
+ expect(getAllTables({ floors: [] })).toEqual([]);
143
+ expect(getAllTables(null)).toEqual([]);
144
+ });
145
+
146
+ test('should filter out non-Tafel objects', () => {
147
+ const restaurantData = {
148
+ floors: [
149
+ {
150
+ tables: [
151
+ {
152
+ objectType: 'Wall',
153
+ id: 'wall1',
154
+ tableNumber: 1
155
+ },
156
+ {
157
+ objectType: 'Tafel',
158
+ id: 'table1',
159
+ tableNumber: 2,
160
+ minCapacity: 2,
161
+ maxCapacity: 4,
162
+ priority: 1,
163
+ x: 10,
164
+ y: 20
165
+ }
166
+ ]
167
+ }
168
+ ]
169
+ };
170
+
171
+ const tables = getAllTables(restaurantData);
172
+ expect(tables).toHaveLength(1);
173
+ expect(tables[0].tableNumber).toBe(2);
174
+ });
175
+ });
176
+
177
+ describe('tableHelpers - isTemporaryTableValid', () => {
178
+ test('should return true for non-temporary tables', () => {
179
+ const table = {
180
+ tableNumber: 1,
181
+ isTemporary: false
182
+ };
183
+ expect(isTemporaryTableValid(table, '2025-06-15', '12:00')).toBe(true);
184
+ });
185
+
186
+ test('should validate temporary table within date range and correct meal type', () => {
187
+ const table = {
188
+ tableNumber: 1,
189
+ isTemporary: true,
190
+ startDate: '2025-06-01',
191
+ endDate: '2025-06-30',
192
+ application: 'lunch'
193
+ };
194
+ expect(isTemporaryTableValid(table, '2025-06-15', '12:00')).toBe(true);
195
+ });
196
+
197
+ test('should reject temporary table outside date range', () => {
198
+ const table = {
199
+ tableNumber: 1,
200
+ isTemporary: true,
201
+ startDate: '2025-06-01',
202
+ endDate: '2025-06-30',
203
+ application: 'lunch'
204
+ };
205
+ expect(isTemporaryTableValid(table, '2025-07-01', '12:00')).toBe(false);
206
+ expect(isTemporaryTableValid(table, '2025-05-31', '12:00')).toBe(false);
207
+ });
208
+
209
+ test('should reject temporary table with wrong meal type', () => {
210
+ const table = {
211
+ tableNumber: 1,
212
+ isTemporary: true,
213
+ startDate: '2025-06-01',
214
+ endDate: '2025-06-30',
215
+ application: 'dinner'
216
+ };
217
+ expect(isTemporaryTableValid(table, '2025-06-15', '12:00')).toBe(false); // lunch time
218
+ });
219
+
220
+ test('should reject temporary table with missing date range', () => {
221
+ const table = {
222
+ tableNumber: 1,
223
+ isTemporary: true,
224
+ application: 'lunch'
225
+ };
226
+ expect(isTemporaryTableValid(table, '2025-06-15', '12:00')).toBe(false);
227
+ });
228
+
229
+ test('should reject temporary table with invalid time', () => {
230
+ const table = {
231
+ tableNumber: 1,
232
+ isTemporary: true,
233
+ startDate: '2025-06-01',
234
+ endDate: '2025-06-30',
235
+ application: 'lunch'
236
+ };
237
+ expect(isTemporaryTableValid(table, '2025-06-15', 'invalid')).toBe(false);
238
+ });
239
+ });
240
+
241
+ describe('tableHelpers - shifts constant', () => {
242
+ test('should have correct shift definitions', () => {
243
+ expect(shifts.breakfast).toEqual({ start: '07:00', end: '11:00' });
244
+ expect(shifts.lunch).toEqual({ start: '11:00', end: '16:00' });
245
+ expect(shifts.dinner).toEqual({ start: '16:00', end: '23:00' });
246
+ });
247
+ });
package/assignTables.js CHANGED
@@ -299,10 +299,19 @@ async function assignTablesIfPossible({
299
299
  }
300
300
  }
301
301
 
302
- // 5) Get duration and interval settings
303
- const duurReservatie = parseInt(
302
+ // 5) Get duration from reservation or settings
303
+ let duurReservatie = parseInt(
304
304
  restaurantSettings["general-settings"]?.duurReservatie?.$numberInt || restaurantSettings["general-settings"]?.duurReservatie || 120
305
305
  );
306
+ // Use reservation specific duration if provided
307
+ if (reservation.duration) {
308
+ const rawDur = reservation.duration.$numberInt ?? reservation.duration;
309
+ const parsedDur = parseInt(rawDur, 10);
310
+ if (!isNaN(parsedDur) && parsedDur > 0) {
311
+ duurReservatie = parsedDur;
312
+ }
313
+ }
314
+
306
315
  const intervalReservatie = parseInt(
307
316
  restaurantSettings["general-settings"]?.intervalReservatie?.$numberInt || restaurantSettings["general-settings"]?.intervalReservatie || 30
308
317
  );
@@ -322,7 +331,17 @@ async function assignTablesIfPossible({
322
331
  // No need to skip the current reservation as it's not yet inserted
323
332
 
324
333
  // compute that reservation's time slots
325
- const rDuration = duurReservatie; // assuming same duration
334
+ // Use reservation specific duration if available, else default
335
+ let rDuration = duurReservatie;
336
+ if (r.duration) {
337
+ // Handle both direct value and MongoDB $numberInt
338
+ // Use ?? to correctly handle 0 values
339
+ const rawDur = r.duration.$numberInt ?? r.duration;
340
+ const parsed = parseInt(rawDur, 10);
341
+ if (!isNaN(parsed) && parsed > 0) {
342
+ rDuration = parsed;
343
+ }
344
+ }
326
345
  const rSlots = computeRequiredSlots(r.time, rDuration, intervalReservatie);
327
346
 
328
347
  if (r.tables) {
@@ -397,18 +416,19 @@ async function assignTablesIfPossible({
397
416
  return false;
398
417
  }
399
418
 
400
- // 11) Try preferred floor first (if specified), then fall back to all floors
419
+ // 11) If a linked floor is specified for the Zitplaats, ONLY use that floor (no fallback)
401
420
  if (preferredFloorTables && preferredFloorTables.length > 0) {
402
- console.log(`[Zitplaats] Trying preferred floor first (${preferredFloorTables.length} tables)`);
403
- if (tryAssignTables(preferredFloorTables, 'PreferredFloor')) {
404
- return; // Success on preferred floor
421
+ console.log(`[Zitplaats] Trying linked floor only (${preferredFloorTables.length} tables)`);
422
+ if (tryAssignTables(preferredFloorTables, 'LinkedFloor')) {
423
+ return; // Success on linked floor
424
+ }
425
+ console.log(`[Zitplaats] No availability on linked floor - not falling back to other floors`);
426
+ // Do NOT fall back to all floors when a floor link is specified
427
+ } else {
428
+ // 12) Try all floors only when no floor link is specified
429
+ if (tryAssignTables(allTables, 'AllFloors')) {
430
+ return; // Success
405
431
  }
406
- console.log(`[Zitplaats] No availability on preferred floor, falling back to all floors`);
407
- }
408
-
409
- // 12) Try all floors
410
- if (tryAssignTables(allTables, 'AllFloors')) {
411
- return; // Success
412
432
  }
413
433
 
414
434
  // 13) No valid table combo found
@@ -0,0 +1,20 @@
1
+ # PR 11 - Duration
2
+
3
+ **Actions:**
4
+
5
+ ## Changes Summary
6
+ ADDED:
7
+ - New function `duration(start, end)` added to calculate the time difference between two datetime strings.
8
+ - New import `datetime` from the `datetime` module to support date and time operations.
9
+
10
+ NO_REMOVALS
11
+
12
+ CHANGED:
13
+ - Modified the `getAvailableTimeblocks` function to change the calculation of `uurOpVoorhand` from `4` to `0`, affecting the time window for available timeblocks.
14
+ - Updated the `getAvailableTimeblocks` function to adjust the `duration` parameter handling, now using `duration` directly instead of a hardcoded value, impacting the timeblock duration logic.
15
+
16
+ ---
17
+
18
+ **Author:** Fakhar-Rashid
19
+ **Date:** 2026-01-13
20
+ **PR Link:** https://github.com/thibaultvandesompele2/15-happy-algorithm/pull/11
@@ -30,7 +30,7 @@ function parseDateTimeInTimeZone(dateStr, timeStr, timeZone) {
30
30
  * @param {boolean} isAdmin - Optional flag to bypass time restrictions for admin users.
31
31
  * @returns {Object} - Returns a pruned object of available time blocks or shifts, or an empty object if out of range.
32
32
  */
33
- function getAvailableTimeblocks(data, dateStr, reservations, guests, blockedSlots = [], giftcard = null, isAdmin = false) {
33
+ function getAvailableTimeblocks(data, dateStr, reservations, guests, blockedSlots = [], giftcard = null, isAdmin = false, duration = null) {
34
34
  // Get 'uurOpVoorhand' from general settings
35
35
  let uurOpVoorhand = 0;
36
36
  if (
@@ -79,7 +79,7 @@ function getAvailableTimeblocks(data, dateStr, reservations, guests, blockedSlot
79
79
  currentTimeInTimeZone.toDateString() === targetDateInTimeZone.toDateString();
80
80
 
81
81
  // Get available time blocks or shifts
82
- const availableTimeblocks = timeblocksAvailable(data, dateStr, reservations, guests, blockedSlots, giftcard, isAdmin);
82
+ const availableTimeblocks = timeblocksAvailable(data, dateStr, reservations, guests, blockedSlots, giftcard, isAdmin, duration);
83
83
 
84
84
  // If the date is today and uurOpVoorhand is greater than zero, prune time blocks (skip for admin)
85
85
  if (!isAdmin && isToday && uurOpVoorhand >= 0) {
@@ -62,14 +62,14 @@ function isDateWithinAllowedRange(data, dateStr) {
62
62
  * @param {boolean} isAdmin - Optional flag to bypass time restrictions for admin users.
63
63
  * @returns {boolean} - Returns true if the date has at least one available timeblock, false otherwise.
64
64
  */
65
- function isDateAvailable(data, dateStr, reservations, guests, blockedSlots = [], giftcard = null, isAdmin = false) {
65
+ function isDateAvailable(data, dateStr, reservations, guests, blockedSlots = [], giftcard = null, isAdmin = false, duration = null) {
66
66
  // Check if date is within allowed range (skip for admin)
67
67
  if (!isAdmin && !isDateWithinAllowedRange(data, dateStr)) {
68
68
  return false;
69
69
  }
70
70
 
71
71
  // Get available timeblocks using the existing logic
72
- const availableTimeblocks = getAvailableTimeblocks(data, dateStr, reservations, guests, blockedSlots, giftcard, isAdmin);
72
+ const availableTimeblocks = getAvailableTimeblocks(data, dateStr, reservations, guests, blockedSlots, giftcard, isAdmin, duration);
73
73
 
74
74
  // Return true only if we have at least one available timeblock
75
75
  return Object.keys(availableTimeblocks).length > 0;
@@ -74,7 +74,7 @@ function timeHasGiftcard(data, dateStr, timeStr, giftcard) {
74
74
  * @param {boolean} isAdmin - Optional flag to bypass time restrictions for admin users.
75
75
  * @returns {boolean} - Returns true if the date passes all checks to be available.
76
76
  */
77
- function isDateAvailableWithTableCheck(data, dateStr, reservations, guests, blockedSlots = [], selectedGiftcard = null, isAdmin = false) {
77
+ function isDateAvailableWithTableCheck(data, dateStr, reservations, guests, blockedSlots = [], selectedGiftcard = null, isAdmin = false, duration = null) {
78
78
  // 0) Optionally filter by selected menu item's date range (only when normalOpeningTimes = false)
79
79
  const currentItem = typeof window !== 'undefined' ? window.currentReservationTicketItem : null;
80
80
  if (
@@ -114,7 +114,7 @@ function isDateAvailableWithTableCheck(data, dateStr, reservations, guests, bloc
114
114
  console.log(`Table assignment is ${isTableAssignmentEnabled ? 'ENABLED' : 'DISABLED'} for date ${dateStr}`);
115
115
 
116
116
  // 1) First, do the standard day-level checks (including simple giftcard check).
117
- const basicDateAvailable = isDateAvailable(data, dateStr, reservations, guests, blockedSlots, selectedGiftcard, isAdmin);
117
+ const basicDateAvailable = isDateAvailable(data, dateStr, reservations, guests, blockedSlots, selectedGiftcard, isAdmin, duration);
118
118
  if (!basicDateAvailable) {
119
119
  console.log(`Date ${dateStr} fails basic availability check`);
120
120
  return false;
@@ -128,7 +128,7 @@ function isDateAvailableWithTableCheck(data, dateStr, reservations, guests, bloc
128
128
 
129
129
  // 2) Get all available timeblocks for this date
130
130
  console.log(`Getting available timeblocks for ${dateStr}`);
131
- const availableTimeblocks = getAvailableTimeblocks(data, dateStr, reservations, guests, blockedSlots, selectedGiftcard, isAdmin);
131
+ const availableTimeblocks = getAvailableTimeblocks(data, dateStr, reservations, guests, blockedSlots, selectedGiftcard, isAdmin, duration);
132
132
  console.log(`Found ${Object.keys(availableTimeblocks).length} available timeblocks before table check`);
133
133
 
134
134
  // If no timeblocks are available at all, exit early
@@ -153,7 +153,8 @@ function isDateAvailableWithTableCheck(data, dateStr, reservations, guests, bloc
153
153
  }
154
154
 
155
155
  console.log(`Checking table availability for ${time} on ${dateStr} for ${guests} guests`);
156
- if (isTimeAvailableSync(data, dateStr, time, guests, reservations)) {
156
+ // Pass null for selectedZitplaats, then duration
157
+ if (isTimeAvailableSync(data, dateStr, time, guests, reservations, null, duration)) {
157
158
  console.log(`Found available time ${time} with table assignment!`);
158
159
  atLeastOneAvailable = true;
159
160
  break;