From 88deecd02eaa55dc628d9a63267697f2fdfa0e4a Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 3 Sep 2025 12:05:20 +0530 Subject: [PATCH] feat: add inbox filter --- .../dashboard/i18n/locale/en/report.json | 2 + .../reports/components/HeatmapContainer.vue | 110 +++++++++++++++++- 2 files changed, 107 insertions(+), 5 deletions(-) diff --git a/app/javascript/dashboard/i18n/locale/en/report.json b/app/javascript/dashboard/i18n/locale/en/report.json index 7c42fdfba..9c3c0a94a 100644 --- a/app/javascript/dashboard/i18n/locale/en/report.json +++ b/app/javascript/dashboard/i18n/locale/en/report.json @@ -266,6 +266,8 @@ "NO_ENOUGH_DATA": "We've not received enough data points to generate report, Please try again later.", "DOWNLOAD_INBOX_REPORTS": "Download inbox reports", "FILTER_DROPDOWN_LABEL": "Select Inbox", + "ALL_INBOXES": "All Inboxes", + "SEARCH_INBOX": "Search Inbox", "METRICS": { "CONVERSATIONS": { "NAME": "Conversations", diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/components/HeatmapContainer.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/components/HeatmapContainer.vue index 280e1d6ee..db1a8e650 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/reports/components/HeatmapContainer.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/reports/components/HeatmapContainer.vue @@ -9,9 +9,11 @@ import endOfDay from 'date-fns/endOfDay'; import getUnixTime from 'date-fns/getUnixTime'; import startOfDay from 'date-fns/startOfDay'; import subDays from 'date-fns/subDays'; +import format from 'date-fns/format'; import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue'; import Button from 'dashboard/components-next/button/Button.vue'; import { useI18n } from 'vue-i18n'; +import { downloadCsvFile } from 'dashboard/helper/downloadHelper'; const store = useStore(); @@ -19,6 +21,7 @@ const uiFlags = useMapGetter('getOverviewUIFlags'); const accountConversationHeatmap = useMapGetter( 'getAccountConversationHeatmapData' ); +const inboxes = useMapGetter('inboxes/getInboxes'); const { t } = useI18n(); const menuItems = [ @@ -33,19 +36,78 @@ const menuItems = [ ]; const selectedDays = ref(6); +const selectedInbox = ref(null); const selectedDayFilter = computed(() => menuItems.find(menuItem => menuItem.value === selectedDays.value) ); +const inboxMenuItems = computed(() => { + return [ + { + label: t('INBOX_REPORTS.ALL_INBOXES'), + value: null, + }, + ...inboxes.value.map(inbox => ({ + label: inbox.name, + value: inbox.id, + })), + ]; +}); + +const selectedInboxFilter = computed(() => { + if (!selectedInbox.value) { + return { label: t('INBOX_REPORTS.ALL_INBOXES') }; + } + return inboxMenuItems.value.find( + item => item.value === selectedInbox.value.id + ); +}); + const downloadHeatmapData = () => { const to = endOfDay(new Date()); - store.dispatch('downloadAccountConversationHeatmap', { - daysBefore: selectedDays.value, - to: getUnixTime(to), + + // If no inbox is selected, use the existing backend CSV endpoint + if (!selectedInbox.value) { + store.dispatch('downloadAccountConversationHeatmap', { + daysBefore: selectedDays.value, + to: getUnixTime(to), + }); + return; + } + + // If inbox is selected, generate CSV from store data + if ( + !accountConversationHeatmap.value || + accountConversationHeatmap.value.length === 0 + ) { + return; + } + + // Create CSV headers + const headers = ['Date', 'Hour', 'Conversations Count']; + const rows = [headers]; + + // Convert heatmap data to rows + accountConversationHeatmap.value.forEach(item => { + const date = new Date(item.timestamp * 1000); + const dateStr = format(date, 'yyyy-MM-dd'); + const hour = date.getHours(); + rows.push([dateStr, `${hour}:00 - ${hour + 1}:00`, item.value]); }); + + // Convert to CSV string + const csvContent = rows.map(row => row.join(',')).join('\n'); + + // Generate filename with inbox name + const inboxName = selectedInbox.value.name.replace(/[^a-z0-9]/gi, '_'); + const fileName = `conversation_heatmap_${inboxName}_${format(new Date(), 'dd-MM-yyyy')}.csv`; + + // Download the file + downloadCsvFile(fileName, csvContent); }; const [showDropdown, toggleDropdown] = useToggle(); +const [showInboxDropdown, toggleInboxDropdown] = useToggle(); const fetchHeatmapData = () => { if (uiFlags.value.isFetchingAccountConversationsHeatmap) { return; @@ -54,13 +116,21 @@ const fetchHeatmapData = () => { let to = endOfDay(new Date()); let from = startOfDay(subDays(to, Number(selectedDays.value))); - store.dispatch('fetchAccountConversationHeatmap', { + const params = { metric: 'conversations_count', from: getUnixTime(from), to: getUnixTime(to), groupBy: 'hour', businessHours: false, - }); + }; + + // Add inbox filtering if an inbox is selected + if (selectedInbox.value) { + params.type = 'inbox'; + params.id = selectedInbox.value.id; + } + + store.dispatch('fetchAccountConversationHeatmap', params); }; const handleAction = ({ value }) => { @@ -69,9 +139,18 @@ const handleAction = ({ value }) => { fetchHeatmapData(); }; +const handleInboxAction = ({ value }) => { + toggleInboxDropdown(false); + selectedInbox.value = value + ? inboxes.value.find(inbox => inbox.id === value) + : null; + fetchHeatmapData(); +}; + const { startRefetching } = useLiveRefresh(fetchHeatmapData); onMounted(() => { + store.dispatch('inboxes/get'); fetchHeatmapData(); startRefetching(); }); @@ -100,6 +179,27 @@ onMounted(() => { @action="handleAction($event)" /> +
+