feat: Update design for report pages (#10506)
<img width="1440" alt="Screenshot 2024-11-26 at 8 38 57 PM" src="https://github.com/user-attachments/assets/f752157c-6134-42cb-8211-ce636ea9e4d6"> <img width="1439" alt="Screenshot 2024-11-26 at 8 40 47 PM" src="https://github.com/user-attachments/assets/580b1f61-68bc-489b-9081-b0aeb402f31d"> --------- Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
This commit is contained in:
@@ -25,7 +25,7 @@
|
||||
}
|
||||
|
||||
.mx-input {
|
||||
@apply h-[2.5rem] flex border border-solid border-slate-200 dark:border-slate-600 rounded-md shadow-none;
|
||||
@apply h-[2.5rem] flex border border-solid border-n-weak rounded-md shadow-none;
|
||||
}
|
||||
|
||||
.mx-input:disabled,
|
||||
@@ -39,7 +39,7 @@
|
||||
}
|
||||
|
||||
.mx-datepicker-main {
|
||||
@apply border-0 bg-white dark:bg-slate-800;
|
||||
@apply border-0 bg-n-solid-2 rounded-xl;
|
||||
|
||||
.cell {
|
||||
&.disabled {
|
||||
@@ -53,6 +53,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
.mx-calendar+.mx-calendar {
|
||||
@apply border-l border-n-weak;
|
||||
}
|
||||
|
||||
.mx-datepicker-footer {
|
||||
@apply border border-n-weak;
|
||||
}
|
||||
|
||||
.mx-time {
|
||||
@apply border-0 bg-white dark:bg-slate-800;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ const handleButtonClick = () => {
|
||||
<template>
|
||||
<section class="flex flex-col w-full h-full overflow-hidden bg-n-background">
|
||||
<header class="sticky top-0 z-10 px-6 lg:px-0">
|
||||
<div class="w-full max-w-[900px] mx-auto">
|
||||
<div class="w-full max-w-[960px] mx-auto">
|
||||
<div class="flex items-center justify-between w-full h-20 gap-2">
|
||||
<span class="text-xl font-medium text-n-slate-12">
|
||||
{{ headerTitle }}
|
||||
@@ -44,7 +44,7 @@ const handleButtonClick = () => {
|
||||
</div>
|
||||
</header>
|
||||
<main class="flex-1 px-6 overflow-y-auto lg:px-0">
|
||||
<div class="w-full max-w-[900px] mx-auto py-4">
|
||||
<div class="w-full max-w-[960px] mx-auto py-4">
|
||||
<slot name="default" />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -46,7 +46,7 @@ const emit = defineEmits([
|
||||
<template>
|
||||
<header class="sticky top-0 z-10 px-6 xl:px-0">
|
||||
<div
|
||||
class="flex items-center justify-between w-full h-20 gap-2 mx-auto max-w-[900px]"
|
||||
class="flex items-center justify-between w-full h-20 gap-2 mx-auto max-w-[960px]"
|
||||
>
|
||||
<span class="text-xl font-medium truncate text-n-slate-12">
|
||||
{{ headerTitle }}
|
||||
|
||||
@@ -60,7 +60,7 @@ const togglePortalSwitcher = () => {
|
||||
<template>
|
||||
<section class="flex flex-col w-full h-full overflow-hidden bg-n-background">
|
||||
<header class="sticky top-0 z-10 px-6 pb-3 lg:px-0">
|
||||
<div class="w-full max-w-[900px] mx-auto">
|
||||
<div class="w-full max-w-[960px] mx-auto">
|
||||
<div
|
||||
v-if="showHeaderTitle"
|
||||
class="flex items-center justify-start h-20 gap-2"
|
||||
@@ -95,7 +95,7 @@ const togglePortalSwitcher = () => {
|
||||
</div>
|
||||
</header>
|
||||
<main class="flex-1 px-6 overflow-y-auto lg:px-0">
|
||||
<div class="w-full max-w-[900px] mx-auto py-3">
|
||||
<div class="w-full max-w-[960px] mx-auto py-3">
|
||||
<slot name="content" />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -14,22 +14,22 @@ const menuItems = ref([
|
||||
{
|
||||
label: 'Contact Support',
|
||||
icon: 'i-lucide-life-buoy',
|
||||
click: () => window.alert('Contact Support'),
|
||||
click: () => console.log('Contact Support'),
|
||||
},
|
||||
{
|
||||
label: 'Keyboard Shortcuts',
|
||||
icon: 'i-lucide-keyboard',
|
||||
click: () => window.alert('Keyboard Shortcuts'),
|
||||
click: () => console.log('Keyboard Shortcuts'),
|
||||
},
|
||||
{
|
||||
label: 'Profile Settings',
|
||||
icon: 'i-lucide-user-pen',
|
||||
click: () => window.alert('Profile Settings'),
|
||||
click: () => console.log('Profile Settings'),
|
||||
},
|
||||
{
|
||||
label: 'Change Appearance',
|
||||
icon: 'i-lucide-swatch-book',
|
||||
click: () => window.alert('Change Appearance'),
|
||||
click: () => console.log('Change Appearance'),
|
||||
},
|
||||
{
|
||||
label: 'Open SuperAdmin',
|
||||
@@ -40,7 +40,7 @@ const menuItems = ref([
|
||||
{
|
||||
label: 'Log Out',
|
||||
icon: 'i-lucide-log-out',
|
||||
click: () => window.alert('Log Out'),
|
||||
click: () => console.log('Log Out'),
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
|
||||
@@ -249,11 +249,6 @@ const menuItems = computed(() => {
|
||||
label: t('SIDEBAR.CSAT'),
|
||||
to: accountScopedRoute('csat_reports'),
|
||||
},
|
||||
{
|
||||
name: 'Reports Bot',
|
||||
label: t('SIDEBAR.REPORTS_BOT'),
|
||||
to: accountScopedRoute('bot_reports'),
|
||||
},
|
||||
{
|
||||
name: 'Reports Agent',
|
||||
label: t('SIDEBAR.REPORTS_AGENT'),
|
||||
@@ -279,6 +274,11 @@ const menuItems = computed(() => {
|
||||
label: t('SIDEBAR.REPORTS_SLA'),
|
||||
to: accountScopedRoute('sla_reports'),
|
||||
},
|
||||
{
|
||||
name: 'Reports Bot',
|
||||
label: t('SIDEBAR.REPORTS_BOT'),
|
||||
to: accountScopedRoute('bot_reports'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -54,7 +54,7 @@ const end = computed(() => {
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex flex-1 items-center justify-between">
|
||||
<div>
|
||||
<p class="text-sm text-gray-700">
|
||||
<p class="text-sm text-n-slate-11 mb-0">
|
||||
{{ $t('REPORT.PAGINATION.RESULTS', { start, end, total }) }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -62,7 +62,7 @@ const end = computed(() => {
|
||||
<woot-button
|
||||
:disabled="!table.getCanPreviousPage()"
|
||||
variant="clear"
|
||||
class="size-8 flex items-center border border-slate-50"
|
||||
class="h-8 border-0 flex items-center"
|
||||
color-scheme="secondary"
|
||||
@click="table.setPageIndex(0)"
|
||||
>
|
||||
@@ -70,7 +70,7 @@ const end = computed(() => {
|
||||
</woot-button>
|
||||
<woot-button
|
||||
variant="clear"
|
||||
class="size-8 flex items-center border border-slate-50"
|
||||
class="h-8 border-0 flex items-center"
|
||||
color-scheme="secondary"
|
||||
:disabled="!table.getCanPreviousPage()"
|
||||
@click="table.previousPage()"
|
||||
@@ -81,22 +81,22 @@ const end = computed(() => {
|
||||
v-for="page in visiblePages"
|
||||
:key="page"
|
||||
variant="clear"
|
||||
class="size-8 flex items-center justify-center border text-xs leading-none text-center"
|
||||
:class="page == currentPage ? 'border-woot-500' : 'border-slate-50'"
|
||||
class="h-8 flex items-center justify-center text-xs leading-none text-center"
|
||||
:class="page == currentPage ? 'border-n-brand' : 'border-slate-50'"
|
||||
color-scheme="secondary"
|
||||
@click="table.setPageIndex(page - 1)"
|
||||
>
|
||||
<div
|
||||
<span
|
||||
class="text-center"
|
||||
:class="{ 'text-woot-500': page == currentPage }"
|
||||
:class="{ 'text-n-brand': page == currentPage }"
|
||||
>
|
||||
{{ page }}
|
||||
</div>
|
||||
</span>
|
||||
</woot-button>
|
||||
<woot-button
|
||||
:disabled="!table.getCanNextPage()"
|
||||
variant="clear"
|
||||
class="size-8 flex items-center border border-slate-50"
|
||||
class="h-8 border-0 flex items-center"
|
||||
color-scheme="secondary"
|
||||
@click="table.nextPage()"
|
||||
>
|
||||
@@ -105,7 +105,7 @@ const end = computed(() => {
|
||||
<woot-button
|
||||
:disabled="!table.getCanNextPage()"
|
||||
variant="clear"
|
||||
class="size-8 flex items-center border border-slate-50"
|
||||
class="h-8 border-0 flex items-center"
|
||||
color-scheme="secondary"
|
||||
@click="table.setPageIndex(table.getPageCount() - 1)"
|
||||
>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<script setup>
|
||||
import { FlexRender } from '@tanstack/vue-table';
|
||||
import SortButton from './SortButton.vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
defineProps({
|
||||
const props = defineProps({
|
||||
table: {
|
||||
type: Object,
|
||||
required: true,
|
||||
@@ -11,22 +12,36 @@ defineProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'relaxed',
|
||||
},
|
||||
});
|
||||
|
||||
const isRelaxed = computed(() => props.type === 'relaxed');
|
||||
const headerClass = computed(() =>
|
||||
isRelaxed.value
|
||||
? 'first:rounded-bl-lg first:rounded-tl-lg last:rounded-br-lg last:rounded-tr-lg'
|
||||
: ''
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<table :class="{ 'table-fixed': fixed }">
|
||||
<thead
|
||||
class="sticky top-0 z-10 border-b border-slate-50 dark:border-slate-800 bg-slate-25 dark:bg-slate-800"
|
||||
>
|
||||
<tr v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
|
||||
<thead class="sticky top-0 z-10 bg-n-slate-1">
|
||||
<tr
|
||||
v-for="headerGroup in table.getHeaderGroups()"
|
||||
:key="headerGroup.id"
|
||||
class="rounded-xl"
|
||||
>
|
||||
<th
|
||||
v-for="header in headerGroup.headers"
|
||||
:key="header.id"
|
||||
:style="{
|
||||
width: `${header.getSize()}px`,
|
||||
}"
|
||||
class="text-left py-3 px-5 dark:bg-slate-800 text-slate-800 dark:text-slate-200 font-normal text-xs"
|
||||
class="text-left py-3 px-5 font-normal text-sm"
|
||||
:class="headerClass"
|
||||
@click="header.column.getCanSort() && header.column.toggleSorting()"
|
||||
>
|
||||
<div
|
||||
@@ -43,16 +58,12 @@ defineProps({
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="divide-y divide-slate-25 dark:divide-slate-900">
|
||||
<tr
|
||||
v-for="row in table.getRowModel().rows"
|
||||
:key="row.id"
|
||||
class="hover:bg-slate-25 dark:hover:bg-slate-800"
|
||||
>
|
||||
<tbody class="divide-y divide-n-slate-2">
|
||||
<tr v-for="row in table.getRowModel().rows" :key="row.id">
|
||||
<td
|
||||
v-for="cell in row.getVisibleCells()"
|
||||
:key="cell.id"
|
||||
class="py-2 px-5"
|
||||
:class="isRelaxed ? 'py-4 px-5' : 'py-2 px-5'"
|
||||
>
|
||||
<FlexRender
|
||||
:render="cell.column.columnDef.cell"
|
||||
|
||||
@@ -29,7 +29,7 @@ const spanClass = computed(() => {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center px-0 py-2 text-xs font-medium text-left uppercase text-slate-700 dark:text-slate-100 rtl:text-right"
|
||||
class="flex items-center px-0 py-2 text-xs font-medium text-right uppercase text-n-slate-11 rtl:text-left"
|
||||
:class="spanClass"
|
||||
>
|
||||
<slot>
|
||||
|
||||
@@ -4,7 +4,7 @@ import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
||||
defineProps({
|
||||
user: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
default: () => ({}),
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
@@ -12,7 +12,7 @@ defineProps({
|
||||
},
|
||||
textClass: {
|
||||
type: String,
|
||||
default: 'text-xs text-slate-600',
|
||||
default: 'text-sm text-n-slate-12',
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -25,11 +25,11 @@ defineProps({
|
||||
:username="user.name"
|
||||
:status="user.availability_status"
|
||||
/>
|
||||
<h6
|
||||
class="my-0 dark:text-slate-100 overflow-hidden whitespace-nowrap text-ellipsis text-capitalize"
|
||||
<span
|
||||
class="my-0 overflow-hidden whitespace-nowrap text-ellipsis text-capitalize"
|
||||
:class="textClass"
|
||||
>
|
||||
{{ user.name }}
|
||||
</h6>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -18,7 +18,7 @@ const formatDate = timestamp =>
|
||||
<template>
|
||||
<div class="flex justify-between w-full">
|
||||
<span
|
||||
class="text-sm sticky top-0 h-fit font-normal tracking-[-0.6%] min-w-[140px] truncate text-slate-600 dark:text-slate-200"
|
||||
class="text-sm sticky top-0 h-fit font-normal tracking-[-0.6%] min-w-[140px] truncate text-n-slate-11"
|
||||
>
|
||||
{{ label }}
|
||||
</span>
|
||||
@@ -26,7 +26,7 @@ const formatDate = timestamp =>
|
||||
<span
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
class="text-sm font-normal text-slate-900 dark:text-slate-25 text-right tabular-nums"
|
||||
class="text-sm font-normal text-n-slate-12 text-right tabular-nums"
|
||||
>
|
||||
{{ formatDate(item.created_at) }}
|
||||
</span>
|
||||
|
||||
@@ -40,9 +40,9 @@ const toggleShowAllNRT = () => {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="absolute flex flex-col items-start bg-white dark:bg-slate-800 z-50 p-4 border border-solid border-slate-75 dark:border-slate-700 w-[384px] rounded-xl gap-4 max-h-96 overflow-auto"
|
||||
class="absolute flex flex-col items-start border-n-strong bg-n-solid-3 w-96 backdrop-blur-[100px] px-6 py-5 z-50 shadow rounded-xl gap-4 max-h-96 overflow-auto"
|
||||
>
|
||||
<span class="text-sm font-medium text-slate-900 dark:text-slate-25">
|
||||
<span class="text-sm font-medium text-n-slate-12">
|
||||
{{ $t('SLA.EVENTS.TITLE') }}
|
||||
</span>
|
||||
<SLAEventItem
|
||||
|
||||
@@ -171,7 +171,7 @@ const table = useVueTable({
|
||||
<template>
|
||||
<section class="flex-1 h-full overflow-auto bg-white dark:bg-slate-900">
|
||||
<section class="overflow-x-auto">
|
||||
<Table fixed :table="table" />
|
||||
<Table fixed :table="table" type="compact" />
|
||||
</section>
|
||||
|
||||
<EmptyState
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
<script>
|
||||
<script setup>
|
||||
import WootReports from './components/WootReports.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
WootReports,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -15,5 +9,6 @@ export default {
|
||||
getter-key="agents/getAgents"
|
||||
action-key="agents/get"
|
||||
:download-button-label="$t('REPORT.DOWNLOAD_AGENT_REPORTS')"
|
||||
:report-title="$t('AGENT_REPORTS.HEADER')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -5,11 +5,13 @@ import ReportFilterSelector from './components/FilterSelector.vue';
|
||||
import { GROUP_BY_FILTER } from './constants';
|
||||
import ReportContainer from './ReportContainer.vue';
|
||||
import { REPORTS_EVENTS } from '../../../../helper/AnalyticsHelper/events';
|
||||
import ReportHeader from './components/ReportHeader.vue';
|
||||
|
||||
export default {
|
||||
name: 'BotReports',
|
||||
components: {
|
||||
BotMetrics,
|
||||
ReportHeader,
|
||||
ReportFilterSelector,
|
||||
ReportContainer,
|
||||
},
|
||||
@@ -84,7 +86,8 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex-1 p-4 overflow-auto">
|
||||
<ReportHeader :header-title="$t('BOT_REPORTS.HEADER')" />
|
||||
<div class="flex flex-col gap-4">
|
||||
<ReportFilterSelector
|
||||
:show-agents-filter="false"
|
||||
show-group-by-filter
|
||||
|
||||
@@ -7,6 +7,8 @@ import ReportFilterSelector from './components/FilterSelector.vue';
|
||||
import { generateFileName } from '../../../../helper/downloadHelper';
|
||||
import { REPORTS_EVENTS } from '../../../../helper/AnalyticsHelper/events';
|
||||
import { FEATURE_FLAGS } from '../../../../featureFlags';
|
||||
import V4Button from 'dashboard/components-next/button/Button.vue';
|
||||
import ReportHeader from './components/ReportHeader.vue';
|
||||
|
||||
export default {
|
||||
name: 'CsatResponses',
|
||||
@@ -14,6 +16,8 @@ export default {
|
||||
CsatMetrics,
|
||||
CsatTable,
|
||||
ReportFilterSelector,
|
||||
ReportHeader,
|
||||
V4Button,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -108,7 +112,16 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex-1 p-4 overflow-auto">
|
||||
<ReportHeader :header-title="$t('CSAT_REPORTS.HEADER')">
|
||||
<V4Button
|
||||
:label="$t('CSAT_REPORTS.DOWNLOAD')"
|
||||
icon="i-ph-download-simple"
|
||||
size="sm"
|
||||
@click="downloadReports"
|
||||
/>
|
||||
</ReportHeader>
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
<ReportFilterSelector
|
||||
show-agents-filter
|
||||
show-inbox-filter
|
||||
@@ -117,14 +130,7 @@ export default {
|
||||
:show-business-hours-switch="false"
|
||||
@filter-change="onFilterChange"
|
||||
/>
|
||||
<woot-button
|
||||
color-scheme="success"
|
||||
class-names="button--fixed-top"
|
||||
icon="arrow-download"
|
||||
@click="downloadReports"
|
||||
>
|
||||
{{ $t('CSAT_REPORTS.DOWNLOAD') }}
|
||||
</woot-button>
|
||||
|
||||
<CsatMetrics :filters="requestPayload" />
|
||||
<CsatTable :page-index="pageIndex" @page-change="onPageNumberChange" />
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
<script>
|
||||
<script setup>
|
||||
import WootReports from './components/WootReports.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
WootReports,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -15,5 +9,6 @@ export default {
|
||||
getter-key="inboxes/getInboxes"
|
||||
action-key="inboxes/get"
|
||||
:download-button-label="$t('INBOX_REPORTS.DOWNLOAD_INBOX_REPORTS')"
|
||||
:report-title="$t('INBOX_REPORTS.HEADER')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import V4Button from 'dashboard/components-next/button/Button.vue';
|
||||
import { useAlert, useTrack } from 'dashboard/composables';
|
||||
import fromUnixTime from 'date-fns/fromUnixTime';
|
||||
import format from 'date-fns/format';
|
||||
@@ -6,6 +7,7 @@ import ReportFilterSelector from './components/FilterSelector.vue';
|
||||
import { GROUP_BY_FILTER } from './constants';
|
||||
import { REPORTS_EVENTS } from '../../../../helper/AnalyticsHelper/events';
|
||||
import ReportContainer from './ReportContainer.vue';
|
||||
import ReportHeader from './components/ReportHeader.vue';
|
||||
|
||||
const REPORTS_KEYS = {
|
||||
CONVERSATIONS: 'conversations_count',
|
||||
@@ -20,8 +22,10 @@ const REPORTS_KEYS = {
|
||||
export default {
|
||||
name: 'ConversationReports',
|
||||
components: {
|
||||
ReportHeader,
|
||||
ReportFilterSelector,
|
||||
ReportContainer,
|
||||
V4Button,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -98,15 +102,15 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex-1 p-4 overflow-auto">
|
||||
<woot-button
|
||||
color-scheme="success"
|
||||
class-names="button--fixed-top"
|
||||
icon="arrow-download"
|
||||
<ReportHeader :header-title="$t('REPORT.HEADER')">
|
||||
<V4Button
|
||||
:label="$t('REPORT.DOWNLOAD_AGENT_REPORTS')"
|
||||
icon="i-ph-download-simple"
|
||||
size="sm"
|
||||
@click="downloadAgentReports"
|
||||
>
|
||||
{{ $t('REPORT.DOWNLOAD_AGENT_REPORTS') }}
|
||||
</woot-button>
|
||||
/>
|
||||
</ReportHeader>
|
||||
<div class="flex flex-col gap-3">
|
||||
<ReportFilterSelector
|
||||
:show-agents-filter="false"
|
||||
show-group-by-filter
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
<script>
|
||||
<script setup>
|
||||
import WootReports from './components/WootReports.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
WootReports,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -15,5 +9,6 @@ export default {
|
||||
getter-key="labels/getLabels"
|
||||
action-key="labels/get"
|
||||
:download-button-label="$t('LABEL_REPORTS.DOWNLOAD_LABEL_REPORTS')"
|
||||
:report-title="$t('LABEL_REPORTS.HEADER')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -10,10 +10,12 @@ import getUnixTime from 'date-fns/getUnixTime';
|
||||
import startOfDay from 'date-fns/startOfDay';
|
||||
import subDays from 'date-fns/subDays';
|
||||
import { emitter } from 'shared/helpers/mitt';
|
||||
import ReportHeader from './components/ReportHeader.vue';
|
||||
|
||||
export default {
|
||||
name: 'LiveReports',
|
||||
components: {
|
||||
ReportHeader,
|
||||
AgentTable,
|
||||
MetricCard,
|
||||
ReportHeatmap,
|
||||
@@ -123,8 +125,9 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex-1 p-4 overflow-auto">
|
||||
<div class="flex flex-col items-center md:flex-row">
|
||||
<ReportHeader :header-title="$t('OVERVIEW_REPORTS.HEADER')" />
|
||||
<div class="flex flex-col gap-4 pb-6">
|
||||
<div class="flex flex-col items-center md:flex-row gap-4">
|
||||
<div
|
||||
class="flex-1 w-full max-w-full md:w-[65%] md:max-w-[65%] conversation-metric"
|
||||
>
|
||||
@@ -140,10 +143,10 @@ export default {
|
||||
:key="index"
|
||||
class="flex-1 min-w-0 pb-2"
|
||||
>
|
||||
<h3 class="text-base text-slate-700 dark:text-slate-100">
|
||||
<h3 class="text-base text-n-slate-11">
|
||||
{{ name }}
|
||||
</h3>
|
||||
<p class="text-woot-800 dark:text-woot-300 text-3xl mb-0 mt-1">
|
||||
<p class="text-n-slate-12 text-3xl mb-0 mt-1">
|
||||
{{ metric }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -156,17 +159,17 @@ export default {
|
||||
:key="index"
|
||||
class="flex-1 min-w-0 pb-2"
|
||||
>
|
||||
<h3 class="text-base text-slate-700 dark:text-slate-100">
|
||||
<h3 class="text-base text-n-slate-11">
|
||||
{{ name }}
|
||||
</h3>
|
||||
<p class="text-woot-800 dark:text-woot-300 text-3xl mb-0 mt-1">
|
||||
<p class="text-n-slate-12 text-3xl mb-0 mt-1">
|
||||
{{ metric }}
|
||||
</p>
|
||||
</div>
|
||||
</MetricCard>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row flex-wrap max-w-full ml-auto mr-auto">
|
||||
<div class="flex flex-row flex-wrap max-w-full">
|
||||
<MetricCard :header="$t('OVERVIEW_REPORTS.CONVERSATION_HEATMAP.HEADER')">
|
||||
<template #control>
|
||||
<woot-button
|
||||
@@ -185,7 +188,7 @@ export default {
|
||||
/>
|
||||
</MetricCard>
|
||||
</div>
|
||||
<div class="flex flex-row flex-wrap max-w-full ml-auto mr-auto">
|
||||
<div class="flex flex-row flex-wrap max-w-full">
|
||||
<MetricCard :header="$t('OVERVIEW_REPORTS.AGENT_CONVERSATIONS.HEADER')">
|
||||
<AgentTable
|
||||
:agents="agents"
|
||||
|
||||
@@ -135,7 +135,7 @@ export default {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="grid grid-cols-1 p-2 bg-white border rounded-md md:grid-cols-2 lg:grid-cols-3 dark:bg-slate-800 border-slate-100 dark:border-slate-700"
|
||||
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 px-6 py-5 shadow outline-1 outline outline-n-container rounded-xl bg-n-solid-2"
|
||||
>
|
||||
<div
|
||||
v-for="metric in metrics"
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
<script>
|
||||
import V4Button from 'dashboard/components-next/button/Button.vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { useAlert } from 'dashboard/composables';
|
||||
import SLAMetrics from './components/SLA/SLAMetrics.vue';
|
||||
import SLATable from './components/SLA/SLATable.vue';
|
||||
import SLAReportFilters from './components/SLA/SLAReportFilters.vue';
|
||||
import { generateFileName } from 'dashboard/helper/downloadHelper';
|
||||
import ReportHeader from './components/ReportHeader.vue';
|
||||
export default {
|
||||
name: 'SLAReports',
|
||||
components: {
|
||||
V4Button,
|
||||
ReportHeader,
|
||||
SLAMetrics,
|
||||
SLATable,
|
||||
SLAReportFilters,
|
||||
@@ -77,30 +81,28 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col flex-1 gap-6 px-4 pt-4 overflow-auto">
|
||||
<SLAReportFilters @filter-change="onFilterChange" />
|
||||
<woot-button
|
||||
color-scheme="success"
|
||||
class-names="button--fixed-top"
|
||||
icon="arrow-download"
|
||||
<ReportHeader :header-title="$t('SLA_REPORTS.HEADER')">
|
||||
<V4Button
|
||||
:label="$t('SLA_REPORTS.DOWNLOAD_SLA_REPORTS')"
|
||||
icon="i-ph-download-simple"
|
||||
size="sm"
|
||||
@click="downloadReports"
|
||||
>
|
||||
{{ $t('SLA_REPORTS.DOWNLOAD_SLA_REPORTS') }}
|
||||
</woot-button>
|
||||
<div class="flex flex-col gap-6">
|
||||
<SLAMetrics
|
||||
:hit-rate="slaMetrics.hitRate"
|
||||
:no-of-breaches="slaMetrics.numberOfSLAMisses"
|
||||
:no-of-conversations="slaMetrics.numberOfConversations"
|
||||
:is-loading="uiFlags.isFetchingMetrics"
|
||||
/>
|
||||
<SLATable
|
||||
:sla-reports="slaReports"
|
||||
:is-loading="uiFlags.isFetching"
|
||||
:current-page="Number(slaMeta.currentPage)"
|
||||
:total-count="Number(slaMeta.count)"
|
||||
@page-change="onPageChange"
|
||||
/>
|
||||
</div>
|
||||
/>
|
||||
</ReportHeader>
|
||||
<div class="flex flex-col flex-1 gap-6">
|
||||
<SLAReportFilters @filter-change="onFilterChange" />
|
||||
<SLAMetrics
|
||||
:hit-rate="slaMetrics.hitRate"
|
||||
:no-of-breaches="slaMetrics.numberOfSLAMisses"
|
||||
:no-of-conversations="slaMetrics.numberOfConversations"
|
||||
:is-loading="uiFlags.isFetchingMetrics"
|
||||
/>
|
||||
<SLATable
|
||||
:sla-reports="slaReports"
|
||||
:is-loading="uiFlags.isFetching"
|
||||
:current-page="Number(slaMeta.currentPage)"
|
||||
:total-count="Number(slaMeta.count)"
|
||||
@page-change="onPageChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
<script>
|
||||
<script setup>
|
||||
import WootReports from './components/WootReports.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
WootReports,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -15,5 +9,6 @@ export default {
|
||||
getter-key="teams/getTeams"
|
||||
action-key="teams/get"
|
||||
:download-button-label="$t('TEAM_REPORTS.DOWNLOAD_TEAM_REPORTS')"
|
||||
:report-title="$t('TEAM_REPORTS.HEADER')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -38,7 +38,7 @@ onMounted(fetchMetrics);
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex flex-wrap mx-0 bg-white dark:bg-slate-800 rounded-[4px] p-4 mb-5 border border-solid border-slate-75 dark:border-slate-700"
|
||||
class="flex flex-wrap mx-0 shadow outline-1 outline outline-n-container rounded-xl bg-n-solid-2 px-6 py-5"
|
||||
>
|
||||
<ReportMetricCard
|
||||
:label="$t('BOT_REPORTS.METRIC.TOTAL_CONVERSATIONS.LABEL')"
|
||||
|
||||
@@ -29,11 +29,11 @@ const trendColor = (value, key) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="text-slate-900 dark:text-slate-100">
|
||||
<div class="text-n-slate-11">
|
||||
<span class="text-sm">
|
||||
{{ metric.NAME }}
|
||||
</span>
|
||||
<div class="flex items-end">
|
||||
<div class="flex items-end text-n-slate-12">
|
||||
<div class="text-xl font-medium">
|
||||
{{ displayMetric(metric.KEY) }}
|
||||
</div>
|
||||
|
||||
@@ -86,7 +86,7 @@ export default {
|
||||
<!-- Added ref for writing specs -->
|
||||
<template>
|
||||
<div
|
||||
class="flex-col lg:flex-row flex flex-wrap mx-0 bg-white dark:bg-slate-800 rounded-[4px] p-4 mb-5 border border-solid border-slate-75 dark:border-slate-700"
|
||||
class="flex-col lg:flex-row flex flex-wrap mx-0 shadow outline-1 outline outline-n-container rounded-xl bg-n-solid-2 px-6 py-8 gap-4"
|
||||
>
|
||||
<CsatMetricCard
|
||||
:label="$t('CSAT_REPORTS.METRIC.TOTAL_RESPONSES.LABEL')"
|
||||
@@ -111,10 +111,10 @@ export default {
|
||||
<div
|
||||
v-if="metrics.totalResponseCount && !ratingFilterEnabled"
|
||||
ref="csatBarChart"
|
||||
class="w-full md:w-1/2 md:max-w-[50%] flex-1 rtl:[direction:initial] p-4"
|
||||
class="w-full md:w-1/2 md:max-w-[50%] flex-1 rtl:[direction:initial]"
|
||||
>
|
||||
<h3
|
||||
class="flex items-center m-0 text-xs font-medium md:text-sm text-slate-800 dark:text-slate-100"
|
||||
class="flex items-center m-0 text-xs font-medium md:text-sm text-n-slate-12"
|
||||
>
|
||||
<div class="flex flex-row-reverse justify-end">
|
||||
<div
|
||||
|
||||
@@ -145,14 +145,13 @@ const table = useVueTable({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="csat--table-container">
|
||||
<Table
|
||||
:table="table"
|
||||
class="max-h-[calc(100vh-21.875rem)] border bg-white dark:bg-slate-900 border-slate-50 dark:border-slate-800"
|
||||
/>
|
||||
<div
|
||||
class="shadow outline-1 outline outline-n-container rounded-xl bg-n-solid-2 px-6 py-5"
|
||||
>
|
||||
<Table :table="table" class="max-h-[calc(100vh-21.875rem)]" />
|
||||
<div
|
||||
v-show="!tableData.length"
|
||||
class="csat--empty-records text-slate-600 dark:text-slate-200 bg-white dark:bg-slate-900 border border-t-0 border-solid border-slate-75 dark:border-slate-700"
|
||||
class="h-48 flex items-center justify-center text-n-slate-12 text-sm"
|
||||
>
|
||||
{{ $t('CSAT_REPORTS.NO_RECORDS') }}
|
||||
</div>
|
||||
@@ -161,17 +160,3 @@ const table = useVueTable({
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.csat--empty-records {
|
||||
align-items: center;
|
||||
// border: 1px solid var(--color-border);
|
||||
border-top: 0;
|
||||
display: flex;
|
||||
font-size: var(--font-size-small);
|
||||
height: 12.5rem;
|
||||
justify-content: center;
|
||||
margin-top: -1px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -178,7 +178,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col justify-between gap-3 mb-4 md:flex-row">
|
||||
<div class="flex flex-col justify-between gap-3 md:flex-row">
|
||||
<div
|
||||
class="w-full grid gap-y-2 gap-x-1.5 grid-cols-[repeat(auto-fill,minmax(250px,1fr))]"
|
||||
>
|
||||
|
||||
@@ -53,7 +53,6 @@ const closeDropdown = () => emit('closeDropdown');
|
||||
<FilterButton
|
||||
right-icon="chevron-down"
|
||||
:button-text="name"
|
||||
class="bg-slate-50 dark:bg-slate-800 hover:bg-slate-75 dark:hover:bg-slate-800"
|
||||
@click="toggleDropdown"
|
||||
>
|
||||
<template v-if="showMenu && activeFilterType === type" #dropdown>
|
||||
|
||||
@@ -63,8 +63,7 @@ function getDayOfTheWeek(date) {
|
||||
return days[dayIndex];
|
||||
}
|
||||
function getHeatmapLevelClass(value) {
|
||||
if (!value)
|
||||
return 'outline-slate-100 dark:outline-slate-700 dark:bg-slate-700/40 bg-slate-50/50';
|
||||
if (!value) return 'outline-n-container dark:bg-slate-700/40 bg-slate-50/50';
|
||||
|
||||
let level = [...quantileRange.value, Infinity].findIndex(
|
||||
range => value <= range && value > 0
|
||||
@@ -73,7 +72,7 @@ function getHeatmapLevelClass(value) {
|
||||
if (level > 6) level = 5;
|
||||
|
||||
if (level === 0) {
|
||||
return 'outline-slate-100 dark:outline-slate-700 dark:bg-slate-700/40 bg-slate-50/50';
|
||||
return 'outline-n-container dark:bg-slate-700/40 bg-slate-50/50';
|
||||
}
|
||||
|
||||
const classes = [
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
headerTitle: {
|
||||
required: true,
|
||||
type: String,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-between w-full h-20 gap-2">
|
||||
<span class="text-xl font-medium text-n-slate-12">
|
||||
{{ headerTitle }}
|
||||
</span>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
@@ -22,26 +22,23 @@ defineProps({
|
||||
<template>
|
||||
<div
|
||||
data-test-id="reportMetricContainer"
|
||||
class="p-4 m-0"
|
||||
:class="{
|
||||
'grayscale pointer-events-none opacity-30': disabled,
|
||||
}"
|
||||
>
|
||||
<h3
|
||||
class="flex items-center m-0 text-sm font-medium text-slate-800 dark:text-slate-100"
|
||||
>
|
||||
<h3 class="flex items-center m-0 text-sm font-medium text-n-slate-11">
|
||||
<span data-test-id="reportMetricLabel">{{ label }}</span>
|
||||
<fluent-icon
|
||||
v-tooltip="infoText"
|
||||
data-test-id="reportMetricInfo"
|
||||
size="14"
|
||||
icon="info"
|
||||
class="text-slate-500 dark:text-slate-200 my-0 mx-1 mt-0.5"
|
||||
class="text-n-slate-11 my-0 mx-1 mt-0.5"
|
||||
/>
|
||||
</h3>
|
||||
<h4
|
||||
data-test-id="reportMetricValue"
|
||||
class="mt-1 mb-0 text-3xl font-thin text-slate-700 dark:text-slate-100"
|
||||
class="mt-1 mb-0 text-2xl text-n-slate-12"
|
||||
>
|
||||
{{ value }}
|
||||
</h4>
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<div
|
||||
class="reports--wrapper overflow-auto bg-n-background w-full px-8 xl:px-0"
|
||||
>
|
||||
<div class="max-w-[960px] mx-auto pb-12">
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.reports--wrapper {
|
||||
::v-deep {
|
||||
.multiselect--disabled {
|
||||
@apply opacity-50 border border-n-weak rounded-md cursor-not-allowed;
|
||||
}
|
||||
|
||||
.multiselect__content-wrapper {
|
||||
@apply bg-n-solid-2 border border-n-weak text-n-slate-12;
|
||||
}
|
||||
|
||||
.multiselect__tags {
|
||||
@apply bg-n-slate-1 border border-n-weak m-0 min-h-[2.875rem] pt-0;
|
||||
|
||||
input[type='text'] {
|
||||
@apply bg-n-alpha-3 border-n-weak !min-h-[2.375rem] !h-[2.375rem] !ps-0.5 !py-0 !text-sm;
|
||||
}
|
||||
}
|
||||
|
||||
.multiselect__placeholder {
|
||||
@apply text-n-slate-11;
|
||||
}
|
||||
|
||||
.multiselect__select {
|
||||
@apply min-h-0;
|
||||
}
|
||||
|
||||
.multiselect__single {
|
||||
@apply bg-n-alpha-3 text-n-slate-11;
|
||||
}
|
||||
|
||||
.multiselect__input {
|
||||
@apply text-sm !h-[2.375rem] mb-0 !py-0;
|
||||
}
|
||||
|
||||
.multiselect__tags,
|
||||
.multiselect__input,
|
||||
.multiselect {
|
||||
@apply bg-n-alpha-3 !border-n-weak text-n-slate-12 rounded-lg text-sm min-h-[2.5rem];
|
||||
}
|
||||
|
||||
.mx-input-wrapper {
|
||||
@apply bg-n-alpha-3 !border-n-weak text-n-slate-12 rounded-lg text-sm;
|
||||
|
||||
input {
|
||||
@apply border-n-weak text-sm;
|
||||
}
|
||||
}
|
||||
|
||||
.multiselect__option {
|
||||
@apply flex items-center;
|
||||
}
|
||||
|
||||
.mx-datepicker {
|
||||
.mx-input {
|
||||
@apply bg-n-alpha-3;
|
||||
}
|
||||
|
||||
.mx-input-wrapper input::placeholder {
|
||||
@apply text-n-slate-11;
|
||||
}
|
||||
|
||||
.mx-input-wrapper input {
|
||||
@apply text-n-slate-11;
|
||||
}
|
||||
}
|
||||
|
||||
.multiselect--active:not(.multiselect--above) .multiselect__current,
|
||||
.multiselect--active:not(.multiselect--above) .multiselect__input,
|
||||
.multiselect--active:not(.multiselect--above) .multiselect__tags {
|
||||
@apply rounded-b-none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -24,7 +24,7 @@ export default {
|
||||
<template>
|
||||
<div class="flex flex-col gap-2 items-start justify-center min-w-[10rem]">
|
||||
<span
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-slate-700 dark:text-slate-200"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-n-slate-11"
|
||||
>
|
||||
{{ label }}
|
||||
<fluent-icon
|
||||
@@ -32,15 +32,15 @@ export default {
|
||||
size="14"
|
||||
icon="information"
|
||||
type="outline"
|
||||
class="flex flex-shrink-0 text-sm font-normal sm:font-medium text-slate-500 dark:text-slate-500"
|
||||
class="flex flex-shrink-0 text-sm font-normal sm:font-medium text-n-slate-10"
|
||||
/>
|
||||
</span>
|
||||
<div
|
||||
v-if="isLoading"
|
||||
class="w-12 h-6 mb-0.5 rounded-md bg-slate-50 dark:bg-slate-800 animate-pulse"
|
||||
class="w-12 h-6 mb-0.5 rounded-md bg-n-slate-3 animate-pulse"
|
||||
/>
|
||||
|
||||
<span v-else class="text-2xl font-medium text-slate-900 dark:text-slate-25">
|
||||
<span v-else class="text-2xl font-medium text-n-slate-12">
|
||||
{{ value }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -22,7 +22,7 @@ defineProps({
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex sm:flex-row flex-col w-full gap-4 sm:gap-14 bg-white dark:bg-slate-900 rounded-xl border border-slate-75 dark:border-slate-700/50 px-6 py-4"
|
||||
class="flex sm:flex-row flex-col w-full gap-4 sm:gap-14 shadow outline-1 outline outline-n-container rounded-xl bg-n-solid-2 px-6 py-5"
|
||||
>
|
||||
<SLAMetricCard
|
||||
:label="$t('SLA_REPORTS.METRICS.HIT_RATE.LABEL')"
|
||||
@@ -31,18 +31,14 @@ defineProps({
|
||||
:is-loading="isLoading"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="w-full sm:w-px h-full border border-slate-75 dark:border-slate-700/50"
|
||||
/>
|
||||
<div class="w-full sm:w-px bg-n-strong" />
|
||||
<SLAMetricCard
|
||||
:label="$t('SLA_REPORTS.METRICS.NO_OF_MISSES.LABEL')"
|
||||
:value="noOfBreaches"
|
||||
:tool-tip="$t('SLA_REPORTS.METRICS.NO_OF_MISSES.TOOLTIP')"
|
||||
:is-loading="isLoading"
|
||||
/>
|
||||
<div
|
||||
class="w-full sm:w-px h-full border border-slate-75 dark:border-slate-700/50"
|
||||
/>
|
||||
<div class="w-full sm:w-px bg-n-strong" />
|
||||
<SLAMetricCard
|
||||
:label="$t('SLA_REPORTS.METRICS.NO_OF_CONVERSATIONS.LABEL')"
|
||||
:value="noOfConversations"
|
||||
|
||||
@@ -31,22 +31,23 @@ const conversationLabels = computed(() => {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="grid items-center content-center w-full h-16 grid-cols-12 gap-4 px-6 py-0 bg-white border-b last:border-b-0 last:rounded-b-xl border-slate-75 dark:border-slate-800/50 dark:bg-slate-900"
|
||||
class="grid items-center content-center w-full h-16 grid-cols-12 gap-4 px-6 py-0 border-b last:border-b-0 last:rounded-b-xl border-n-weak"
|
||||
>
|
||||
<div
|
||||
class="flex items-center gap-2 col-span-6 px-0 py-2 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 rtl:text-right"
|
||||
>
|
||||
<span class="text-slate-700 dark:text-slate-200">
|
||||
<span class="text-n-slate-12">
|
||||
{{ `#${conversationId} ` }}
|
||||
</span>
|
||||
<span class="text-slate-600 dark:text-slate-300">
|
||||
<span class="text-slate-11">
|
||||
{{ $t('SLA_REPORTS.WITH') }}
|
||||
</span>
|
||||
<span class="capitalize truncate text-slate-700 dark:text-slate-200">{{
|
||||
<span class="capitalize truncate text-n-slate-12">{{
|
||||
conversation.contact.name
|
||||
}}</span>
|
||||
<CardLabels
|
||||
class="w-[80%]"
|
||||
v-if="conversationLabels.length"
|
||||
class="w-[60%]"
|
||||
:conversation-id="conversationId"
|
||||
:conversation-labels="conversationLabels"
|
||||
/>
|
||||
@@ -61,7 +62,7 @@ const conversationLabels = computed(() => {
|
||||
v-if="conversation.assignee"
|
||||
:user="conversation.assignee"
|
||||
/>
|
||||
<span v-else class="text-slate-600 dark:text-slate-200"> --- </span>
|
||||
<span v-else class="text-n-slate-11"> --- </span>
|
||||
</div>
|
||||
<SLAViewDetails :sla-events="slaEvents" />
|
||||
</div>
|
||||
|
||||
@@ -57,10 +57,10 @@ export default {
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
class="min-w-full border rounded-xl border-slate-75 dark:border-slate-700/50"
|
||||
class="min-w-full shadow outline-1 outline outline-n-container rounded-xl bg-n-solid-2 p-6"
|
||||
>
|
||||
<div
|
||||
class="grid content-center h-12 grid-cols-12 gap-4 px-6 py-0 border-b bg-slate-25 border-slate-75 dark:border-slate-800 rounded-t-xl dark:bg-slate-900"
|
||||
class="grid content-center h-12 grid-cols-12 gap-4 px-6 py-0 bg-n-slate-2 rounded-md"
|
||||
>
|
||||
<TableHeaderCell
|
||||
:span="6"
|
||||
@@ -74,13 +74,10 @@ export default {
|
||||
:span="2"
|
||||
:label="$t('SLA_REPORTS.TABLE.HEADER.AGENT')"
|
||||
/>
|
||||
<TableHeaderCell :span="2" label="" />
|
||||
<TableHeaderCell :span="1" label="" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="isLoading"
|
||||
class="flex items-center justify-center h-32 bg-white rounded-b-xl dark:bg-slate-900"
|
||||
>
|
||||
<div v-if="isLoading" class="flex items-center justify-center h-32">
|
||||
<Spinner />
|
||||
<span>{{ $t('SLA_REPORTS.LOADING') }}</span>
|
||||
</div>
|
||||
@@ -94,10 +91,7 @@ export default {
|
||||
:sla-events="slaReport.sla_events"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="flex items-center justify-center h-32 bg-white rounded-b-xl dark:bg-slate-900"
|
||||
>
|
||||
<div v-else class="flex items-center justify-center h-32">
|
||||
{{ $t('SLA_REPORTS.NO_RECORDS') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -29,24 +29,23 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-on-clickaway="closeSlaEvents" class="label-wrap">
|
||||
<div
|
||||
class="flex items-center col-span-2 px-0 py-2 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 rtl:text-right"
|
||||
>
|
||||
<div class="relative">
|
||||
<woot-button
|
||||
color-scheme="secondary"
|
||||
variant="link"
|
||||
@click="openSlaEvents"
|
||||
>
|
||||
{{ $t('SLA_REPORTS.TABLE.VIEW_DETAILS') }}
|
||||
</woot-button>
|
||||
<SLAPopoverCard
|
||||
v-if="showSlaPopoverCard"
|
||||
:sla-missed-events="slaEvents"
|
||||
class="right-0"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-on-clickaway="closeSlaEvents"
|
||||
class="flex items-center col-span-2 text-slate-11 justify-end"
|
||||
>
|
||||
<div class="relative">
|
||||
<woot-button
|
||||
color-scheme="secondary"
|
||||
variant="link"
|
||||
@click="openSlaEvents"
|
||||
>
|
||||
{{ $t('SLA_REPORTS.TABLE.VIEW_DETAILS') }}
|
||||
</woot-button>
|
||||
<SLAPopoverCard
|
||||
v-if="showSlaPopoverCard"
|
||||
:sla-missed-events="slaEvents"
|
||||
class="right-0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<script>
|
||||
import V4Button from 'dashboard/components-next/button/Button.vue';
|
||||
import { useAlert, useTrack } from 'dashboard/composables';
|
||||
import ReportFilters from './ReportFilters.vue';
|
||||
import ReportContainer from '../ReportContainer.vue';
|
||||
import { GROUP_BY_FILTER } from '../constants';
|
||||
import { generateFileName } from '../../../../../helper/downloadHelper';
|
||||
import { REPORTS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
|
||||
import ReportHeader from './ReportHeader.vue';
|
||||
|
||||
const GROUP_BY_OPTIONS = {
|
||||
DAY: [{ id: 1, groupByKey: 'REPORT.GROUPING_OPTIONS.DAY' }],
|
||||
@@ -26,6 +28,8 @@ const GROUP_BY_OPTIONS = {
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ReportHeader,
|
||||
V4Button,
|
||||
ReportFilters,
|
||||
ReportContainer,
|
||||
},
|
||||
@@ -46,6 +50,10 @@ export default {
|
||||
type: String,
|
||||
default: 'Download Reports',
|
||||
},
|
||||
reportTitle: {
|
||||
type: String,
|
||||
default: 'Download Reports',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -198,30 +206,29 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex-1 p-4 overflow-auto">
|
||||
<woot-button
|
||||
color-scheme="success"
|
||||
class-names="button--fixed-top"
|
||||
icon="arrow-download"
|
||||
<ReportHeader :header-title="reportTitle">
|
||||
<V4Button
|
||||
:label="downloadButtonLabel"
|
||||
icon="i-ph-download-simple"
|
||||
size="sm"
|
||||
@click="downloadReports"
|
||||
>
|
||||
{{ downloadButtonLabel }}
|
||||
</woot-button>
|
||||
<ReportFilters
|
||||
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"
|
||||
@business-hours-toggle="onBusinessHoursToggle"
|
||||
/>
|
||||
<ReportContainer
|
||||
v-if="filterItemsList.length"
|
||||
:group-by="groupBy"
|
||||
:report-keys="reportKeys"
|
||||
/>
|
||||
</div>
|
||||
</ReportHeader>
|
||||
|
||||
<ReportFilters
|
||||
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"
|
||||
@business-hours-toggle="onBusinessHoursToggle"
|
||||
/>
|
||||
<ReportContainer
|
||||
v-if="filterItemsList.length"
|
||||
:group-by="groupBy"
|
||||
:report-keys="reportKeys"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -144,10 +144,7 @@ const table = useVueTable({
|
||||
|
||||
<template>
|
||||
<div class="agent-table-container">
|
||||
<Table
|
||||
:table="table"
|
||||
class="max-h-[calc(100vh-21.875rem)] border border-slate-50 dark:border-slate-800"
|
||||
/>
|
||||
<Table :table="table" class="max-h-[calc(100vh-21.875rem)]" />
|
||||
<Pagination class="mt-2" :table="table" />
|
||||
<div v-if="isLoading" class="agents-loader">
|
||||
<Spinner />
|
||||
@@ -169,7 +166,7 @@ const table = useVueTable({
|
||||
.ve-table {
|
||||
&::v-deep {
|
||||
th.ve-table-header-th {
|
||||
font-size: var(--font-size-mini) !important;
|
||||
@apply text-sm rounded-xl;
|
||||
padding: var(--space-small) var(--space-two) !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,25 +25,23 @@ export default {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="metric-card mb-2 p flex flex-col m-2 p-4 border border-solid overflow-hidden rounded-md flex-grow shadow-sm text-slate-700 dark:text-slate-100 bg-white dark:bg-slate-800 border-slate-75 dark:border-slate-700 min-h-[10rem]"
|
||||
class="flex flex-col m-0.5 px-6 py-5 overflow-hidden rounded-xl flex-grow text-n-slate-12 shadow outline-1 outline outline-n-container bg-n-solid-2 min-h-[10rem]"
|
||||
>
|
||||
<div
|
||||
class="card-header grid w-full mb-6 grid-cols-[repeat(auto-fit,minmax(max-content,50%))] gap-y-2"
|
||||
>
|
||||
<slot name="header">
|
||||
<div class="flex items-center gap-0.5 flex-row">
|
||||
<h5
|
||||
class="mb-0 text-slate-800 dark:text-slate-100 font-medium text-xl"
|
||||
>
|
||||
<div class="flex items-center gap-2 flex-row">
|
||||
<h5 class="mb-0 text-n-slate-12 font-medium text-lg">
|
||||
{{ header }}
|
||||
</h5>
|
||||
<span
|
||||
class="flex flex-row items-center pr-2 pl-2 m-1 rounded-sm text-green-400 dark:text-green-400 text-xs bg-green-100/30 dark:bg-green-100/20"
|
||||
class="flex flex-row items-center py-0.5 px-2 rounded bg-n-teal-3 text-xs"
|
||||
>
|
||||
<span
|
||||
class="bg-green-500 dark:bg-green-500 h-1 w-1 rounded-full mr-1 rtl:mr-0 rtl:ml-0"
|
||||
class="bg-n-teal-9 h-1 w-1 rounded-full mr-1 rtl:mr-0 rtl:ml-0"
|
||||
/>
|
||||
<span>
|
||||
<span class="text-xs text-n-teal-11">
|
||||
{{ $t('OVERVIEW_REPORTS.LIVE') }}
|
||||
</span>
|
||||
</span>
|
||||
@@ -66,7 +64,7 @@ export default {
|
||||
class="items-center flex text-base justify-center px-12 py-6"
|
||||
>
|
||||
<Spinner />
|
||||
<span class="text-slate-300 dark:text-slate-200">
|
||||
<span class="text-n-slate-11">
|
||||
{{ loadingMessage }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`CsatMetrics.vue > computes response count correctly 1`] = `
|
||||
"<div class="flex-col lg:flex-row flex flex-wrap mx-0 bg-white dark:bg-slate-800 rounded-[4px] p-4 mb-5 border border-solid border-slate-75 dark:border-slate-700">
|
||||
"<div class="flex-col lg:flex-row flex flex-wrap mx-0 shadow outline-1 outline outline-n-container rounded-xl bg-n-solid-2 px-6 py-8 gap-4">
|
||||
<csat-metric-card-stub label="CSAT_REPORTS.METRIC.TOTAL_RESPONSES.LABEL" infotext="CSAT_REPORTS.METRIC.TOTAL_RESPONSES.TOOLTIP" disabled="false" class="xs:w-full sm:max-w-[50%] lg:w-1/6 lg:max-w-[16%]" value="100"></csat-metric-card-stub>
|
||||
<csat-metric-card-stub label="CSAT_REPORTS.METRIC.SATISFACTION_SCORE.LABEL" infotext="CSAT_REPORTS.METRIC.SATISFACTION_SCORE.TOOLTIP" disabled="true" class="xs:w-full sm:max-w-[50%] lg:w-1/6 lg:max-w-[16%]" value="--"></csat-metric-card-stub>
|
||||
<csat-metric-card-stub label="CSAT_REPORTS.METRIC.RESPONSE_RATE.LABEL" infotext="CSAT_REPORTS.METRIC.RESPONSE_RATE.TOOLTIP" disabled="false" class="xs:w-full sm:max-w-[50%] lg:w-1/6 lg:max-w-[16%]" value="90%"></csat-metric-card-stub>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { frontendURL } from '../../../../helper/URLHelper';
|
||||
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
||||
|
||||
import SettingsContent from '../Wrapper.vue';
|
||||
import ReportsWrapper from './components/ReportsWrapper.vue';
|
||||
import Index from './Index.vue';
|
||||
import AgentReports from './AgentReports.vue';
|
||||
import LabelReports from './LabelReports.vue';
|
||||
@@ -16,12 +16,7 @@ export default {
|
||||
routes: [
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/reports'),
|
||||
component: SettingsContent,
|
||||
props: {
|
||||
headerTitle: 'OVERVIEW_REPORTS.HEADER',
|
||||
icon: 'arrow-trending-lines',
|
||||
keepAlive: false,
|
||||
},
|
||||
component: ReportsWrapper,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
@@ -37,17 +32,6 @@ export default {
|
||||
},
|
||||
component: LiveReports,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/reports'),
|
||||
component: SettingsContent,
|
||||
props: {
|
||||
headerTitle: 'REPORT.HEADER',
|
||||
icon: 'chat',
|
||||
keepAlive: false,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'conversation',
|
||||
name: 'conversation_reports',
|
||||
@@ -56,56 +40,6 @@ export default {
|
||||
},
|
||||
component: Index,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/reports'),
|
||||
component: SettingsContent,
|
||||
props: {
|
||||
headerTitle: 'CSAT_REPORTS.HEADER',
|
||||
icon: 'emoji',
|
||||
keepAlive: false,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'csat',
|
||||
name: 'csat_reports',
|
||||
meta: {
|
||||
permissions: ['administrator', 'report_manage'],
|
||||
},
|
||||
component: CsatResponses,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/reports'),
|
||||
component: SettingsContent,
|
||||
props: {
|
||||
headerTitle: 'BOT_REPORTS.HEADER',
|
||||
icon: 'bot',
|
||||
keepAlive: false,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'bot',
|
||||
name: 'bot_reports',
|
||||
meta: {
|
||||
permissions: ['administrator', 'report_manage'],
|
||||
featureFlag: FEATURE_FLAGS.RESPONSE_BOT,
|
||||
},
|
||||
component: BotReports,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/reports'),
|
||||
component: SettingsContent,
|
||||
props: {
|
||||
headerTitle: 'AGENT_REPORTS.HEADER',
|
||||
icon: 'people',
|
||||
keepAlive: false,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'agent',
|
||||
name: 'agent_reports',
|
||||
@@ -114,17 +48,6 @@ export default {
|
||||
},
|
||||
component: AgentReports,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/reports'),
|
||||
component: SettingsContent,
|
||||
props: {
|
||||
headerTitle: 'LABEL_REPORTS.HEADER',
|
||||
icon: 'tag',
|
||||
keepAlive: false,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'label',
|
||||
name: 'label_reports',
|
||||
@@ -133,17 +56,6 @@ export default {
|
||||
},
|
||||
component: LabelReports,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/reports'),
|
||||
component: SettingsContent,
|
||||
props: {
|
||||
headerTitle: 'INBOX_REPORTS.HEADER',
|
||||
icon: 'mail-inbox-all',
|
||||
keepAlive: false,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'inboxes',
|
||||
name: 'inbox_reports',
|
||||
@@ -152,16 +64,6 @@ export default {
|
||||
},
|
||||
component: InboxReports,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/reports'),
|
||||
component: SettingsContent,
|
||||
props: {
|
||||
headerTitle: 'TEAM_REPORTS.HEADER',
|
||||
icon: 'people-team',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'teams',
|
||||
name: 'team_reports',
|
||||
@@ -170,17 +72,6 @@ export default {
|
||||
},
|
||||
component: TeamReports,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/reports'),
|
||||
component: SettingsContent,
|
||||
props: {
|
||||
headerTitle: 'SLA_REPORTS.HEADER',
|
||||
icon: 'document-list-clock',
|
||||
keepAlive: false,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'sla',
|
||||
name: 'sla_reports',
|
||||
@@ -190,6 +81,22 @@ export default {
|
||||
},
|
||||
component: SLAReports,
|
||||
},
|
||||
{
|
||||
path: 'csat',
|
||||
name: 'csat_reports',
|
||||
meta: {
|
||||
permissions: ['administrator', 'report_manage'],
|
||||
},
|
||||
component: CsatResponses,
|
||||
},
|
||||
{
|
||||
path: 'bot',
|
||||
name: 'bot_reports',
|
||||
meta: {
|
||||
permissions: ['administrator', 'report_manage'],
|
||||
},
|
||||
component: BotReports,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user