@happychef/algorithm 1.2.24 → 1.2.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/getAvailableTimeblocks.js +49 -6
- package/isDateAvailable.js +42 -5
- package/package.json +1 -1
|
@@ -3,6 +3,42 @@
|
|
|
3
3
|
const { timeblocksAvailable } = require('./processing/timeblocksAvailable');
|
|
4
4
|
const { parseTime, getMealTypeByTime } = require('./tableHelpers');
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Gets the current date/time components in the specified timezone.
|
|
8
|
+
* Uses Intl.DateTimeFormat for reliable cross-browser timezone conversion.
|
|
9
|
+
* @param {Date} date - The date to convert.
|
|
10
|
+
* @param {string} timeZone - The IANA timezone identifier.
|
|
11
|
+
* @returns {Object} Object with year, month, day, hour, minute, second components.
|
|
12
|
+
*/
|
|
13
|
+
function getDatePartsInTimeZone(date, timeZone) {
|
|
14
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
15
|
+
timeZone,
|
|
16
|
+
year: 'numeric',
|
|
17
|
+
month: '2-digit',
|
|
18
|
+
day: '2-digit',
|
|
19
|
+
hour: '2-digit',
|
|
20
|
+
minute: '2-digit',
|
|
21
|
+
second: '2-digit',
|
|
22
|
+
hourCycle: 'h23', // Use 'h23' instead of hour12:false for consistent 0-23 range
|
|
23
|
+
});
|
|
24
|
+
const parts = formatter.formatToParts(date);
|
|
25
|
+
const values = {};
|
|
26
|
+
for (const part of parts) {
|
|
27
|
+
values[part.type] = part.value;
|
|
28
|
+
}
|
|
29
|
+
// Handle edge case: Chrome may return "24" for midnight with some hourCycle settings
|
|
30
|
+
let hour = parseInt(values.hour, 10);
|
|
31
|
+
if (hour === 24) hour = 0;
|
|
32
|
+
return {
|
|
33
|
+
year: parseInt(values.year, 10),
|
|
34
|
+
month: parseInt(values.month, 10),
|
|
35
|
+
day: parseInt(values.day, 10),
|
|
36
|
+
hour: hour,
|
|
37
|
+
minute: parseInt(values.minute, 10),
|
|
38
|
+
second: parseInt(values.second, 10),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
6
42
|
/**
|
|
7
43
|
* Parses a time string in "HH:MM" format into a Date object on a specific date.
|
|
8
44
|
* @param {string} dateStr - The date string in "YYYY-MM-DD" format.
|
|
@@ -54,10 +90,13 @@ function getAvailableTimeblocks(data, dateStr, reservations, guests, blockedSlot
|
|
|
54
90
|
// Time zone for CEST/CET (Europe/Amsterdam)
|
|
55
91
|
const timeZone = 'Europe/Amsterdam';
|
|
56
92
|
|
|
57
|
-
//
|
|
58
|
-
// Note: We assume the server is running in the correct timezone
|
|
93
|
+
// Get current time in target timezone using reliable cross-browser method
|
|
59
94
|
const now = new Date();
|
|
60
|
-
const
|
|
95
|
+
const nowParts = getDatePartsInTimeZone(now, timeZone);
|
|
96
|
+
const currentTimeInTimeZone = new Date(
|
|
97
|
+
nowParts.year, nowParts.month - 1, nowParts.day,
|
|
98
|
+
nowParts.hour, nowParts.minute, nowParts.second
|
|
99
|
+
);
|
|
61
100
|
|
|
62
101
|
// Calculate the maximum allowed date
|
|
63
102
|
const maxAllowedDate = new Date(currentTimeInTimeZone.getTime());
|
|
@@ -75,8 +114,9 @@ function getAvailableTimeblocks(data, dateStr, reservations, guests, blockedSlot
|
|
|
75
114
|
}
|
|
76
115
|
|
|
77
116
|
// Check if the target date is today in the specified time zone
|
|
117
|
+
// Compare year, month, day components to determine if it's today
|
|
78
118
|
const isToday =
|
|
79
|
-
|
|
119
|
+
nowParts.year === year && nowParts.month === month && nowParts.day === day;
|
|
80
120
|
|
|
81
121
|
// Get available time blocks or shifts
|
|
82
122
|
const availableTimeblocks = timeblocksAvailable(data, dateStr, reservations, guests, blockedSlots, giftcard, isAdmin, duration);
|
|
@@ -115,11 +155,14 @@ function getAvailableTimeblocks(data, dateStr, reservations, guests, blockedSlot
|
|
|
115
155
|
timeZone: 'Europe/Brussels',
|
|
116
156
|
hour: '2-digit',
|
|
117
157
|
minute: '2-digit',
|
|
118
|
-
|
|
158
|
+
hourCycle: 'h23', // Use 'h23' for consistent 0-23 hour range across browsers
|
|
119
159
|
});
|
|
120
160
|
const parts = formatter.formatToParts(now);
|
|
121
161
|
const timeParts = Object.fromEntries(parts.map(p => [p.type, p.value]));
|
|
122
|
-
|
|
162
|
+
// Handle edge case: some browsers may return "24" for midnight
|
|
163
|
+
let hourValue = parseInt(timeParts.hour, 10);
|
|
164
|
+
if (hourValue === 24) hourValue = 0;
|
|
165
|
+
const currentTimeMinutes = hourValue * 60 + parseInt(timeParts.minute, 10);
|
|
123
166
|
|
|
124
167
|
// Check if current time has passed any stop times
|
|
125
168
|
const breakfastStopMinutes = breakfastStop ? parseTime(breakfastStop) : null;
|
package/isDateAvailable.js
CHANGED
|
@@ -12,6 +12,42 @@ function parseTime(timeStr) {
|
|
|
12
12
|
return hours * 60 + minutes;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Gets the current date/time components in the specified timezone.
|
|
17
|
+
* Uses Intl.DateTimeFormat for reliable cross-browser timezone conversion.
|
|
18
|
+
* @param {Date} date - The date to convert.
|
|
19
|
+
* @param {string} timeZone - The IANA timezone identifier.
|
|
20
|
+
* @returns {Object} Object with year, month, day, hour, minute, second components.
|
|
21
|
+
*/
|
|
22
|
+
function getDatePartsInTimeZone(date, timeZone) {
|
|
23
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
24
|
+
timeZone,
|
|
25
|
+
year: 'numeric',
|
|
26
|
+
month: '2-digit',
|
|
27
|
+
day: '2-digit',
|
|
28
|
+
hour: '2-digit',
|
|
29
|
+
minute: '2-digit',
|
|
30
|
+
second: '2-digit',
|
|
31
|
+
hourCycle: 'h23', // Use 'h23' instead of hour12:false for consistent 0-23 range
|
|
32
|
+
});
|
|
33
|
+
const parts = formatter.formatToParts(date);
|
|
34
|
+
const values = {};
|
|
35
|
+
for (const part of parts) {
|
|
36
|
+
values[part.type] = part.value;
|
|
37
|
+
}
|
|
38
|
+
// Handle edge case: Chrome may return "24" for midnight with some hourCycle settings
|
|
39
|
+
let hour = parseInt(values.hour, 10);
|
|
40
|
+
if (hour === 24) hour = 0;
|
|
41
|
+
return {
|
|
42
|
+
year: parseInt(values.year, 10),
|
|
43
|
+
month: parseInt(values.month, 10),
|
|
44
|
+
day: parseInt(values.day, 10),
|
|
45
|
+
hour: hour,
|
|
46
|
+
minute: parseInt(values.minute, 10),
|
|
47
|
+
second: parseInt(values.second, 10),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
15
51
|
/**
|
|
16
52
|
* Checks if a date is within the allowed future range defined by dagenInToekomst.
|
|
17
53
|
* @param {Object} data - The main data object (to access general settings).
|
|
@@ -31,20 +67,21 @@ function isDateWithinAllowedRange(data, dateStr) {
|
|
|
31
67
|
|
|
32
68
|
const timeZone = 'Europe/Amsterdam';
|
|
33
69
|
|
|
70
|
+
// Get current time in the target timezone using reliable cross-browser method
|
|
34
71
|
const now = new Date();
|
|
72
|
+
const nowParts = getDatePartsInTimeZone(now, timeZone);
|
|
35
73
|
const currentTimeInTimeZone = new Date(
|
|
36
|
-
|
|
74
|
+
nowParts.year, nowParts.month - 1, nowParts.day,
|
|
75
|
+
nowParts.hour, nowParts.minute, nowParts.second
|
|
37
76
|
);
|
|
38
77
|
|
|
39
78
|
const maxAllowedDate = new Date(currentTimeInTimeZone.getTime());
|
|
40
79
|
maxAllowedDate.setDate(maxAllowedDate.getDate() + dagenInToekomst);
|
|
41
80
|
maxAllowedDate.setHours(23, 59, 59, 999);
|
|
42
81
|
|
|
82
|
+
// Parse target date - already in local date format, no timezone conversion needed
|
|
43
83
|
const [year, month, day] = dateStr.split('-').map(Number);
|
|
44
|
-
const
|
|
45
|
-
const targetDateInTimeZone = new Date(
|
|
46
|
-
targetDate.toLocaleString('en-US', { timeZone: timeZone })
|
|
47
|
-
);
|
|
84
|
+
const targetDateInTimeZone = new Date(year, month - 1, day);
|
|
48
85
|
|
|
49
86
|
return targetDateInTimeZone <= maxAllowedDate;
|
|
50
87
|
}
|