Commit
This commit is contained in:
@@ -6,7 +6,7 @@ class SummaryReportsAPI extends ApiClient {
|
||||
super('summary_reports', { accountScoped: true, apiVersion: 'v2' });
|
||||
}
|
||||
|
||||
getTeamReports({ since, until, businessHours }) {
|
||||
getTeamReports({ since, until, businessHours } = {}) {
|
||||
return axios.get(`${this.url}/team`, {
|
||||
params: {
|
||||
since,
|
||||
@@ -16,7 +16,7 @@ class SummaryReportsAPI extends ApiClient {
|
||||
});
|
||||
}
|
||||
|
||||
getAgentReports({ since, until, businessHours }) {
|
||||
getAgentReports({ since, until, businessHours } = {}) {
|
||||
return axios.get(`${this.url}/agents`, {
|
||||
params: {
|
||||
since,
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
<template>
|
||||
<div class="overflow-auto">
|
||||
<metric-card :is-live="false" header="Team wise reports" />
|
||||
<metric-card :is-live="false" header="Team wise reports">
|
||||
<metric-card :is-live="false" header="All teams overview">
|
||||
<team-list-table />
|
||||
</metric-card>
|
||||
<metric-card
|
||||
:is-live="false"
|
||||
header="Team wise reports"
|
||||
class="overflow-visible"
|
||||
>
|
||||
<woot-reports
|
||||
key="team-reports"
|
||||
class="!p-0"
|
||||
@@ -15,6 +21,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TeamListTable from './components/AggregateTables/TeamListTable.vue';
|
||||
import WootReports from './components/WootReports.vue';
|
||||
import MetricCard from './components/overview/MetricCard.vue';
|
||||
|
||||
@@ -22,6 +29,7 @@ export default {
|
||||
components: {
|
||||
WootReports,
|
||||
MetricCard,
|
||||
TeamListTable,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<div class="agent-table-container">
|
||||
<ve-table
|
||||
max-height="calc(100vh - 21.875rem)"
|
||||
:fixed-header="true"
|
||||
:columns="columns"
|
||||
:table-data="tableData"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { VeTable } from 'vue-easytable';
|
||||
import rtlMixin from 'shared/mixins/rtlMixin';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'TeamTable',
|
||||
components: {
|
||||
VeTable,
|
||||
},
|
||||
mixins: [rtlMixin],
|
||||
computed: {
|
||||
...mapGetters({
|
||||
teams: 'teams/getTeams',
|
||||
teamMetrics: 'summaryReports/getTeamSummaryReports',
|
||||
}),
|
||||
tableData() {
|
||||
return this.teams.map(team => {
|
||||
const teamMetrics = this.getTeamMetrics(team.id);
|
||||
return {
|
||||
name: team.name,
|
||||
conversationsCount: teamMetrics.open || 0,
|
||||
avgFirstResponseTime: teamMetrics.open || 0,
|
||||
avgResolutionTime: teamMetrics.open || 0,
|
||||
resolutionsCount: teamMetrics.open || 0,
|
||||
};
|
||||
});
|
||||
},
|
||||
columns() {
|
||||
return [
|
||||
{
|
||||
field: 'agent',
|
||||
key: 'agent',
|
||||
title: 'Team',
|
||||
fixed: 'left',
|
||||
align: this.isRTLView ? 'right' : 'left',
|
||||
width: 25,
|
||||
renderBodyCell: ({ row }) => (
|
||||
<div class="row-user-block">
|
||||
<div class="user-block">
|
||||
<h6 class="title overflow-hidden whitespace-nowrap text-ellipsis">
|
||||
{row.name}
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'conversationsCount',
|
||||
key: 'conversationsCount',
|
||||
title: 'No. of conversations',
|
||||
align: this.isRTLView ? 'right' : 'left',
|
||||
width: 20,
|
||||
},
|
||||
{
|
||||
field: 'resolutionsCount',
|
||||
key: 'resolutionsCount',
|
||||
title: 'No. of resolved conversations',
|
||||
align: this.isRTLView ? 'right' : 'left',
|
||||
width: 20,
|
||||
},
|
||||
{
|
||||
field: 'avgFirstResponseTime',
|
||||
key: 'avgFirstResponseTime',
|
||||
title: 'Average first response time',
|
||||
align: this.isRTLView ? 'right' : 'left',
|
||||
width: 20,
|
||||
},
|
||||
{
|
||||
field: 'avgResolutionTime',
|
||||
key: 'avgResolutionTime',
|
||||
title: 'Average resolution time',
|
||||
align: this.isRTLView ? 'right' : 'left',
|
||||
width: 20,
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$store.dispatch('summaryReports/fetchTeamSummaryReports');
|
||||
},
|
||||
methods: {
|
||||
getTeamMetrics(id) {
|
||||
return (
|
||||
this.teamMetrics.find(metrics => metrics.team_id === Number(id)) || {}
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.agent-table-container {
|
||||
@apply flex flex-col flex-1;
|
||||
|
||||
.ve-table {
|
||||
&::v-deep {
|
||||
th.ve-table-header-th {
|
||||
font-size: var(--font-size-mini) !important;
|
||||
padding: var(--space-small) var(--space-two) !important;
|
||||
}
|
||||
|
||||
td.ve-table-body-td {
|
||||
padding: var(--space-one) var(--space-two) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&::v-deep .ve-pagination {
|
||||
@apply bg-transparent dark:bg-transparent;
|
||||
}
|
||||
|
||||
&::v-deep .ve-pagination-select {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.row-user-block {
|
||||
@apply items-center flex text-left;
|
||||
|
||||
.user-block {
|
||||
@apply items-start flex flex-col min-w-0 my-0 mx-2;
|
||||
|
||||
.title {
|
||||
@apply text-sm m-0 leading-[1.2] text-slate-800 dark:text-slate-100;
|
||||
}
|
||||
|
||||
.sub-title {
|
||||
@apply text-xs text-slate-600 dark:text-slate-200;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-pagination {
|
||||
@apply mt-4 text-right;
|
||||
}
|
||||
}
|
||||
|
||||
.agents-loader {
|
||||
@apply items-center flex text-base justify-center p-8;
|
||||
}
|
||||
</style>
|
||||
+1
-9
@@ -27,7 +27,6 @@
|
||||
import { VeTable, VePagination } from 'vue-easytable';
|
||||
import Spinner from 'shared/components/Spinner.vue';
|
||||
import rtlMixin from 'shared/mixins/rtlMixin';
|
||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
||||
|
||||
export default {
|
||||
name: 'TeamTable',
|
||||
@@ -79,17 +78,10 @@ export default {
|
||||
width: 25,
|
||||
renderBodyCell: ({ row }) => (
|
||||
<div class="row-user-block">
|
||||
<Thumbnail
|
||||
src={row.thumbnail}
|
||||
size="32px"
|
||||
username={row.agent}
|
||||
status={row.status}
|
||||
/>
|
||||
<div class="user-block">
|
||||
<h6 class="title overflow-hidden whitespace-nowrap text-ellipsis">
|
||||
<h6 class="capitalize title overflow-hidden whitespace-nowrap text-ellipsis">
|
||||
{row.agent}
|
||||
</h6>
|
||||
<span class="sub-title">{row.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
|
||||
@@ -41,6 +41,7 @@ import reports from './modules/reports';
|
||||
import teamMembers from './modules/teamMembers';
|
||||
import teams from './modules/teams';
|
||||
import userNotificationSettings from './modules/userNotificationSettings';
|
||||
import summaryReports from './modules/summaryReports';
|
||||
import webhooks from './modules/webhooks';
|
||||
import draftMessages from './modules/draftMessages';
|
||||
|
||||
@@ -106,6 +107,7 @@ export default new Vuex.Store({
|
||||
reports,
|
||||
teamMembers,
|
||||
teams,
|
||||
summaryReports,
|
||||
userNotificationSettings,
|
||||
webhooks,
|
||||
draftMessages,
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
import * as MutationHelpers from 'shared/helpers/vuex/mutationHelpers';
|
||||
import types from '../mutation-types';
|
||||
import LabelsAPI from '../../api/labels';
|
||||
import AnalyticsHelper from '../../helper/AnalyticsHelper';
|
||||
import { LABEL_EVENTS } from '../../helper/AnalyticsHelper/events';
|
||||
import SummaryReportsAPI from '../../api/summaryReports';
|
||||
|
||||
export const state = {
|
||||
teamSummaryReports: [],
|
||||
agentSummaryReports: [],
|
||||
uiFlags: {
|
||||
isFetching: false,
|
||||
isFetchingItem: false,
|
||||
isCreating: false,
|
||||
isDeleting: false,
|
||||
},
|
||||
uiFlags: {},
|
||||
};
|
||||
|
||||
export const getters = {
|
||||
@@ -22,94 +13,34 @@ export const getters = {
|
||||
getTeamSummaryReports(_state) {
|
||||
return _state.teamSummaryReports;
|
||||
},
|
||||
getLabelsOnSidebar(_state) {
|
||||
return _state.records
|
||||
.filter(record => record.show_on_sidebar)
|
||||
.sort((a, b) => a.title.localeCompare(b.title));
|
||||
},
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
revalidate: async function revalidate({ commit }, { newKey }) {
|
||||
async fetchTeamSummaryReports({ commit }, params) {
|
||||
try {
|
||||
const isExistingKeyValid = await LabelsAPI.validateCacheKey(newKey);
|
||||
if (!isExistingKeyValid) {
|
||||
const response = await LabelsAPI.refetchAndCommit(newKey);
|
||||
commit(types.SET_LABELS, response.data.payload);
|
||||
}
|
||||
const response = await SummaryReportsAPI.getTeamReports(params);
|
||||
commit('setTeamSummaryReport', response.data);
|
||||
} catch (error) {
|
||||
// Ignore error
|
||||
}
|
||||
},
|
||||
|
||||
get: async function getLabels({ commit }) {
|
||||
commit(types.SET_LABEL_UI_FLAG, { isFetching: true });
|
||||
async getAgentSummaryReports({ commit }, params) {
|
||||
try {
|
||||
const response = await LabelsAPI.get(true);
|
||||
const sortedLabels = response.data.payload.sort((a, b) =>
|
||||
a.title.localeCompare(b.title)
|
||||
);
|
||||
commit(types.SET_LABELS, sortedLabels);
|
||||
const response = await SummaryReportsAPI.getAgentReports(params);
|
||||
commit('setAgentSummayReport', response.data);
|
||||
} catch (error) {
|
||||
// Ignore error
|
||||
} finally {
|
||||
commit(types.SET_LABEL_UI_FLAG, { isFetching: false });
|
||||
}
|
||||
},
|
||||
|
||||
create: async function createLabels({ commit }, cannedObj) {
|
||||
commit(types.SET_LABEL_UI_FLAG, { isCreating: true });
|
||||
try {
|
||||
const response = await LabelsAPI.create(cannedObj);
|
||||
AnalyticsHelper.track(LABEL_EVENTS.CREATE);
|
||||
commit(types.ADD_LABEL, response.data);
|
||||
} catch (error) {
|
||||
const errorMessage = error?.response?.data?.message;
|
||||
throw new Error(errorMessage);
|
||||
} finally {
|
||||
commit(types.SET_LABEL_UI_FLAG, { isCreating: false });
|
||||
}
|
||||
},
|
||||
|
||||
update: async function updateLabels({ commit }, { id, ...updateObj }) {
|
||||
commit(types.SET_LABEL_UI_FLAG, { isUpdating: true });
|
||||
try {
|
||||
const response = await LabelsAPI.update(id, updateObj);
|
||||
AnalyticsHelper.track(LABEL_EVENTS.UPDATE);
|
||||
commit(types.EDIT_LABEL, response.data);
|
||||
} catch (error) {
|
||||
throw new Error(error);
|
||||
} finally {
|
||||
commit(types.SET_LABEL_UI_FLAG, { isUpdating: false });
|
||||
}
|
||||
},
|
||||
|
||||
delete: async function deleteLabels({ commit }, id) {
|
||||
commit(types.SET_LABEL_UI_FLAG, { isDeleting: true });
|
||||
try {
|
||||
await LabelsAPI.delete(id);
|
||||
AnalyticsHelper.track(LABEL_EVENTS.DELETED);
|
||||
commit(types.DELETE_LABEL, id);
|
||||
} catch (error) {
|
||||
throw new Error(error);
|
||||
} finally {
|
||||
commit(types.SET_LABEL_UI_FLAG, { isDeleting: false });
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const mutations = {
|
||||
[types.SET_LABEL_UI_FLAG](_state, data) {
|
||||
_state.uiFlags = {
|
||||
..._state.uiFlags,
|
||||
...data,
|
||||
};
|
||||
setTeamSummaryReport(_state, data) {
|
||||
_state.teamSummaryReports = data;
|
||||
},
|
||||
setAgentSummaryReport(_state, data) {
|
||||
_state.agentSummaryReports = data;
|
||||
},
|
||||
|
||||
[types.SET_LABELS]: MutationHelpers.set,
|
||||
[types.ADD_LABEL]: MutationHelpers.create,
|
||||
[types.EDIT_LABEL]: MutationHelpers.update,
|
||||
[types.DELETE_LABEL]: MutationHelpers.destroy,
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
Reference in New Issue
Block a user