From b235d66f813e45588745686ce6b568c2f51b9b73 Mon Sep 17 00:00:00 2001 From: Pranav Date: Wed, 5 Feb 2025 19:13:24 -0800 Subject: [PATCH] Add liveagentreports --- .../v2/accounts/live_reports_controller.rb | 57 ++++++++ app/javascript/dashboard/api/liveReports.js | 20 +++ .../settings/reports/LiveReports.vue | 45 +----- .../components/AgentLiveReportContainer.vue | 36 +++++ .../components/overview/AgentTable.vue | 134 +++++------------- .../dashboard/store/modules/reports.js | 6 +- config/routes.rb | 6 + 7 files changed, 162 insertions(+), 142 deletions(-) create mode 100644 app/controllers/api/v2/accounts/live_reports_controller.rb create mode 100644 app/javascript/dashboard/api/liveReports.js create mode 100644 app/javascript/dashboard/routes/dashboard/settings/reports/components/AgentLiveReportContainer.vue diff --git a/app/controllers/api/v2/accounts/live_reports_controller.rb b/app/controllers/api/v2/accounts/live_reports_controller.rb new file mode 100644 index 000000000..27a06a66d --- /dev/null +++ b/app/controllers/api/v2/accounts/live_reports_controller.rb @@ -0,0 +1,57 @@ +class Api::V2::Accounts::LiveReportsController < Api::V1::Accounts::BaseController + before_action :load_conversations, only: [:conversation_metrics, :grouped_conversation_metrics] + before_action :set_group_scope, only: [:grouped_conversation_metrics] + + def conversation_metrics + render json: { + open: @conversations.open.count, + unattended: @conversations.open.unattended.count, + unassigned: @conversations.open.unassigned.count + } + end + + def grouped_conversation_metrics + count_by_group = @conversations.open.group(@group_scope).count + unattended_by_group = @conversations.open.unattended.group(@group_scope).count + unassigned_by_group = @conversations.open.unassigned.group(@group_scope).count + + group_metrics = count_by_group.map do |group_id, count| + metric = { + open: count, + unattended: unattended_by_group[group_id] || 0, + unassigned: unassigned_by_group[group_id] || 0 + } + metric[@group_scope] = group_id + metric + end + + render json: group_metrics + end + + private + + def set_group_scope + render json: { error: 'invalid group_by' }, status: :unprocessable_entity and return unless %w[ + team_id + assignee_id + ].include?(permitted_params[:group_by]) + + @group_scope = permitted_params[:group_by] + end + + def team + return unless permitted_params[:team_id] + + @team ||= Current.account.teams.find(permitted_params[:team_id]) + end + + def load_conversations + scope = Current.account.conversations + scope = scope.where(team_id: team.id) if team.present? + @conversations = scope + end + + def permitted_params + params.permit(:team_id, :group_by) + end +end diff --git a/app/javascript/dashboard/api/liveReports.js b/app/javascript/dashboard/api/liveReports.js new file mode 100644 index 000000000..1435da258 --- /dev/null +++ b/app/javascript/dashboard/api/liveReports.js @@ -0,0 +1,20 @@ +/* global axios */ +import ApiClient from './ApiClient'; + +class LiveReportsAPI extends ApiClient { + constructor() { + super('live_reports', { accountScoped: true, apiVersion: 'v2' }); + } + + getConversationMetric(params = {}) { + return axios.get(`${this.url}/conversation_metrics`, { params }); + } + + getGroupedConversations({ groupBy } = { groupBy: 'assignee_id' }) { + return axios.get(`${this.url}/grouped_conversation_metrics`, { + params: { group_by: groupBy }, + }); + } +} + +export default new LiveReportsAPI(); diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/LiveReports.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/LiveReports.vue index 3e343fd05..6ccb4351d 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/reports/LiveReports.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/reports/LiveReports.vue @@ -1,22 +1,20 @@ @@ -115,9 +91,8 @@ export default {
-
- - - -
+ diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/components/AgentLiveReportContainer.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/components/AgentLiveReportContainer.vue new file mode 100644 index 000000000..e274e4fe2 --- /dev/null +++ b/app/javascript/dashboard/routes/dashboard/settings/reports/components/AgentLiveReportContainer.vue @@ -0,0 +1,36 @@ + + + diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/components/overview/AgentTable.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/components/overview/AgentTable.vue index fb470d8fc..20a97c9d8 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/reports/components/overview/AgentTable.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/reports/components/overview/AgentTable.vue @@ -4,6 +4,7 @@ import { useVueTable, createColumnHelper, getCoreRowModel, + getPaginationRowModel, } from '@tanstack/vue-table'; import { useI18n } from 'vue-i18n'; @@ -13,7 +14,7 @@ import Table from 'dashboard/components/table/Table.vue'; import Pagination from 'dashboard/components/table/Pagination.vue'; import AgentCell from './AgentCell.vue'; -const { agents, agentMetrics, pageIndex } = defineProps({ +const { agents, agentMetrics } = defineProps({ agents: { type: Array, default: () => [], @@ -26,36 +27,36 @@ const { agents, agentMetrics, pageIndex } = defineProps({ type: Boolean, default: false, }, - pageIndex: { - type: Number, - default: 1, - }, }); -const emit = defineEmits(['pageChange']); const { t } = useI18n(); -function getAgentInformation(id) { - return agents?.find(agent => agent.id === Number(id)); -} +const getAgentMetrics = id => + agentMetrics.find(metrics => metrics.assignee_id === Number(id)) || {}; -const totalCount = computed(() => agents.length); - -const tableData = computed(() => { - return agentMetrics - .filter(agentMetric => getAgentInformation(agentMetric.id)) +const tableData = computed(() => + agents .map(agent => { - const agentInformation = getAgentInformation(agent.id); + const metric = getAgentMetrics(agent.id); return { - agent: agentInformation.name || agentInformation.available_name, - email: agentInformation.email, - thumbnail: agentInformation.thumbnail, - open: agent.metric.open ?? 0, - unattended: agent.metric.unattended ?? 0, - status: agentInformation.availability_status, + agent: agent.available_name || agent.name, + email: agent.email, + thumbnail: agent.thumbnail, + open: metric.open || 0, + unattended: metric.unattended || 0, + status: agent.availability_status, }; - }); -}); + }) + .sort((a, b) => { + // First sort by open tickets (descending) + const openDiff = b.open - a.open; + // If open tickets are equal, sort by name (ascending) + if (openDiff === 0) { + return a.agent.localeCompare(b.agent); + } + return openDiff; + }) +); const defaulSpanRender = cellProps => h( @@ -86,100 +87,33 @@ const columns = [ }), ]; -const paginationParams = computed(() => { - return { - pageIndex: pageIndex, - pageSize: 25, - }; -}); - const table = useVueTable({ get data() { return tableData.value; }, columns, - manualPagination: true, enableSorting: false, getCoreRowModel: getCoreRowModel(), - get rowCount() { - return totalCount.value; - }, - state: { - get pagination() { - return paginationParams.value; - }, - }, - onPaginationChange: updater => { - const newPagintaion = updater(paginationParams.value); - emit('pageChange', newPagintaion.pageIndex); - }, + getPaginationRowModel: getPaginationRowModel(), }); - - diff --git a/app/javascript/dashboard/store/modules/reports.js b/app/javascript/dashboard/store/modules/reports.js index 74da87d32..4d3430daa 100644 --- a/app/javascript/dashboard/store/modules/reports.js +++ b/app/javascript/dashboard/store/modules/reports.js @@ -5,6 +5,7 @@ import { downloadCsvFile, generateFileName } from '../../helper/downloadHelper'; import AnalyticsHelper from '../../helper/AnalyticsHelper'; import { REPORTS_EVENTS } from '../../helper/AnalyticsHelper/events'; import { clampDataBetweenTimeline } from 'shared/helpers/ReportsDataHelper'; +import liveReports from '../../api/liveReports'; const state = { fetchingStatus: false, @@ -159,9 +160,10 @@ export const actions = { commit(types.default.TOGGLE_ACCOUNT_CONVERSATION_METRIC_LOADING, false); }); }, - fetchAgentConversationMetric({ commit }, reportObj) { + fetchAgentConversationMetric({ commit }) { commit(types.default.TOGGLE_AGENT_CONVERSATION_METRIC_LOADING, true); - Report.getConversationMetric(reportObj.type, reportObj.page) + liveReports + .getGroupedConversations({ groupBy: 'assignee_id' }) .then(agentConversationMetric => { commit( types.default.SET_AGENT_CONVERSATION_METRIC, diff --git a/config/routes.rb b/config/routes.rb index ebb3804cb..7df6d33a7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -336,6 +336,12 @@ Rails.application.routes.draw do get :bot_metrics end end + resources :live_reports, only: [] do + collection do + get :conversation_metrics + get :grouped_conversation_metrics + end + end end end end