diff --git a/app/javascript/dashboard/api/reports.js b/app/javascript/dashboard/api/reports.js
index 987b69701..52fa7f444 100644
--- a/app/javascript/dashboard/api/reports.js
+++ b/app/javascript/dashboard/api/reports.js
@@ -84,6 +84,24 @@ class ReportsAPI extends ApiClient {
params: { since, until, business_hours: businessHours },
});
}
+
+ getBotMetrics({ from, to } = {}) {
+ return axios.get(`${this.url}/bot_metrics`, {
+ params: { since: from, until: to },
+ });
+ }
+
+ getBotSummary({ from, to, groupBy, businessHours } = {}) {
+ return axios.get(`${this.url}/bot_summary`, {
+ params: {
+ since: from,
+ until: to,
+ type: 'account',
+ group_by: groupBy,
+ business_hours: businessHours,
+ },
+ });
+ }
}
export default new ReportsAPI();
diff --git a/app/javascript/dashboard/api/specs/reports.spec.js b/app/javascript/dashboard/api/specs/reports.spec.js
index 7822dad8f..05d4a152c 100644
--- a/app/javascript/dashboard/api/specs/reports.spec.js
+++ b/app/javascript/dashboard/api/specs/reports.spec.js
@@ -111,6 +111,40 @@ describe('#Reports API', () => {
});
});
+ it('#getBotMetrics', () => {
+ reportsAPI.getBotMetrics({ from: 1621103400, to: 1621621800 });
+ expect(axiosMock.get).toHaveBeenCalledWith(
+ '/api/v2/reports/bot_metrics',
+ {
+ params: {
+ since: 1621103400,
+ until: 1621621800,
+ },
+ }
+ );
+ });
+
+ it('#getBotSummary', () => {
+ reportsAPI.getBotSummary({
+ from: 1621103400,
+ to: 1621621800,
+ groupBy: 'date',
+ businessHours: true,
+ });
+ expect(axiosMock.get).toHaveBeenCalledWith(
+ '/api/v2/reports/bot_summary',
+ {
+ params: {
+ since: 1621103400,
+ until: 1621621800,
+ type: 'account',
+ group_by: 'date',
+ business_hours: true,
+ },
+ }
+ );
+ });
+
it('#getConversationMetric', () => {
reportsAPI.getConversationMetric('account');
expect(axiosMock.get).toHaveBeenCalledWith(
diff --git a/app/javascript/dashboard/components/layout/config/sidebarItems/reports.js b/app/javascript/dashboard/components/layout/config/sidebarItems/reports.js
index 967ee44ed..551256c74 100644
--- a/app/javascript/dashboard/components/layout/config/sidebarItems/reports.js
+++ b/app/javascript/dashboard/components/layout/config/sidebarItems/reports.js
@@ -1,3 +1,4 @@
+import { FEATURE_FLAGS } from '../../../../featureFlags';
import { frontendURL } from '../../../../helper/URLHelper';
const reports = accountId => ({
@@ -6,6 +7,7 @@ const reports = accountId => ({
'account_overview_reports',
'conversation_reports',
'csat_reports',
+ 'bot_reports',
'agent_reports',
'label_reports',
'inbox_reports',
@@ -33,6 +35,14 @@ const reports = accountId => ({
toState: frontendURL(`accounts/${accountId}/reports/csat`),
toStateName: 'csat_reports',
},
+ {
+ icon: 'bot',
+ label: 'REPORTS_BOT',
+ hasSubMenu: false,
+ featureFlag: FEATURE_FLAGS.RESPONSE_BOT,
+ toState: frontendURL(`accounts/${accountId}/reports/bot`),
+ toStateName: 'bot_reports',
+ },
{
icon: 'people',
label: 'REPORTS_AGENT',
diff --git a/app/javascript/dashboard/featureFlags.js b/app/javascript/dashboard/featureFlags.js
index 2936d22ea..f2fd3e757 100644
--- a/app/javascript/dashboard/featureFlags.js
+++ b/app/javascript/dashboard/featureFlags.js
@@ -19,4 +19,5 @@ export const FEATURE_FLAGS = {
INSERT_ARTICLE_IN_REPLY: 'insert_article_in_reply',
INBOX_VIEW: 'inbox_view',
SLA: 'sla',
+ RESPONSE_BOT: 'response_bot',
};
diff --git a/app/javascript/dashboard/i18n/locale/en/report.json b/app/javascript/dashboard/i18n/locale/en/report.json
index a6d476bc9..56ca21773 100644
--- a/app/javascript/dashboard/i18n/locale/en/report.json
+++ b/app/javascript/dashboard/i18n/locale/en/report.json
@@ -35,6 +35,14 @@
"NAME": "Resolution Count",
"DESC": "( Total )"
},
+ "BOT_RESOLUTION_COUNT": {
+ "NAME": "Resolution Count",
+ "DESC": "( Total )"
+ },
+ "BOT_HANDOFF_COUNT": {
+ "NAME": "Handoff Count",
+ "DESC": "( Total )"
+ },
"REPLY_TIME": {
"NAME": "Customer waiting time",
"TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)"
@@ -86,20 +94,49 @@
"MONTH": "Month",
"YEAR": "Year"
},
- "GROUP_BY_DAY_OPTIONS": [{ "id": 1, "groupBy": "Day" }],
+ "GROUP_BY_DAY_OPTIONS": [
+ {
+ "id": 1,
+ "groupBy": "Day"
+ }
+ ],
"GROUP_BY_WEEK_OPTIONS": [
- { "id": 1, "groupBy": "Day" },
- { "id": 2, "groupBy": "Week" }
+ {
+ "id": 1,
+ "groupBy": "Day"
+ },
+ {
+ "id": 2,
+ "groupBy": "Week"
+ }
],
"GROUP_BY_MONTH_OPTIONS": [
- { "id": 1, "groupBy": "Day" },
- { "id": 2, "groupBy": "Week" },
- { "id": 3, "groupBy": "Month" }
+ {
+ "id": 1,
+ "groupBy": "Day"
+ },
+ {
+ "id": 2,
+ "groupBy": "Week"
+ },
+ {
+ "id": 3,
+ "groupBy": "Month"
+ }
],
"GROUP_BY_YEAR_OPTIONS": [
- { "id": 2, "groupBy": "Week" },
- { "id": 3, "groupBy": "Month" },
- { "id": 4, "groupBy": "Year" }
+ {
+ "id": 2,
+ "groupBy": "Week"
+ },
+ {
+ "id": 3,
+ "groupBy": "Month"
+ },
+ {
+ "id": 4,
+ "groupBy": "Year"
+ }
],
"BUSINESS_HOURS": "Business Hours"
},
@@ -404,6 +441,27 @@
}
}
},
+ "BOT_REPORTS": {
+ "HEADER": "Bot Reports",
+ "METRIC": {
+ "TOTAL_CONVERSATIONS": {
+ "LABEL": "No. of Conversations",
+ "TOOLTIP": "Total number of conversations handled by the bot"
+ },
+ "TOTAL_RESPONSES": {
+ "LABEL": "Total Responses",
+ "TOOLTIP": "Total number of responses sent by the bot"
+ },
+ "RESOLUTION_RATE": {
+ "LABEL": "Resolution Rate",
+ "TOOLTIP": "Total number of conversations resolved by the bot / Total number of conversations handled by the bot * 100"
+ },
+ "HANDOFF_RATE": {
+ "LABEL": "Handoff Rate",
+ "TOOLTIP": "Total number of conversations handed off to agents / Total number of conversations handled by the bot * 100"
+ }
+ }
+ },
"OVERVIEW_REPORTS": {
"HEADER": "Overview",
"LIVE": "Live",
diff --git a/app/javascript/dashboard/i18n/locale/en/settings.json b/app/javascript/dashboard/i18n/locale/en/settings.json
index 63725f949..9a4bde2c8 100644
--- a/app/javascript/dashboard/i18n/locale/en/settings.json
+++ b/app/javascript/dashboard/i18n/locale/en/settings.json
@@ -234,6 +234,7 @@
"CAMPAIGNS": "Campaigns",
"ONGOING": "Ongoing",
"ONE_OFF": "One off",
+ "REPORTS_BOT": "Bot",
"REPORTS_AGENT": "Agents",
"REPORTS_LABEL": "Labels",
"REPORTS_INBOX": "Inbox",
diff --git a/app/javascript/dashboard/mixins/reportMixin.js b/app/javascript/dashboard/mixins/reportMixin.js
index 2b8a5f87d..d57af1ad2 100644
--- a/app/javascript/dashboard/mixins/reportMixin.js
+++ b/app/javascript/dashboard/mixins/reportMixin.js
@@ -2,11 +2,19 @@ import { mapGetters } from 'vuex';
import { formatTime } from '@chatwoot/utils';
export default {
+ props: {
+ accountSummaryKey: {
+ type: String,
+ default: 'getAccountSummary',
+ },
+ },
computed: {
...mapGetters({
- accountSummary: 'getAccountSummary',
accountReport: 'getAccountReports',
}),
+ accountSummary() {
+ return this.$store.getters[this.accountSummaryKey];
+ },
},
methods: {
calculateTrend(key) {
diff --git a/app/javascript/dashboard/mixins/specs/reportMixin.spec.js b/app/javascript/dashboard/mixins/specs/reportMixin.spec.js
index d981de4e9..c0bc1e15f 100644
--- a/app/javascript/dashboard/mixins/specs/reportMixin.spec.js
+++ b/app/javascript/dashboard/mixins/specs/reportMixin.spec.js
@@ -11,11 +11,42 @@ describe('reportMixin', () => {
beforeEach(() => {
getters = {
getAccountSummary: () => reportFixtures.summary,
+ getBotSummary: () => reportFixtures.botSummary,
getAccountReports: () => reportFixtures.report,
};
store = new Vuex.Store({ getters });
});
+ it('display the metric for account', async () => {
+ const Component = {
+ render() {},
+ title: 'TestComponent',
+ mixins: [reportMixin],
+ };
+ const wrapper = shallowMount(Component, { store, localVue });
+ await wrapper.setProps({
+ accountSummaryKey: 'getAccountSummary',
+ });
+ expect(wrapper.vm.displayMetric('conversations_count')).toEqual('5,000');
+ expect(wrapper.vm.displayMetric('avg_first_response_time')).toEqual(
+ '3 Min 18 Sec'
+ );
+ });
+
+ it('display the metric for bot', async () => {
+ const Component = {
+ render() {},
+ title: 'TestComponent',
+ mixins: [reportMixin],
+ };
+ const wrapper = shallowMount(Component, { store, localVue });
+ await wrapper.setProps({
+ accountSummaryKey: 'getBotSummary',
+ });
+ expect(wrapper.vm.displayMetric('bot_resolutions_count')).toEqual('10');
+ expect(wrapper.vm.displayMetric('bot_handoffs_count')).toEqual('20');
+ });
+
it('display the metric', () => {
const Component = {
render() {},
diff --git a/app/javascript/dashboard/mixins/specs/reportMixinFixtures.js b/app/javascript/dashboard/mixins/specs/reportMixinFixtures.js
index ab6b6fecf..591bf7c1f 100644
--- a/app/javascript/dashboard/mixins/specs/reportMixinFixtures.js
+++ b/app/javascript/dashboard/mixins/specs/reportMixinFixtures.js
@@ -15,6 +15,14 @@ export default {
},
resolutions_count: 3,
},
+ botSummary: {
+ bot_resolutions_count: 10,
+ bot_handoffs_count: 20,
+ previous: {
+ bot_resolutions_count: 8,
+ bot_handoffs_count: 5,
+ },
+ },
report: {
data: [
{ value: '0.00', timestamp: 1647541800, count: 0 },
diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/BotReports.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/BotReports.vue
new file mode 100644
index 000000000..a75051aaf
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/reports/BotReports.vue
@@ -0,0 +1,106 @@
+
+