fix: Update business hour calculation (#4496)
This commit is contained in:
parent
e010f0c6f0
commit
17fb6b8d55
7 changed files with 125 additions and 46 deletions
|
@ -2,7 +2,6 @@ import fromUnixTime from 'date-fns/fromUnixTime';
|
|||
import format from 'date-fns/format';
|
||||
import isToday from 'date-fns/isToday';
|
||||
import isYesterday from 'date-fns/isYesterday';
|
||||
import parseISO from 'date-fns/parseISO';
|
||||
|
||||
export const formatUnixDate = (date, dateFormat = 'MMM dd, yyyy') => {
|
||||
const unixDate = fromUnixTime(date);
|
||||
|
@ -20,10 +19,14 @@ export const formatDigitToString = val => {
|
|||
return val > 9 ? `${val}` : `0${val}`;
|
||||
};
|
||||
|
||||
export const buildDateFromTime = (hr, min, utcOffset, date = new Date()) => {
|
||||
const today = format(date, 'yyyy-MM-dd');
|
||||
const hour = formatDigitToString(hr);
|
||||
const minute = formatDigitToString(min);
|
||||
const timeString = `${today}T${hour}:${minute}:00${utcOffset}`;
|
||||
return parseISO(timeString);
|
||||
export const isTimeAfter = (h1, m1, h2, m2) => {
|
||||
if (h1 < h2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (h1 === h2) {
|
||||
return m1 >= m2;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import {
|
||||
formatDate,
|
||||
formatUnixDate,
|
||||
buildDateFromTime,
|
||||
formatDigitToString,
|
||||
isTimeAfter,
|
||||
} from '../DateHelper';
|
||||
|
||||
describe('#DateHelper', () => {
|
||||
|
@ -44,27 +44,21 @@ describe('#DateHelper', () => {
|
|||
})
|
||||
).toEqual('Yesterday');
|
||||
});
|
||||
|
||||
describe('#buildDate', () => {
|
||||
it('returns correctly parsed date', () => {
|
||||
const date = new Date();
|
||||
date.setFullYear(2021);
|
||||
date.setMonth(2);
|
||||
date.setDate(5);
|
||||
|
||||
const result = buildDateFromTime(12, 15, '.465Z', date);
|
||||
expect(result + '').toEqual(
|
||||
'Fri Mar 05 2021 12:15:00 GMT+0000 (Coordinated Universal Time)'
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('#formatDigitToString', () => {
|
||||
it('returns date compatabile string from number is less than 9', () => {
|
||||
expect(formatDigitToString(8)).toEqual('08');
|
||||
});
|
||||
|
||||
describe('#formatDigitToString', () => {
|
||||
it('returns date compatabile string from number is less than 9', () => {
|
||||
expect(formatDigitToString(8)).toEqual('08');
|
||||
});
|
||||
it('returns date compatabile string from number is greater than 9', () => {
|
||||
expect(formatDigitToString(11)).toEqual('11');
|
||||
});
|
||||
it('returns date compatabile string from number is greater than 9', () => {
|
||||
expect(formatDigitToString(11)).toEqual('11');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isTimeAfter', () => {
|
||||
it('return correct values', () => {
|
||||
expect(isTimeAfter(5, 30, 9, 30)).toEqual(false);
|
||||
expect(isTimeAfter(9, 30, 9, 30)).toEqual(true);
|
||||
expect(isTimeAfter(9, 29, 9, 30)).toEqual(false);
|
||||
expect(isTimeAfter(11, 59, 12, 0)).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -58,6 +58,7 @@ export default {
|
|||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters({
|
||||
widgetColor: 'appConfig/getWidgetColor',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import compareAsc from 'date-fns/compareAsc';
|
||||
import { buildDateFromTime } from 'shared/helpers/DateHelper';
|
||||
import { utcToZonedTime } from 'date-fns-tz';
|
||||
import { isTimeAfter } from 'shared/helpers/DateHelper';
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
|
@ -33,23 +33,32 @@ export default {
|
|||
closedAllDay,
|
||||
openAllDay,
|
||||
} = this.currentDayAvailability;
|
||||
|
||||
if (openAllDay || closedAllDay) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const { utcOffset } = this.channelConfig;
|
||||
|
||||
if (openAllDay) return true;
|
||||
|
||||
if (closedAllDay) return false;
|
||||
|
||||
const startTime = buildDateFromTime(openHour, openMinute, utcOffset);
|
||||
const endTime = buildDateFromTime(closeHour, closeMinute, utcOffset);
|
||||
const isBetween =
|
||||
compareAsc(new Date(), startTime) === 1 &&
|
||||
compareAsc(endTime, new Date()) === 1;
|
||||
|
||||
if (isBetween) return true;
|
||||
return false;
|
||||
const today = this.getDateWithOffset(utcOffset);
|
||||
const currentHours = today.getHours();
|
||||
const currentMinutes = today.getMinutes();
|
||||
const isAfterStartTime = isTimeAfter(
|
||||
currentHours,
|
||||
currentMinutes,
|
||||
openHour,
|
||||
openMinute
|
||||
);
|
||||
const isBeforeEndTime = isTimeAfter(
|
||||
closeHour,
|
||||
closeMinute,
|
||||
currentHours,
|
||||
currentMinutes
|
||||
);
|
||||
return isAfterStartTime && isBeforeEndTime;
|
||||
},
|
||||
currentDayAvailability() {
|
||||
const dayOfTheWeek = new Date().getDay();
|
||||
const { utcOffset } = this.channelConfig;
|
||||
const dayOfTheWeek = this.getDateWithOffset(utcOffset).getDay();
|
||||
const [workingHourConfig = {}] = this.channelConfig.workingHours.filter(
|
||||
workingHour => workingHour.day_of_week === dayOfTheWeek
|
||||
);
|
||||
|
@ -63,8 +72,14 @@ export default {
|
|||
};
|
||||
},
|
||||
isInBusinessHours() {
|
||||
const { workingHoursEnabled } = window.chatwootWebChannel;
|
||||
const { workingHoursEnabled } = this.channelConfig;
|
||||
return workingHoursEnabled ? this.isInBetweenTheWorkingHours : true;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
getDateWithOffset(utcOffset) {
|
||||
return utcToZonedTime(new Date().toISOString(), utcOffset);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
60
app/javascript/widget/mixins/specs/availabilityMixin.spec.js
Normal file
60
app/javascript/widget/mixins/specs/availabilityMixin.spec.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
import { createWrapper } from '@vue/test-utils';
|
||||
import availabilityMixin from '../availability';
|
||||
import Vue from 'vue';
|
||||
|
||||
global.chatwootWebChannel = {
|
||||
workingHoursEnabled: true,
|
||||
workingHours: [
|
||||
{
|
||||
day_of_week: 3,
|
||||
closed_all_day: false,
|
||||
open_hour: 8,
|
||||
open_minutes: 30,
|
||||
close_hour: 17,
|
||||
close_minutes: 35,
|
||||
open_all_day: false,
|
||||
},
|
||||
{
|
||||
day_of_week: 4,
|
||||
closed_all_day: false,
|
||||
open_hour: 8,
|
||||
open_minutes: 30,
|
||||
close_hour: 17,
|
||||
close_minutes: 30,
|
||||
open_all_day: false,
|
||||
},
|
||||
],
|
||||
utcOffset: '-07:00',
|
||||
};
|
||||
|
||||
describe('availabilityMixin', () => {
|
||||
it('returns valid isInBetweenWorkingHours if in different timezone', () => {
|
||||
const Component = {
|
||||
render() {},
|
||||
mixins: [availabilityMixin],
|
||||
};
|
||||
jest
|
||||
.useFakeTimers('modern')
|
||||
.setSystemTime(new Date('Thu Apr 14 2022 06:04:46 GMT+0530'));
|
||||
const Constructor = Vue.extend(Component);
|
||||
const vm = new Constructor().$mount();
|
||||
const wrapper = createWrapper(vm);
|
||||
expect(wrapper.vm.isInBetweenTheWorkingHours).toBe(true);
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('returns valid isInBetweenWorkingHours if in same timezone', () => {
|
||||
global.chatwootWebChannel.utcOffset = '+05:30';
|
||||
const Component = {
|
||||
render() {},
|
||||
mixins: [availabilityMixin],
|
||||
};
|
||||
jest
|
||||
.useFakeTimers('modern')
|
||||
.setSystemTime(new Date('Thu Apr 14 2022 09:01:46 GMT+0530'));
|
||||
const Constructor = Vue.extend(Component);
|
||||
const wrapper = createWrapper(new Constructor().$mount());
|
||||
expect(wrapper.vm.isInBetweenTheWorkingHours).toBe(true);
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
|
@ -35,6 +35,7 @@
|
|||
"core-js": "3.11.0",
|
||||
"country-code-emoji": "^1.0.0",
|
||||
"date-fns": "2.21.1",
|
||||
"date-fns-tz": "^1.3.3",
|
||||
"dompurify": "2.2.7",
|
||||
"dotenv": "^8.0.0",
|
||||
"foundation-sites": "~6.5.3",
|
||||
|
|
|
@ -5454,6 +5454,11 @@ data-urls@^2.0.0:
|
|||
whatwg-mimetype "^2.3.0"
|
||||
whatwg-url "^8.0.0"
|
||||
|
||||
date-fns-tz@^1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/date-fns-tz/-/date-fns-tz-1.3.3.tgz#7884a4b3ed6cd95bfd81831d608e5ef8be500c86"
|
||||
integrity sha512-Gks46gwbSauBQnV3Oofluj1wTm8J0tM7sbSJ9P+cJq/ZnTCpMohTKmmO5Tn+jQ7dyn0+b8G7cY4O2DZ5P/LXcA==
|
||||
|
||||
date-fns@2.21.1:
|
||||
version "2.21.1"
|
||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.21.1.tgz#679a4ccaa584c0706ea70b3fa92262ac3009d2b0"
|
||||
|
|
Loading…
Reference in a new issue