Add live team reports

This commit is contained in:
Pranav
2025-02-05 19:26:46 -08:00
parent b235d66f81
commit 698642fecb
6 changed files with 192 additions and 0 deletions
@@ -6,6 +6,7 @@ import { OVERVIEW_METRICS } from './constants';
import ReportHeader from './components/ReportHeader.vue';
import HeatmapContainer from './components/HeatmapContainer.vue';
import AgentLiveReportContainer from './components/AgentLiveReportContainer.vue';
import TeamLiveReportContainer from './components/TeamLiveReportContainer.vue';
export const FETCH_INTERVAL = 60000;
export default {
@@ -15,6 +16,7 @@ export default {
MetricCard,
HeatmapContainer,
AgentLiveReportContainer,
TeamLiveReportContainer,
},
data() {
return {
@@ -127,5 +129,6 @@ export default {
</div>
<HeatmapContainer />
<AgentLiveReportContainer />
<TeamLiveReportContainer />
</div>
</template>
@@ -0,0 +1,36 @@
<script setup>
import { onMounted } from 'vue';
import MetricCard from './overview/MetricCard.vue';
import { useStore, useMapGetter } from 'dashboard/composables/store';
import { useLiveRefresh } from 'dashboard/composables/useLiveRefresh';
import TeamTable from './overview/TeamTable.vue';
const store = useStore();
const uiFlags = useMapGetter('getOverviewUIFlags');
const teamConversationMetric = useMapGetter('getTeamConversationMetric');
const teams = useMapGetter('teams/getTeams');
const fetchData = () => store.dispatch('fetchTeamConversationMetric');
const { startRefetching } = useLiveRefresh(fetchData);
onMounted(() => {
store.dispatch('teams/get');
fetchData();
startRefetching();
});
</script>
<template>
<div class="flex flex-row flex-wrap max-w-full">
<MetricCard :header="$t('OVERVIEW_REPORTS.TEAM_CONVERSATIONS.HEADER')">
<TeamTable
:teams="teams"
:team-metrics="teamConversationMetric"
:is-loading="uiFlags.isFetchingTeamConversationMetric"
/>
</MetricCard>
</div>
</template>
@@ -0,0 +1,115 @@
<script setup>
import { computed, h } from 'vue';
import {
useVueTable,
createColumnHelper,
getCoreRowModel,
getPaginationRowModel,
} from '@tanstack/vue-table';
import { useI18n } from 'vue-i18n';
import Spinner from 'shared/components/Spinner.vue';
import EmptyState from 'dashboard/components/widgets/EmptyState.vue';
import Table from 'dashboard/components/table/Table.vue';
import Pagination from 'dashboard/components/table/Pagination.vue';
const { teams, teamMetrics } = defineProps({
teams: {
type: Array,
default: () => [],
},
teamMetrics: {
type: Array,
default: () => [],
},
isLoading: {
type: Boolean,
default: false,
},
});
const { t } = useI18n();
const getTeamMetrics = id =>
teamMetrics.find(metrics => metrics.team_id === Number(id)) || {};
const tableData = computed(() =>
teams
.map(team => {
const metric = getTeamMetrics(team.id);
return {
agent: team.name,
open: metric.open || 0,
unattended: metric.unattended || 0,
};
})
.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(
'span',
{
class: cellProps.getValue() ? '' : 'text-slate-300 dark:text-slate-700',
},
cellProps.getValue() ? cellProps.getValue() : '---'
);
const columnHelper = createColumnHelper();
const columns = [
columnHelper.accessor('agent', {
header: t('OVERVIEW_REPORTS.TEAM_CONVERSATIONS.TABLE_HEADER.AGENT'),
cell: defaulSpanRender,
size: 250,
}),
columnHelper.accessor('open', {
header: t('OVERVIEW_REPORTS.TEAM_CONVERSATIONS.TABLE_HEADER.OPEN'),
cell: defaulSpanRender,
size: 100,
}),
columnHelper.accessor('unattended', {
header: t('OVERVIEW_REPORTS.TEAM_CONVERSATIONS.TABLE_HEADER.UNATTENDED'),
cell: defaulSpanRender,
size: 100,
}),
];
const table = useVueTable({
get data() {
return tableData.value;
},
columns,
enableSorting: false,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
});
</script>
<template>
<div class="flex flex-col flex-1">
<Table :table="table" class="max-h-[calc(100vh-21.875rem)]" />
<Pagination class="mt-2" :table="table" />
<div
v-if="isLoading"
class="items-center flex text-base justify-center p-8"
>
<Spinner />
<span>
{{ $t('OVERVIEW_REPORTS.TEAM_CONVERSATIONS.LOADING_MESSAGE') }}
</span>
</div>
<EmptyState
v-else-if="!isLoading && !teams.length"
:title="$t('OVERVIEW_REPORTS.TEAM_CONVERSATIONS.NO_TEAMS')"
/>
</div>
</template>