Fix: Update offline message in widget by availability (#1879)

Feat: Display out of office message based on business hours

Co-authored-by: Pranav Raj Sreepuram <pranavrajs@gmail.com>
This commit is contained in:
Nithin David Thomas
2021-03-13 14:06:25 +05:30
committed by GitHub
parent 2a28e05a77
commit 33b73451b7
5 changed files with 110 additions and 89 deletions

View File

@@ -16,12 +16,14 @@ export const formatDate = ({ date, todayText, yesterdayText }) => {
return date; return date;
}; };
export const buildDateFromTime = (hr, min, utcOffset, date = new Date()) => {
const today = format(date, 'yyyy-MM-dd');
const timeString = `${today}T${hr}:${min}:00${utcOffset}`;
return parseISO(timeString);
};
export const formatDigitToString = val => { export const formatDigitToString = val => {
return val > 9 ? `${val}` : `0${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);
};

View File

@@ -13,13 +13,13 @@
<div <div
:class=" :class="
`status-view--badge rounded-full leading-4 ${ `status-view--badge rounded-full leading-4 ${
availableAgents.length ? 'bg-green-500' : 'hidden' isOnline ? 'bg-green-500' : 'hidden'
}` }`
" "
/> />
</div> </div>
<div class="text-xs mt-1 text-black-700"> <div class="text-xs mt-1 text-black-700">
{{ replyTimeStatus }} {{ replyWaitMeessage }}
</div> </div>
</div> </div>
</div> </div>
@@ -30,14 +30,14 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import HeaderActions from './HeaderActions'; import HeaderActions from './HeaderActions';
import configMixin from 'widget/mixins/configMixin'; import availabilityMixin from 'widget/mixins/availability';
export default { export default {
name: 'ChatHeader', name: 'ChatHeader',
components: { components: {
HeaderActions, HeaderActions,
}, },
mixins: [configMixin], mixins: [availabilityMixin],
props: { props: {
avatarUrl: { avatarUrl: {
type: String, type: String,
@@ -60,6 +60,20 @@ export default {
...mapGetters({ ...mapGetters({
widgetColor: 'appConfig/getWidgetColor', widgetColor: 'appConfig/getWidgetColor',
}), }),
isOnline() {
const { workingHoursEnabled } = this.channelConfig;
const anyAgentOnline = this.availableAgents.length > 0;
if (workingHoursEnabled) {
return this.isInBetweenTheWorkingHours;
}
return anyAgentOnline;
},
replyWaitMeessage() {
return this.isOnline
? this.replyTimeStatus
: this.$t('TEAM_AVAILABILITY.OFFLINE');
},
}, },
}; };
</script> </script>

View File

@@ -1,27 +1,19 @@
<template> <template>
<div class="px-4"> <div class="px-4">
<div <div class="flex items-center justify-between mb-4">
v-if="channelConfig.workingHoursEnabled"
class="flex items-center justify-between mb-4"
>
<div class="text-black-700"> <div class="text-black-700">
<div class="text-base leading-5 font-medium mb-1"> <div class="text-base leading-5 font-medium mb-1">
{{ {{
isInBetweenTheWorkingHours isOnline
? $t('TEAM_AVAILABILITY.ONLINE') ? $t('TEAM_AVAILABILITY.ONLINE')
: $t('TEAM_AVAILABILITY.OFFLINE') : $t('TEAM_AVAILABILITY.OFFLINE')
}} }}
</div> </div>
<div class="text-xs leading-4 mt-1"> <div class="text-xs leading-4 mt-1">
{{ {{ replyWaitMeessage }}
isInBetweenTheWorkingHours ? replyTimeStatus : outOfOfficeMessage
}}
</div> </div>
</div> </div>
<available-agents <available-agents v-if="isOnline" :agents="availableAgents" />
v-if="isInBetweenTheWorkingHours"
:agents="availableAgents"
/>
</div> </div>
<woot-button <woot-button
class="font-medium" class="font-medium"
@@ -39,13 +31,9 @@
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import AvailableAgents from 'widget/components/AvailableAgents.vue'; import AvailableAgents from 'widget/components/AvailableAgents.vue';
import { getContrastingTextColor } from 'shared/helpers/ColorHelper'; import { getContrastingTextColor } from 'shared/helpers/ColorHelper';
import {
buildDateFromTime,
formatDigitToString,
} from 'shared/helpers/DateHelper';
import WootButton from 'shared/components/Button'; import WootButton from 'shared/components/Button';
import configMixin from 'widget/mixins/configMixin'; import configMixin from 'widget/mixins/configMixin';
import compareAsc from 'date-fns/compareAsc'; import availabilityMixin from 'widget/mixins/availability';
export default { export default {
name: 'TeamAvailability', name: 'TeamAvailability',
@@ -53,7 +41,7 @@ export default {
AvailableAgents, AvailableAgents,
WootButton, WootButton,
}, },
mixins: [configMixin], mixins: [configMixin, availabilityMixin],
props: { props: {
availableAgents: { availableAgents: {
type: Array, type: Array,
@@ -65,52 +53,25 @@ export default {
textColor() { textColor() {
return getContrastingTextColor(this.widgetColor); return getContrastingTextColor(this.widgetColor);
}, },
isInBetweenTheWorkingHours() { isOnline() {
const { const { workingHoursEnabled } = this.channelConfig;
closedAllDay, const anyAgentOnline = this.availableAgents.length > 0;
openHour,
openMinute,
closeHour,
closeMinute,
} = this.currentDayAvailability;
if (closedAllDay) { if (workingHoursEnabled) {
return false; return this.isInBetweenTheWorkingHours;
} }
return anyAgentOnline;
const { utcOffset } = this.channelConfig;
const startTime = buildDateFromTime(
formatDigitToString(openHour),
formatDigitToString(openMinute),
utcOffset
);
const endTime = buildDateFromTime(
formatDigitToString(closeHour),
formatDigitToString(closeMinute),
utcOffset
);
if (
compareAsc(new Date(), startTime) === 1 &&
compareAsc(endTime, new Date()) === 1
) {
return true;
}
return false;
}, },
currentDayAvailability() { replyWaitMeessage() {
const dayOfTheWeek = new Date().getDay(); const { workingHoursEnabled } = this.channelConfig;
const [workingHourConfig = {}] = this.channelConfig.workingHours.filter(
workingHour => workingHour.day_of_week === dayOfTheWeek if (this.isOnline) {
); return this.replyTimeStatus;
return { }
closedAllDay: workingHourConfig.closed_all_day, if (workingHoursEnabled) {
openHour: workingHourConfig.open_hour, return this.outOfOfficeMessage;
openMinute: workingHourConfig.open_minutes, }
closeHour: workingHourConfig.close_hour, return this.$t('TEAM_AVAILABILITY.OFFLINE');
closeMinute: workingHourConfig.close_minutes,
};
}, },
}, },
methods: { methods: {

View File

@@ -0,0 +1,62 @@
import compareAsc from 'date-fns/compareAsc';
import { buildDateFromTime } from 'shared/helpers/DateHelper';
export default {
computed: {
channelConfig() {
return window.chatwootWebChannel;
},
replyTime() {
return window.chatwootWebChannel.replyTime;
},
replyTimeStatus() {
switch (this.replyTime) {
case 'in_a_few_minutes':
return this.$t('REPLY_TIME.IN_A_FEW_MINUTES');
case 'in_a_few_hours':
return this.$t('REPLY_TIME.IN_A_FEW_HOURS');
case 'in_a_day':
return this.$t('REPLY_TIME.IN_A_DAY');
default:
return this.$t('REPLY_TIME.IN_A_FEW_HOURS');
}
},
outOfOfficeMessage() {
return this.channelConfig.outOfOfficeMessage;
},
isInBetweenTheWorkingHours() {
const {
openHour,
openMinute,
closeHour,
closeMinute,
closedAllDay,
} = this.currentDayAvailability;
const { utcOffset } = this.channelConfig;
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;
},
currentDayAvailability() {
const dayOfTheWeek = new Date().getDay();
const [workingHourConfig = {}] = this.channelConfig.workingHours.filter(
workingHour => workingHour.day_of_week === dayOfTheWeek
);
return {
closedAllDay: workingHourConfig.closed_all_day,
openHour: workingHourConfig.open_hour,
openMinute: workingHourConfig.open_minutes,
closeHour: workingHourConfig.close_hour,
closeMinute: workingHourConfig.close_minutes,
};
},
},
};

View File

@@ -21,9 +21,6 @@ export default {
hasAttachmentsEnabled() { hasAttachmentsEnabled() {
return this.channelConfig.enabledFeatures.includes('attachments'); return this.channelConfig.enabledFeatures.includes('attachments');
}, },
replyTime() {
return window.chatwootWebChannel.replyTime;
},
preChatFormEnabled() { preChatFormEnabled() {
return window.chatwootWebChannel.preChatFormEnabled; return window.chatwootWebChannel.preChatFormEnabled;
}, },
@@ -34,20 +31,5 @@ export default {
preChatMessage: options.pre_chat_message, preChatMessage: options.pre_chat_message,
}; };
}, },
replyTimeStatus() {
switch (this.replyTime) {
case 'in_a_few_minutes':
return this.$t('REPLY_TIME.IN_A_FEW_MINUTES');
case 'in_a_few_hours':
return this.$t('REPLY_TIME.IN_A_FEW_HOURS');
case 'in_a_day':
return this.$t('REPLY_TIME.IN_A_DAY');
default:
return this.$t('REPLY_TIME.IN_A_FEW_HOURS');
}
},
outOfOfficeMessage() {
return this.channelConfig.outOfOfficeMessage;
},
}, },
}; };