From 7069883eb12acb4d888785044e3fb51b67f185ac Mon Sep 17 00:00:00 2001 From: SanttuA Date: Wed, 29 May 2024 12:35:44 +0300 Subject: [PATCH] Fix to overnight calendar continous reservation check (#329) Previously continous reservation check did not correctly detect reservations that last 24hrs or less. This change fixes the issue. --- .../overnight-calendar/OvernightCalendar.js | 9 +- .../overnight-calendar/overnightUtils.js | 35 ++++-- .../tests/overnightUtils.spec.js | 106 +++++++++++++++++- 3 files changed, 136 insertions(+), 14 deletions(-) diff --git a/app/shared/overnight-calendar/OvernightCalendar.js b/app/shared/overnight-calendar/OvernightCalendar.js index a7848a766..906e62ca1 100644 --- a/app/shared/overnight-calendar/OvernightCalendar.js +++ b/app/shared/overnight-calendar/OvernightCalendar.js @@ -144,7 +144,14 @@ function OvernightCalendar({ } if ((startDate && !endDate) - && !isSelectionContinous(startDate, day, filteredReservations, openingHours)) { + && !isSelectionContinous({ + startDate, + endDate: day, + reservations: filteredReservations, + openingHours, + overnightStartTime, + overnightEndTime + })) { actions.addNotification({ message: t('Notifications.continousFreeDaysError'), type: 'info', diff --git a/app/shared/overnight-calendar/overnightUtils.js b/app/shared/overnight-calendar/overnightUtils.js index 43646fda3..058e295e7 100644 --- a/app/shared/overnight-calendar/overnightUtils.js +++ b/app/shared/overnight-calendar/overnightUtils.js @@ -117,16 +117,20 @@ export function getClosedDays(openingHours) { * Returns reservations modifier for DayPicker * @param {Date} day * @param {Object[]} reservations + * @param {string} granularity e.g. 'day' or 'hour' for checking + * is day between reservation start and end. Default is 'day'. + * @param {string} inclusivity e.g. '()' or '[]' for checking + * is day between reservation start and end. Default is '()'. * @returns {boolean} is day booked */ -export function reservationsModifier(day, reservations) { +export function reservationsModifier(day, reservations, granularity = 'day', inclusivity = '()') { if (day && reservations) { const dayMoment = moment(day); for (let index = 0; index < reservations.length; index += 1) { const reservation = reservations[index]; const beginMoment = moment(reservation.begin); const endMoment = moment(reservation.end); - if (dayMoment.isBetween(beginMoment, endMoment, 'day', '()')) { + if (dayMoment.isBetween(beginMoment, endMoment, granularity, inclusivity)) { return true; } } @@ -526,18 +530,33 @@ export function areDatesSameAsInitialDates(startDate, endDate, initialStart, ini /** * Returns true if selection is continous i.e. does not contain disabled days - * @param {Date} startDate - * @param {Date} endDate - * @param {Object[]} reservations - * @param {Object[]} openingHours + * @param {Object} params + * @param {Date} params.startDate + * @param {Date} params.endDate + * @param {Object[]} params.reservations + * @param {Object[]} params.openingHours + * @param {string} params.overnightStartTime + * @param {string} params.overnightEndTime * @returns {boolean} true if selection is continous */ -export function isSelectionContinous(startDate, endDate, reservations, openingHours) { +export function isSelectionContinous({ + startDate, endDate, reservations, openingHours, + overnightStartTime, overnightEndTime +}) { const dates = createDateArray(startDate, endDate); + if (dates.length < 2) { + return true; + } + + dates[0] = setDatesTime(dates[0], overnightStartTime).toDate(); + dates[dates.length - 1] = setDatesTime(dates[dates.length - 1], overnightEndTime).toDate(); for (let index = 0; index < dates.length; index += 1) { const date = dates[index]; - if (reservationsModifier(date, reservations) || closedDaysModifier(date, openingHours)) { + const isFirstOrLast = index === 0 || index === dates.length - 1; + const granularity = isFirstOrLast ? 'seconds' : 'days'; + if (reservationsModifier(date, reservations, granularity, '[]') + || closedDaysModifier(date, openingHours)) { return false; } } diff --git a/app/shared/overnight-calendar/tests/overnightUtils.spec.js b/app/shared/overnight-calendar/tests/overnightUtils.spec.js index 7f8efc684..51b608f47 100644 --- a/app/shared/overnight-calendar/tests/overnightUtils.spec.js +++ b/app/shared/overnight-calendar/tests/overnightUtils.spec.js @@ -785,6 +785,12 @@ describe('app/shared/overnight-calendar/overnightUtils', () => { end: '2024-04-29T09:00:00+03:00' }) ]; + const reservations2 = [ + Reservation.build({ + begin: '2024-04-27T13:00:00+03:00', + end: '2024-04-28T09:00:00+03:00' + }) + ]; const openingHours = [ { date: '2024-04-19', closes: null, opens: null }, { date: '2024-04-20', closes: '2024-04-20T20:00:00+03:00', opens: '2024-04-20T06:00:00+03:00' }, @@ -799,12 +805,41 @@ describe('app/shared/overnight-calendar/overnightUtils', () => { { date: '2024-04-29', closes: '2024-04-29T20:00:00+03:00', opens: '2024-04-29T06:00:00+03:00' }, { date: '2024-04-30', closes: null, opens: null }, ]; + const overnightStartTime = '13:00:00'; + const overnightEndTime = '09:00:00'; + test('returns true when no reservations or closed days in selection', () => { const startDate = moment('2024-04-23').toDate(); const endDate = moment('2024-04-27').toDate(); - expect(isSelectionContinous(startDate, endDate, [], openingHours)) + const startDate2 = moment('2024-04-26').toDate(); + const endDate2 = moment('2024-04-27').toDate(); + const startDate3 = moment('2024-04-28').toDate(); + const endDate3 = moment('2024-04-29').toDate(); + expect(isSelectionContinous({ + startDate, endDate, reservations: [], openingHours, overnightStartTime, overnightEndTime + })) + .toBe(true); + expect(isSelectionContinous({ + startDate, endDate, reservations, openingHours, overnightStartTime, overnightEndTime + })) .toBe(true); - expect(isSelectionContinous(startDate, endDate, reservations, openingHours)) + expect(isSelectionContinous({ + startDate: startDate2, + endDate: endDate2, + reservations: reservations2, + openingHours, + overnightStartTime, + overnightEndTime + })) + .toBe(true); + expect(isSelectionContinous({ + startDate: startDate3, + endDate: endDate3, + reservations: reservations2, + openingHours, + overnightStartTime, + overnightEndTime + })) .toBe(true); }); test('returns false when reservations or closed days in selection', () => { @@ -814,11 +849,72 @@ describe('app/shared/overnight-calendar/overnightUtils', () => { const endDate2 = moment('2024-04-30').toDate(); const startDate3 = moment('2024-04-19').toDate(); const endDate3 = moment('2024-04-20').toDate(); - expect(isSelectionContinous(startDate1, endDate1, reservations, openingHours)) + const startDate4 = moment('2024-04-26').toDate(); + const endDate4 = moment('2024-04-28').toDate(); + const startDate5 = moment('2024-04-26').toDate(); + const endDate5 = moment('2024-04-29').toDate(); + expect(isSelectionContinous({ + startDate: startDate1, + endDate: endDate1, + reservations, + openingHours, + overnightStartTime, + overnightEndTime + })) .toBe(false); - expect(isSelectionContinous(startDate2, endDate2, reservations, openingHours)) + expect(isSelectionContinous({ + startDate: startDate1, + endDate: endDate1, + reservations: reservations2, + openingHours, + overnightStartTime, + overnightEndTime + })) + .toBe(false); + expect(isSelectionContinous({ + startDate: startDate2, + endDate: endDate2, + reservations, + openingHours, + overnightStartTime, + overnightEndTime + })) .toBe(false); - expect(isSelectionContinous(startDate3, endDate3, reservations, openingHours)) + expect(isSelectionContinous({ + startDate: startDate2, + endDate: endDate2, + reservations: reservations2, + openingHours, + overnightStartTime, + overnightEndTime + })) + .toBe(false); + expect(isSelectionContinous({ + startDate: startDate3, + endDate: endDate3, + reservations, + openingHours, + overnightStartTime, + overnightEndTime + })) + .toBe(false); + expect(isSelectionContinous({ + startDate: startDate4, + endDate: endDate4, + reservations: reservations2, + openingHours, + overnightStartTime, + overnightEndTime + })) + .toBe(false); + expect(isSelectionContinous({ + startDate: startDate5, + endDate: endDate5, + reservations: reservations2, + openingHours, + overnightStartTime, + overnightEndTime + })) .toBe(false); }); });