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 @@
-
+
@@ -8,14 +8,14 @@
diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/components/DateRangeSelector.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/components/FilterSelector.vue
similarity index 61%
rename from app/javascript/dashboard/routes/dashboard/settings/reports/components/DateRangeSelector.vue
rename to app/javascript/dashboard/routes/dashboard/settings/reports/components/FilterSelector.vue
index a3e45ade1..2a1884bac 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/reports/components/DateRangeSelector.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/reports/components/FilterSelector.vue
@@ -23,6 +23,24 @@
:placeholder="$t('REPORT.CUSTOM_DATE_RANGE.PLACEHOLDER')"
@change="onChange"
/>
+
+
+ {{ $t('REPORT.GROUP_BY_FILTER_DROPDOWN_LABEL') }}
+
+
+
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"
/>
+
+
+ {{ $t('REPORT.GROUP_BY_FILTER_DROPDOWN_LABEL') }}
+
+
+
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