From 63af99eb75fd209ceff1c2fbee44606d824649c9 Mon Sep 17 00:00:00 2001 From: Yulia Shanyrova Date: Tue, 28 Mar 2023 16:45:47 +0200 Subject: [PATCH] Refactoring of isInWorkingHours method (#1574) # What this PR does Instead of using string comparing now isBetween method from dayjs is used ## Which issue(s) this PR fixes https://github.com/grafana/oncall/issues/1418 --------- Co-authored-by: Joey Orlando --- .../WorkingHours/WorkingHours.helpers.test.ts | 110 ++++++++++++++++++ .../WorkingHours/WorkingHours.helpers.ts | 33 ++++-- 2 files changed, 134 insertions(+), 9 deletions(-) create mode 100644 grafana-plugin/src/components/WorkingHours/WorkingHours.helpers.test.ts diff --git a/grafana-plugin/src/components/WorkingHours/WorkingHours.helpers.test.ts b/grafana-plugin/src/components/WorkingHours/WorkingHours.helpers.test.ts new file mode 100644 index 00000000..b54d6ba3 --- /dev/null +++ b/grafana-plugin/src/components/WorkingHours/WorkingHours.helpers.test.ts @@ -0,0 +1,110 @@ +import dayjs from 'dayjs'; +import isBetween from 'dayjs/plugin/isBetween'; +import timezone from 'dayjs/plugin/timezone'; +import utc from 'dayjs/plugin/utc'; + +dayjs.extend(timezone); +dayjs.extend(utc); +dayjs.extend(isBetween); + +import { isInWorkingHours } from './WorkingHours.helpers'; + +describe('Is in working hours', () => { + const currentMoment = dayjs('2023-03-27 14:57'); + + test('Returns true when it is in working hours', () => { + const workingHours = { + monday: [{ end: '17:00:00', start: '09:00:00' }], + tuesday: [{ end: '17:00:00', start: '09:00:00' }], + wednesday: [{ end: '17:00:00', start: '09:00:00' }], + thursday: [{ end: '17:00:00', start: '09:00:00' }], + friday: [{ end: '17:00:00', start: '09:00:00' }], + saturday: [{ end: '17:00:00', start: '09:00:00' }], + sunday: [{ end: '17:00:00', start: '09:00:00' }], + }; + expect(isInWorkingHours(currentMoment, workingHours, dayjs.tz.guess())).toBeTruthy(); + }); + + test('Returns false when it is NOT in working hours', () => { + const workingHours = { + monday: [{ end: '14:00:00', start: '09:00:00' }], + tuesday: [{ end: '14:00:00', start: '09:00:00' }], + wednesday: [{ end: '14:00:00', start: '09:00:00' }], + thursday: [{ end: '14:00:00', start: '09:00:00' }], + friday: [{ end: '14:00:00', start: '09:00:00' }], + saturday: [{ end: '14:00:00', start: '09:00:00' }], + sunday: [{ end: '14:00:00', start: '09:00:00' }], + }; + expect(isInWorkingHours(currentMoment, workingHours, dayjs.tz.guess())).toBeFalsy(); + }); + + test('Returns false when it is complex Working hours schedule', () => { + const workingHours = { + monday: [ + { start: '09:00:00', end: '11:00:00' }, + { start: '15:00:00', end: '18:00:00' }, + ], + tuesday: [ + { start: '09:00:00', end: '11:00:00' }, + { start: '15:00:00', end: '18:00:00' }, + ], + wednesday: [ + { start: '09:00:00', end: '11:00:00' }, + { start: '15:00:00', end: '18:00:00' }, + ], + thursday: [ + { start: '09:00:00', end: '11:00:00' }, + { start: '15:00:00', end: '18:00:00' }, + ], + friday: [ + { start: '09:00:00', end: '11:00:00' }, + { start: '15:00:00', end: '18:00:00' }, + ], + saturday: [ + { start: '09:00:00', end: '11:00:00' }, + { start: '15:00:00', end: '18:00:00' }, + ], + sunday: [ + { start: '09:00:00', end: '11:00:00' }, + { start: '15:00:00', end: '18:00:00' }, + ], + }; + + expect(isInWorkingHours(currentMoment, workingHours, dayjs.tz.guess())).toBeFalsy(); + }); + + test('Returns true when it is complex Working hours schedule', () => { + const workingHours = { + monday: [ + { start: '09:00:00', end: '13:00:00' }, + { start: '14:00:00', end: '18:00:00' }, + ], + tuesday: [ + { start: '09:00:00', end: '13:00:00' }, + { start: '14:00:00', end: '18:00:00' }, + ], + wednesday: [ + { start: '09:00:00', end: '13:00:00' }, + { start: '14:00:00', end: '18:00:00' }, + ], + thursday: [ + { start: '09:00:00', end: '13:00:00' }, + { start: '14:00:00', end: '18:00:00' }, + ], + friday: [ + { start: '09:00:00', end: '13:00:00' }, + { start: '14:00:00', end: '18:00:00' }, + ], + saturday: [ + { start: '09:00:00', end: '13:00:00' }, + { start: '14:00:00', end: '18:00:00' }, + ], + sunday: [ + { start: '09:00:00', end: '13:00:00' }, + { start: '14:00:00', end: '18:00:00' }, + ], + }; + + expect(isInWorkingHours(currentMoment, workingHours, dayjs.tz.guess())).toBeTruthy(); + }); +}); diff --git a/grafana-plugin/src/components/WorkingHours/WorkingHours.helpers.ts b/grafana-plugin/src/components/WorkingHours/WorkingHours.helpers.ts index 43e6f9b8..a905401c 100644 --- a/grafana-plugin/src/components/WorkingHours/WorkingHours.helpers.ts +++ b/grafana-plugin/src/components/WorkingHours/WorkingHours.helpers.ts @@ -98,19 +98,34 @@ export const getNonWorkingMoments = (startMoment, endMoment, workingMoments) => return nonWorkingMoments; }; +const getDayJsDateFromTime = (momentToStart: dayjs.Dayjs, currentMoment: dayjs.Dayjs, workingHours) => { + const [hours, minutes, seconds] = workingHours.split(':'); + + return dayjs(momentToStart) + .set('date', currentMoment.date()) + .set('hour', Number(hours)) + .set('minute', Number(minutes)) + .set('second', Number(seconds)); +}; + export const isInWorkingHours = (currentMoment: dayjs.Dayjs, workingHours, timezone) => { - const timeFormat = 'HH:mm:ss'; + const momentToStart = dayjs().tz(timezone).utcOffset() === 0 ? currentMoment : currentMoment.tz(timezone); const currentDayOfTheWeek = currentMoment.format('dddd').toLowerCase(); - const workingHourStart = workingHours[currentDayOfTheWeek][0]?.start; - const workingHourEnd = workingHours[currentDayOfTheWeek][0]?.end; - if (workingHourStart && workingHourEnd) { - const startTime = dayjs(workingHourStart, timeFormat).tz(timezone).format(timeFormat); - const endTime = dayjs(workingHourEnd, timeFormat).tz(timezone).format(timeFormat); - const currentTime = dayjs(currentMoment, timeFormat).format(timeFormat); + if (workingHours[currentDayOfTheWeek]?.length > 0) { + const currentTime = dayjs(momentToStart); - return currentTime < endTime && currentTime >= startTime; + for (const range of workingHours[currentDayOfTheWeek]) { + const rangeStartData = range?.start; + const rangeEndData = range?.end; + + let startTime = getDayJsDateFromTime(momentToStart, currentMoment, rangeStartData); + let endTime = getDayJsDateFromTime(momentToStart, currentMoment, rangeEndData); + + if (currentTime.isBetween(startTime, endTime, null, '[)')) { + return true; + } + } } - return false; };