From e6f8895c1bfc1ef7dfb33f0b677bff8a0ff6218b Mon Sep 17 00:00:00 2001 From: "Aswin Dev P.S" Date: Tue, 15 Feb 2022 03:40:49 -0800 Subject: [PATCH] feat: Group by filter in reports (#3973) --- .codeclimate.yml | 1 + app/builders/v2/report_builder.rb | 14 ++- .../api/v2/accounts/reports_controller.rb | 6 +- app/javascript/dashboard/api/reports.js | 8 +- .../dashboard/i18n/locale/en/report.json | 19 ++++- .../settings/reports/CsatResponses.vue | 6 +- .../dashboard/settings/reports/Index.vue | 85 ++++++++++++++++--- ...teRangeSelector.vue => FilterSelector.vue} | 60 ++++++++++++- .../reports/components/ReportFilters.vue | 56 +++++++++++- .../reports/components/WootReports.vue | 66 ++++++++++++-- .../dashboard/settings/reports/constants.js | 6 ++ .../dashboard/store/modules/reports.js | 6 +- config/locales/en.yml | 1 + spec/builders/v2/report_builder_spec.rb | 44 ++++++++++ 14 files changed, 343 insertions(+), 35 deletions(-) rename app/javascript/dashboard/routes/dashboard/settings/reports/components/{DateRangeSelector.vue => FilterSelector.vue} (61%) create mode 100644 app/javascript/dashboard/routes/dashboard/settings/reports/constants.js diff --git a/.codeclimate.yml b/.codeclimate.yml index 2799086e3..c9910f9ed 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -49,3 +49,4 @@ exclude_patterns: - 'app/javascript/dashboard/routes/dashboard/contacts/contactFilterItems/index.js' - 'app/javascript/dashboard/routes/dashboard/settings/automation/constants.js' - 'app/javascript/dashboard/components/widgets/FilterInput/FilterOperatorTypes.js' + - 'app/javascript/dashboard/routes/dashboard/settings/reports/constants.js' diff --git a/app/builders/v2/report_builder.rb b/app/builders/v2/report_builder.rb index 82e6ce94c..c2900c7e6 100644 --- a/app/builders/v2/report_builder.rb +++ b/app/builders/v2/report_builder.rb @@ -2,6 +2,8 @@ class V2::ReportBuilder include DateRangeHelper attr_reader :account, :params + DEFAULT_GROUP_BY = 'day'.freeze + def initialize(account, params) @account = account @params = params @@ -64,26 +66,30 @@ class V2::ReportBuilder def conversations_count scope.conversations - .group_by_day(:created_at, range: range, default_value: 0) + .group_by_period(params[:group_by] || DEFAULT_GROUP_BY, + :created_at, range: range, default_value: 0, permit: %w[day week month year]) .count end def incoming_messages_count scope.messages.incoming.unscope(:order) - .group_by_day(:created_at, range: range, default_value: 0) + .group_by_period(params[:group_by] || DEFAULT_GROUP_BY, + :created_at, range: range, default_value: 0, permit: %w[day week month year]) .count end def outgoing_messages_count scope.messages.outgoing.unscope(:order) - .group_by_day(:created_at, range: range, default_value: 0) + .group_by_period(params[:group_by] || DEFAULT_GROUP_BY, + :created_at, range: range, default_value: 0, permit: %w[day week month year]) .count end def resolutions_count scope.conversations .resolved - .group_by_day(:created_at, range: range, default_value: 0) + .group_by_period(params[:group_by] || DEFAULT_GROUP_BY, + :created_at, range: range, default_value: 0, permit: %w[day week month year]) .count end diff --git a/app/controllers/api/v2/accounts/reports_controller.rb b/app/controllers/api/v2/accounts/reports_controller.rb index 4fabd587e..9801d760d 100644 --- a/app/controllers/api/v2/accounts/reports_controller.rb +++ b/app/controllers/api/v2/accounts/reports_controller.rb @@ -46,7 +46,8 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController type: params[:type].to_sym, since: params[:since], until: params[:until], - id: params[:id] + id: params[:id], + group_by: params[:group_by] } end @@ -56,7 +57,8 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController type: params[:type].to_sym, since: params[:since], until: params[:until], - id: params[:id] + id: params[:id], + group_by: params[:group_by] } end diff --git a/app/javascript/dashboard/api/reports.js b/app/javascript/dashboard/api/reports.js index faeee779f..dbb2bf08d 100644 --- a/app/javascript/dashboard/api/reports.js +++ b/app/javascript/dashboard/api/reports.js @@ -6,15 +6,15 @@ class ReportsAPI extends ApiClient { super('reports', { accountScoped: true, apiVersion: 'v2' }); } - getReports(metric, since, until, type = 'account', id) { + getReports(metric, since, until, type = 'account', id, group_by) { return axios.get(`${this.url}`, { - params: { metric, since, until, type, id }, + params: { metric, since, until, type, id, group_by }, }); } - getSummary(since, until, type = 'account', id) { + getSummary(since, until, type = 'account', id, group_by) { return axios.get(`${this.url}/summary`, { - params: { since, until, type, id }, + params: { since, until, type, id, group_by }, }); } diff --git a/app/javascript/dashboard/i18n/locale/en/report.json b/app/javascript/dashboard/i18n/locale/en/report.json index 4afd63b61..229c7b068 100644 --- a/app/javascript/dashboard/i18n/locale/en/report.json +++ b/app/javascript/dashboard/i18n/locale/en/report.json @@ -59,7 +59,24 @@ "CUSTOM_DATE_RANGE": { "CONFIRM": "Apply", "PLACEHOLDER": "Select date range" - } + }, + "GROUP_BY_FILTER_DROPDOWN_LABEL": "Group By", + "GROUP_BY_DAY_OPTIONS": [{ "id": 1, "groupBy": "Day" }], + "GROUP_BY_WEEK_OPTIONS": [ + { "id": 1, "groupBy": "Day" }, + { "id": 2, "groupBy": "Week" } + ], + "GROUP_BY_MONTH_OPTIONS": [ + { "id": 1, "groupBy": "Day" }, + { "id": 2, "groupBy": "Week" }, + { "id": 3, "groupBy": "Month" } + ], + "GROUP_BY_YEAR_OPTIONS": [ + { "id": 1, "groupBy": "Day" }, + { "id": 2, "groupBy": "Week" }, + { "id": 3, "groupBy": "Month" }, + { "id": 4, "groupBy": "Year" } + ] }, "AGENT_REPORTS": { "HEADER": "Agents Overview", diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/CsatResponses.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/CsatResponses.vue index 184d85a99..b893b763e 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/reports/CsatResponses.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/reports/CsatResponses.vue @@ -1,6 +1,6 @@ diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/components/ReportFilters.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/components/ReportFilters.vue index 46071f450..28321cdba 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/reports/components/ReportFilters.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/reports/components/ReportFilters.vue @@ -127,6 +127,24 @@ :placeholder="$t('REPORT.CUSTOM_DATE_RANGE.PLACEHOLDER')" @change="onChange" /> +
+ + +
diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/components/WootReports.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/components/WootReports.vue index 6b26f94b9..449b0383f 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/reports/components/WootReports.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/reports/components/WootReports.vue @@ -12,8 +12,11 @@ v-if="filterItemsList" :type="type" :filter-items-list="filterItemsList" + :group-by-filter-items-list="groupByfilterItemsList" + :selected-group-by-filter="selectedGroupByFilter" @date-range-change="onDateRangeChange" @filter-change="onFilterChange" + @group-by-filter-change="onGroupByFilterChange" />
@@ -51,6 +54,7 @@ import ReportFilters from './ReportFilters'; import fromUnixTime from 'date-fns/fromUnixTime'; import format from 'date-fns/format'; +import { GROUP_BY_FILTER } from '../constants'; const REPORTS_KEYS = { CONVERSATIONS: 'conversations_count', @@ -88,6 +92,9 @@ export default { to: 0, currentSelection: 0, selectedFilter: null, + groupBy: GROUP_BY_FILTER[1], + groupByfilterItemsList: this.$t('REPORT.GROUP_BY_DAY_OPTIONS'), + selectedGroupByFilter: null, }; }, computed: { @@ -105,9 +112,28 @@ export default { return {}; } if (!this.accountReport.data.length) return {}; - const labels = this.accountReport.data.map(element => - format(fromUnixTime(element.timestamp), 'dd/MMM') - ); + const labels = this.accountReport.data.map(element => { + if (this.groupBy.period === GROUP_BY_FILTER[2].period) { + let week_date = new Date(fromUnixTime(element.timestamp)); + const first_day = week_date.getDate() - week_date.getDay(); + const last_day = first_day + 6; + + const week_first_date = new Date(week_date.setDate(first_day)); + const week_last_date = new Date(week_date.setDate(last_day)); + + return `${format(week_first_date, 'dd/MM/yy')} - ${format( + week_last_date, + 'dd/MM/yy' + )}`; + } + if (this.groupBy.period === GROUP_BY_FILTER[3].period) { + return format(fromUnixTime(element.timestamp), 'MMM-yyyy'); + } + if (this.groupBy.period === GROUP_BY_FILTER[4].period) { + return format(fromUnixTime(element.timestamp), 'yyyy'); + } + return format(fromUnixTime(element.timestamp), 'dd-MMM-yyyy'); + }); const data = this.accountReport.data.map(element => element.value); return { labels, @@ -148,24 +174,26 @@ export default { methods: { fetchAllData() { if (this.selectedFilter) { - const { from, to } = this; + const { from, to, groupBy } = this; this.$store.dispatch('fetchAccountSummary', { from, to, type: this.type, id: this.selectedFilter.id, + groupBy: groupBy.period, }); this.fetchChartData(); } }, fetchChartData() { - const { from, to } = this; + const { from, to, groupBy } = this; this.$store.dispatch('fetchAccountReport', { metric: this.metrics[this.currentSelection].KEY, from, to, type: this.type, id: this.selectedFilter.id, + groupBy: groupBy.period, }); }, downloadReports() { @@ -195,9 +223,19 @@ export default { this.currentSelection = index; this.fetchChartData(); }, - onDateRangeChange({ from, to }) { + onDateRangeChange({ from, to, groupBy }) { this.from = from; this.to = to; + this.groupByfilterItemsList = this.fetchFilterItems(groupBy); + const filterItems = this.groupByfilterItemsList.filter( + item => item.id === this.groupBy.id + ); + if (filterItems.length > 0) { + this.selectedGroupByFilter = filterItems[0]; + } else { + this.selectedGroupByFilter = this.groupByfilterItemsList[0]; + this.groupBy = GROUP_BY_FILTER[this.selectedGroupByFilter.id]; + } this.fetchAllData(); }, onFilterChange(payload) { @@ -206,6 +244,22 @@ export default { this.fetchAllData(); } }, + onGroupByFilterChange(payload) { + this.groupBy = GROUP_BY_FILTER[payload.id]; + this.fetchAllData(); + }, + fetchFilterItems(group_by) { + switch (group_by) { + case GROUP_BY_FILTER[2].period: + return this.$t('REPORT.GROUP_BY_WEEK_OPTIONS'); + case GROUP_BY_FILTER[3].period: + return this.$t('REPORT.GROUP_BY_MONTH_OPTIONS'); + case GROUP_BY_FILTER[4].period: + return this.$t('REPORT.GROUP_BY_YEAR_OPTIONS'); + default: + return this.$t('REPORT.GROUP_BY_DAY_OPTIONS'); + } + }, }, }; diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/constants.js b/app/javascript/dashboard/routes/dashboard/settings/reports/constants.js new file mode 100644 index 000000000..f285061cb --- /dev/null +++ b/app/javascript/dashboard/routes/dashboard/settings/reports/constants.js @@ -0,0 +1,6 @@ +export const GROUP_BY_FILTER = { + 1: { id: 1, period: 'day' }, + 2: { id: 2, period: 'week' }, + 3: { id: 3, period: 'month' }, + 4: { id: 4, period: 'year' }, +}; diff --git a/app/javascript/dashboard/store/modules/reports.js b/app/javascript/dashboard/store/modules/reports.js index 87050bcef..027b2388a 100644 --- a/app/javascript/dashboard/store/modules/reports.js +++ b/app/javascript/dashboard/store/modules/reports.js @@ -43,7 +43,8 @@ export const actions = { reportObj.from, reportObj.to, reportObj.type, - reportObj.id + reportObj.id, + reportObj.groupBy ).then(accountReport => { let { data } = accountReport; data = data.filter( @@ -68,7 +69,8 @@ export const actions = { reportObj.from, reportObj.to, reportObj.type, - reportObj.id + reportObj.id, + reportObj.groupBy ) .then(accountSummary => { commit(types.default.SET_ACCOUNT_SUMMARY, accountSummary.data); diff --git a/config/locales/en.yml b/config/locales/en.yml index 0804fbcd9..c52b660e8 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -57,6 +57,7 @@ en: conversations_count: Conversations count avg_first_response_time: Avg first response time (Minutes) avg_resolution_time: Avg resolution time (Minutes) + default_group_by: day notifications: notification_title: diff --git a/spec/builders/v2/report_builder_spec.rb b/spec/builders/v2/report_builder_spec.rb index bcf02f1d8..16fe18f49 100644 --- a/spec/builders/v2/report_builder_spec.rb +++ b/spec/builders/v2/report_builder_spec.rb @@ -147,6 +147,18 @@ describe ::V2::ReportBuilder do expect(metrics[:avg_resolution_time]).to be 0 expect(metrics[:resolutions_count]).to be 0 end + + it 'returns argument error for incorrect group by' do + params = { + type: :account, + since: (Time.zone.today - 3.days).to_time.to_i.to_s, + until: Time.zone.today.to_time.to_i.to_s, + group_by: 'test'.to_s + } + + builder = V2::ReportBuilder.new(account, params) + expect { builder.summary }.to raise_error(ArgumentError) + end end context 'when report type is label' do @@ -247,6 +259,38 @@ describe ::V2::ReportBuilder do expect(metrics[:avg_resolution_time]).to be 0 expect(metrics[:resolutions_count]).to be 0 end + + it 'returns summary for correct group by' do + params = { + type: :label, + id: label_2.id, + since: (Time.zone.today - 3.days).to_time.to_i.to_s, + until: Time.zone.today.to_time.to_i.to_s, + group_by: 'week'.to_s + } + + builder = V2::ReportBuilder.new(account, params) + metrics = builder.summary + + expect(metrics[:conversations_count]).to be 5 + expect(metrics[:incoming_messages_count]).to be 5 + expect(metrics[:outgoing_messages_count]).to be 15 + expect(metrics[:avg_resolution_time]).to be 0 + expect(metrics[:resolutions_count]).to be 0 + end + + it 'returns argument error for incorrect group by' do + params = { + type: :label, + id: label_2.id, + since: (Time.zone.today - 3.days).to_time.to_i.to_s, + until: Time.zone.today.to_time.to_i.to_s, + group_by: 'test'.to_s + } + + builder = V2::ReportBuilder.new(account, params) + expect { builder.summary }.to raise_error(ArgumentError) + end end end end