Files
leadchat/app/javascript/dashboard/store/modules/reports.js
Shivam Mishra c88792f4a3 feat: add Conversation traffic heatmap (#6508)
* feat: add heatmap component

* feat: add heatmap component

* feat: add dummy heatmap

* refactor: compact tiles

* feat: allow hour

* feat: wire up heatmap query

* feat: allow arbritrary number of weeks

* feat: update position of the widget

* chore: update heatmap title

* refactor: move traffic heatmap to overview

* chore: add comment for perf

* feat: add reconcile logic for heatmap fetching

Fetching the data for the last 6 days all the time is wasteful
So we fetch only the data for today and reconcile it with the data we already have

* refactor: re-org code for new utils

* feat: add translations

* feat: translate days of the week

* chore: update chatwoot utils

* feat: add markers to heatmap

* refactor: update class names

* refactor: move flatten as a separate method

* test: Heatmap Helpers

* chore: add comments

* refactor: method naming

* refactor: use heatmap-level mixin

* refactor: cleanup css

* chore: remove log

* refactor: reports.js to use object instead of separate params

* refactor: report store to use new API design

* refactor: rename HeatmapHelper -> ReportsDataHelper

* refactor: separate clampDataBetweenTimeline

* feat: add tests

* fix: group by hour

* feat: add scroll for smaller screens

* refactor: add base data to reconcile with

* fix: tests

* fix: overflow only on smaller screens

* feat: translate tooltip

* refactor: simplify reconcile

* chore: add docs

* chore: remoev heatmap from account report

* feat: let Heatmap handle loading state

* chore: Apply suggestions from code review

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>

* feat: update css

* refactor: color assignment to range

* feat: add short circuit

* Update app/javascript/dashboard/routes/dashboard/settings/reports/components/Heatmap.vue

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2023-03-07 09:01:58 +05:30

220 lines
6.8 KiB
JavaScript

/* eslint no-console: 0 */
import * as types from '../mutation-types';
import Report from '../../api/reports';
import { downloadCsvFile } from '../../helper/downloadHelper';
import AnalyticsHelper from '../../helper/AnalyticsHelper';
import { REPORTS_EVENTS } from '../../helper/AnalyticsHelper/events';
import {
reconcileHeatmapData,
clampDataBetweenTimeline,
} from 'helpers/ReportsDataHelper';
const state = {
fetchingStatus: false,
reportData: [],
accountReport: {
isFetching: false,
data: [],
},
accountSummary: {
avg_first_response_time: 0,
avg_resolution_time: 0,
conversations_count: 0,
incoming_messages_count: 0,
outgoing_messages_count: 0,
resolutions_count: 0,
previous: {},
},
overview: {
uiFlags: {
isFetchingAccountConversationMetric: false,
isFetchingAccountConversationsHeatmap: false,
isFetchingAgentConversationMetric: false,
},
accountConversationMetric: {},
accountConversationHeatmap: [],
agentConversationMetric: [],
},
};
const getters = {
getAccountReports(_state) {
return _state.accountReport;
},
getAccountSummary(_state) {
return _state.accountSummary;
},
getAccountConversationMetric(_state) {
return _state.overview.accountConversationMetric;
},
getAccountConversationHeatmapData(_state) {
return _state.overview.accountConversationHeatmap;
},
getAgentConversationMetric(_state) {
return _state.overview.agentConversationMetric;
},
getOverviewUIFlags($state) {
return $state.overview.uiFlags;
},
};
export const actions = {
fetchAccountReport({ commit }, reportObj) {
commit(types.default.TOGGLE_ACCOUNT_REPORT_LOADING, true);
Report.getReports(reportObj).then(accountReport => {
let { data } = accountReport;
data = clampDataBetweenTimeline(data, reportObj.from, reportObj.to);
commit(types.default.SET_ACCOUNT_REPORTS, data);
commit(types.default.TOGGLE_ACCOUNT_REPORT_LOADING, false);
});
},
fetchAccountConversationHeatmap({ commit }, reportObj) {
commit(types.default.TOGGLE_HEATMAP_LOADING, true);
Report.getReports({ ...reportObj, group_by: 'hour' }).then(heatmapData => {
let { data } = heatmapData;
data = clampDataBetweenTimeline(data, reportObj.from, reportObj.to);
data = reconcileHeatmapData(
data,
state.overview.accountConversationHeatmap
);
commit(types.default.SET_HEATMAP_DATA, data);
commit(types.default.TOGGLE_HEATMAP_LOADING, false);
});
},
fetchAccountSummary({ commit }, reportObj) {
Report.getSummary(
reportObj.from,
reportObj.to,
reportObj.type,
reportObj.id,
reportObj.groupBy,
reportObj.businessHours
)
.then(accountSummary => {
commit(types.default.SET_ACCOUNT_SUMMARY, accountSummary.data);
})
.catch(() => {
commit(types.default.TOGGLE_ACCOUNT_REPORT_LOADING, false);
});
},
fetchAccountConversationMetric({ commit }, reportObj) {
commit(types.default.TOGGLE_ACCOUNT_CONVERSATION_METRIC_LOADING, true);
Report.getConversationMetric(reportObj.type)
.then(accountConversationMetric => {
commit(
types.default.SET_ACCOUNT_CONVERSATION_METRIC,
accountConversationMetric.data
);
commit(types.default.TOGGLE_ACCOUNT_CONVERSATION_METRIC_LOADING, false);
})
.catch(() => {
commit(types.default.TOGGLE_ACCOUNT_CONVERSATION_METRIC_LOADING, false);
});
},
fetchAgentConversationMetric({ commit }, reportObj) {
commit(types.default.TOGGLE_AGENT_CONVERSATION_METRIC_LOADING, true);
Report.getConversationMetric(reportObj.type, reportObj.page)
.then(agentConversationMetric => {
commit(
types.default.SET_AGENT_CONVERSATION_METRIC,
agentConversationMetric.data
);
commit(types.default.TOGGLE_AGENT_CONVERSATION_METRIC_LOADING, false);
})
.catch(() => {
commit(types.default.TOGGLE_AGENT_CONVERSATION_METRIC_LOADING, false);
});
},
downloadAgentReports(_, reportObj) {
return Report.getAgentReports(reportObj)
.then(response => {
downloadCsvFile(reportObj.fileName, response.data);
AnalyticsHelper.track(REPORTS_EVENTS.DOWNLOAD_REPORT, {
reportType: 'agent',
businessHours: reportObj?.businessHours,
});
})
.catch(error => {
console.error(error);
});
},
downloadLabelReports(_, reportObj) {
return Report.getLabelReports(reportObj)
.then(response => {
downloadCsvFile(reportObj.fileName, response.data);
AnalyticsHelper.track(REPORTS_EVENTS.DOWNLOAD_REPORT, {
reportType: 'label',
businessHours: reportObj?.businessHours,
});
})
.catch(error => {
console.error(error);
});
},
downloadInboxReports(_, reportObj) {
return Report.getInboxReports(reportObj)
.then(response => {
downloadCsvFile(reportObj.fileName, response.data);
AnalyticsHelper.track(REPORTS_EVENTS.DOWNLOAD_REPORT, {
reportType: 'inbox',
businessHours: reportObj?.businessHours,
});
})
.catch(error => {
console.error(error);
});
},
downloadTeamReports(_, reportObj) {
return Report.getTeamReports(reportObj)
.then(response => {
downloadCsvFile(reportObj.fileName, response.data);
AnalyticsHelper.track(REPORTS_EVENTS.DOWNLOAD_REPORT, {
reportType: 'team',
businessHours: reportObj?.businessHours,
});
})
.catch(error => {
console.error(error);
});
},
};
const mutations = {
[types.default.SET_ACCOUNT_REPORTS](_state, accountReport) {
_state.accountReport.data = accountReport;
},
[types.default.SET_HEATMAP_DATA](_state, heatmapData) {
_state.overview.accountConversationHeatmap = heatmapData;
},
[types.default.TOGGLE_ACCOUNT_REPORT_LOADING](_state, flag) {
_state.accountReport.isFetching = flag;
},
[types.default.TOGGLE_HEATMAP_LOADING](_state, flag) {
_state.overview.uiFlags.isFetchingAccountConversationsHeatmap = flag;
},
[types.default.SET_ACCOUNT_SUMMARY](_state, summaryData) {
_state.accountSummary = summaryData;
},
[types.default.SET_ACCOUNT_CONVERSATION_METRIC](_state, metricData) {
_state.overview.accountConversationMetric = metricData;
},
[types.default.TOGGLE_ACCOUNT_CONVERSATION_METRIC_LOADING](_state, flag) {
_state.overview.uiFlags.isFetchingAccountConversationMetric = flag;
},
[types.default.SET_AGENT_CONVERSATION_METRIC](_state, metricData) {
_state.overview.agentConversationMetric = metricData;
},
[types.default.TOGGLE_AGENT_CONVERSATION_METRIC_LOADING](_state, flag) {
_state.overview.uiFlags.isFetchingAgentConversationMetric = flag;
},
};
export default {
state,
getters,
actions,
mutations,
};