The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
Rocket.Chat/app/livechat/server/lib/analytics/dashboards.js

270 lines
9.3 KiB

import moment from 'moment';
import { LivechatRooms, Users, LivechatVisitors, LivechatAgentActivity } from '../../../../models/server/raw';
import { Livechat } from '../Livechat';
import { secondsToHHMMSS } from '../../../../utils/server';
import {
findPercentageOfAbandonedRoomsAsync,
findAllAverageOfChatDurationTimeAsync,
findAllAverageWaitingTimeAsync,
findAllNumberOfAbandonedRoomsAsync,
findAllAverageServiceTimeAsync,
} from './departments';
const findAllChatsStatusAsync = async ({
start,
end,
departmentId = undefined,
}) => {
if (!start || !end) {
throw new Error('"start" and "end" must be provided');
}
return {
open: await LivechatRooms.countAllOpenChatsBetweenDate({ start, end, departmentId }),
closed: await LivechatRooms.countAllClosedChatsBetweenDate({ start, end, departmentId }),
queued: await LivechatRooms.countAllQueuedChatsBetweenDate({ start, end, departmentId }),
};
};
const getProductivityMetricsAsync = async ({
start,
end,
departmentId = undefined,
}) => {
if (!start || !end) {
throw new Error('"start" and "end" must be provided');
}
const totalizers = Livechat.Analytics.getAnalyticsOverviewData({
daterange: {
from: start,
to: end,
},
analyticsOptions: {
name: 'Productivity',
},
});
const averageWaitingTime = await findAllAverageWaitingTimeAsync({
start,
end,
departmentId,
});
const totalOfWaitingTime = averageWaitingTime.departments.length;
const sumOfWaitingTime = averageWaitingTime.departments.reduce((acc, serviceTime) => {
acc += serviceTime.averageWaitingTimeInSeconds;
return acc;
}, 0);
const totalOfAvarageWaitingTime = totalOfWaitingTime === 0 ? 0 : sumOfWaitingTime / totalOfWaitingTime;
return {
totalizers: [
...totalizers,
{ title: 'Avg_of_waiting_time', value: secondsToHHMMSS(totalOfAvarageWaitingTime) },
],
};
};
const getAgentsProductivityMetricsAsync = async ({
start,
end,
departmentId = undefined,
}) => {
if (!start || !end) {
throw new Error('"start" and "end" must be provided');
}
const averageOfAvailableServiceTime = (await LivechatAgentActivity.findAllAverageAvailableServiceTime({
date: parseInt(moment(start).format('YYYYMMDD')),
departmentId,
}))[0];
const averageOfServiceTime = await findAllAverageServiceTimeAsync({
start,
end,
departmentId,
});
const totalizers = Livechat.Analytics.getAnalyticsOverviewData({
daterange: {
from: start,
to: end,
},
analyticsOptions: {
name: 'Conversations',
},
});
const totalOfServiceTime = averageOfServiceTime.departments.length;
const sumOfServiceTime = averageOfServiceTime.departments.reduce((acc, serviceTime) => {
acc += serviceTime.averageServiceTimeInSeconds;
return acc;
}, 0);
const totalOfAverageAvailableServiceTime = averageOfAvailableServiceTime ? averageOfAvailableServiceTime.averageAvailableServiceTimeInSeconds : 0;
const totalOfAverageServiceTime = totalOfServiceTime === 0 ? 0 : sumOfServiceTime / totalOfServiceTime;
return {
totalizers: [
...totalizers.filter((metric) => metric.title === 'Busiest_time'),
{ title: 'Avg_of_available_service_time', value: secondsToHHMMSS(totalOfAverageAvailableServiceTime) },
{ title: 'Avg_of_service_time', value: secondsToHHMMSS(totalOfAverageServiceTime) },
],
};
};
const getChatsMetricsAsync = async ({
start,
end,
departmentId = undefined,
}) => {
if (!start || !end) {
throw new Error('"start" and "end" must be provided');
}
const abandonedRooms = await findAllNumberOfAbandonedRoomsAsync({
start,
end,
departmentId,
});
const averageOfAbandonedRooms = await findPercentageOfAbandonedRoomsAsync({
start,
end,
departmentId,
});
const averageOfChatDurationTime = await findAllAverageOfChatDurationTimeAsync({
start,
end,
departmentId,
});
const totalOfAbandonedRooms = averageOfAbandonedRooms.departments.length;
const totalOfChatDurationTime = averageOfChatDurationTime.departments.length;
const sumOfPercentageOfAbandonedRooms = averageOfAbandonedRooms.departments.reduce((acc, abandonedRoom) => {
acc += abandonedRoom.percentageOfAbandonedChats;
return acc;
}, 0);
const sumOfChatDurationTime = averageOfChatDurationTime.departments.reduce((acc, chatDurationTime) => {
acc += chatDurationTime.averageChatDurationTimeInSeconds;
return acc;
}, 0);
const totalAbandonedRooms = abandonedRooms.departments.reduce((acc, item) => {
acc += item.abandonedRooms;
return acc;
}, 0);
const totalOfAverageAbandonedRooms = totalOfAbandonedRooms === 0 ? 0 : sumOfPercentageOfAbandonedRooms / totalOfAbandonedRooms;
const totalOfAverageChatDurationTime = totalOfChatDurationTime === 0 ? 0 : sumOfChatDurationTime / totalOfChatDurationTime;
return {
totalizers: [
{ title: 'Total_abandoned_chats', value: totalAbandonedRooms },
{ title: 'Avg_of_abandoned_chats', value: `${ totalOfAverageAbandonedRooms }%` },
{ title: 'Avg_of_chat_duration_time', value: secondsToHHMMSS(totalOfAverageChatDurationTime) },
],
};
};
const getConversationsMetricsAsync = async ({
start,
end,
}) => {
if (!start || !end) {
throw new Error('"start" and "end" must be provided');
}
const totalizers = Livechat.Analytics.getAnalyticsOverviewData({
daterange: {
from: start,
to: end,
},
analyticsOptions: {
name: 'Conversations',
},
});
const metrics = ['Total_conversations', 'Open_conversations', 'Total_messages'];
const visitorsCount = await LivechatVisitors.getVisitorsBetweenDate({ start, end }).count();
return {
totalizers: [
...totalizers.filter((metric) => metrics.includes(metric.title)),
{ title: 'Total_visitors', value: visitorsCount },
],
};
};
const findAllChatMetricsByAgentAsync = async ({
start,
end,
departmentId = undefined,
}) => {
if (!start || !end) {
throw new Error('"start" and "end" must be provided');
}
const open = await LivechatRooms.countAllOpenChatsByAgentBetweenDate({ start, end, departmentId });
const closed = await LivechatRooms.countAllClosedChatsByAgentBetweenDate({ start, end, departmentId });
const result = {};
(open || []).forEach((agent) => {
result[agent._id] = { open: agent.chats, closed: 0 };
});
(closed || []).forEach((agent) => {
result[agent._id] = { open: result[agent._id] ? result[agent._id].open : 0, closed: agent.chats };
});
return result;
};
const findAllAgentsStatusAsync = async ({ departmentId = undefined }) => (await Users.countAllAgentsStatus({ departmentId }))[0];
const findAllChatMetricsByDepartmentAsync = async ({
start,
end,
departmentId = undefined,
}) => {
if (!start || !end) {
throw new Error('"start" and "end" must be provided');
}
const open = await LivechatRooms.countAllOpenChatsByDepartmentBetweenDate({ start, end, departmentId });
const closed = await LivechatRooms.countAllClosedChatsByDepartmentBetweenDate({ start, end, departmentId });
const result = {};
(open || []).forEach((department) => {
result[department.name] = { open: department.chats, closed: 0 };
});
(closed || []).forEach((department) => {
result[department.name] = { open: result[department.name] ? result[department.name].open : 0, closed: department.chats };
});
return result;
};
const findAllResponseTimeMetricsAsync = async ({
start,
end,
departmentId = undefined,
}) => {
if (!start || !end) {
throw new Error('"start" and "end" must be provided');
}
const responseTimes = (await LivechatRooms.calculateResponseTimingsBetweenDates({ start, end, departmentId }))[0];
const reactionTimes = (await LivechatRooms.calculateReactionTimingsBetweenDates({ start, end, departmentId }))[0];
const durationTimings = (await LivechatRooms.calculateDurationTimingsBetweenDates({ start, end, departmentId }))[0];
return {
response: {
avg: responseTimes ? responseTimes.avg : 0,
longest: responseTimes ? responseTimes.longest : 0,
},
reaction: {
avg: reactionTimes ? reactionTimes.avg : 0,
longest: reactionTimes ? reactionTimes.longest : 0,
},
chatDuration: {
avg: durationTimings ? durationTimings.avg : 0,
longest: durationTimings ? durationTimings.longest : 0,
},
};
};
export const findAllChatsStatus = ({ start, end, departmentId = undefined }) => Promise.await(findAllChatsStatusAsync({ start, end, departmentId }));
export const getProductivityMetrics = ({ start, end, departmentId = undefined }) => Promise.await(getProductivityMetricsAsync({ start, end, departmentId }));
export const getAgentsProductivityMetrics = ({ start, end, departmentId = undefined }) => Promise.await(getAgentsProductivityMetricsAsync({ start, end, departmentId }));
export const getConversationsMetrics = ({ start, end, departmentId = undefined }) => Promise.await(getConversationsMetricsAsync({ start, end, departmentId }));
export const findAllChatMetricsByAgent = ({ start, end, departmentId = undefined }) => Promise.await(findAllChatMetricsByAgentAsync({ start, end, departmentId }));
export const findAllChatMetricsByDepartment = ({ start, end, departmentId = undefined }) => Promise.await(findAllChatMetricsByDepartmentAsync({ start, end, departmentId }));
export const findAllResponseTimeMetrics = ({ start, end, departmentId = undefined }) => Promise.await(findAllResponseTimeMetricsAsync({ start, end, departmentId }));
export const getChatsMetrics = ({ start, end, departmentId = undefined }) => Promise.await(getChatsMetricsAsync({ start, end, departmentId }));
export const findAllAgentsStatus = ({ departmentId = undefined }) => Promise.await(findAllAgentsStatusAsync({ departmentId }));