Merge branch 'develop' into feat/v5-ui-redesign

This commit is contained in:
Sivin Varghese
2026-01-07 15:58:29 +05:30
committed by GitHub
55 changed files with 3976 additions and 387 deletions
@@ -4,6 +4,8 @@ import { useMapGetter, useStore } from 'dashboard/composables/store.js';
import { useRouter, useRoute } from 'vue-router';
import { useTrack } from 'dashboard/composables';
import { useI18n } from 'vue-i18n';
import { useCamelCase } from 'dashboard/composables/useTransformKeys';
import { generateURLParams, parseURLParams } from '../helpers/searchHelper';
import {
ROLES,
CONVERSATION_PERMISSIONS,
@@ -47,7 +49,7 @@ const articleRecords = useMapGetter('conversationSearch/getArticleRecords');
const uiFlags = useMapGetter('conversationSearch/getUIFlags');
const addTypeToRecords = (records, type) =>
records.value.map(item => ({ ...item, type }));
records.value.map(item => ({ ...useCamelCase(item, { deep: true }), type }));
const mappedContacts = computed(() =>
addTypeToRecords(contactRecords, 'contact')
@@ -64,6 +66,11 @@ const mappedArticles = computed(() =>
const isSelectedTabAll = computed(() => selectedTab.value === 'all');
const searchResultSectionClass = computed(() => ({
'mt-4': isSelectedTabAll.value,
'mt-0.5': !isSelectedTabAll.value,
}));
const sliceRecordsIfAllTab = items =>
isSelectedTabAll.value ? items.value.slice(0, 5) : items.value;
@@ -227,30 +234,55 @@ const showViewMore = computed(() => ({
articles: mappedArticles.value?.length > 5 && isSelectedTabAll.value,
}));
const filters = ref({
from: null,
in: null,
dateRange: { type: null, from: null, to: null },
});
const clearSearchResult = () => {
pages.value = { contacts: 1, conversations: 1, messages: 1, articles: 1 };
store.dispatch('conversationSearch/clearSearchResults');
};
const buildSearchPayload = (basePayload = {}, searchType = 'message') => {
const payload = { ...basePayload };
// Only include filters if advanced search is enabled
if (isFeatureFlagEnabled(FEATURE_FLAGS.ADVANCED_SEARCH)) {
// Date filters apply to all search types
if (filters.value.dateRange.from) {
payload.since = filters.value.dateRange.from;
}
if (filters.value.dateRange.to) {
payload.until = filters.value.dateRange.to;
}
// Only messages support 'from' and 'inboxId' filters
if (searchType === 'message') {
if (filters.value.from) payload.from = filters.value.from;
if (filters.value.in) payload.inboxId = filters.value.in;
}
}
return payload;
};
const updateURL = () => {
// Update route with tab as URL parameter and query as query parameter
const params = { accountId: route.params.accountId };
const queryParams = {};
const params = {
accountId: route.params.accountId,
...(selectedTab.value !== 'all' && { tab: selectedTab.value }),
};
// Only add tab param if not 'all'
if (selectedTab.value !== 'all') {
params.tab = selectedTab.value;
}
const queryParams = {
...(query.value?.trim() && { q: query.value.trim() }),
...generateURLParams(
filters.value,
isFeatureFlagEnabled(FEATURE_FLAGS.ADVANCED_SEARCH)
),
};
if (query.value?.trim()) {
queryParams.q = query.value.trim();
}
router.replace({
name: 'search',
params,
query: queryParams,
});
router.replace({ name: 'search', params, query: queryParams });
};
const onSearch = q => {
@@ -259,7 +291,13 @@ const onSearch = q => {
updateURL();
if (!q) return;
useTrack(CONVERSATION_EVENTS.SEARCH_CONVERSATION);
store.dispatch('conversationSearch/fullSearch', { q, page: 1 });
const searchPayload = buildSearchPayload({ q, page: 1 });
store.dispatch('conversationSearch/fullSearch', searchPayload);
};
const onFilterChange = () => {
onSearch(query.value);
};
const onBack = () => {
@@ -280,12 +318,16 @@ const loadMore = () => {
};
if (uiFlags.value.isFetching || selectedTab.value === 'all') return;
const tab = selectedTab.value;
pages.value[tab] += 1;
store.dispatch(SEARCH_ACTIONS[tab], {
q: query.value,
page: pages.value[tab],
});
const payload = buildSearchPayload(
{ q: query.value, page: pages.value[tab] },
tab
);
store.dispatch(SEARCH_ACTIONS[tab], payload);
};
const onTabChange = tab => {
@@ -295,6 +337,13 @@ const onTabChange = tab => {
onMounted(() => {
store.dispatch('conversationSearch/clearSearchResults');
store.dispatch('agents/get');
const parsedFilters = parseURLParams(
route.query,
isFeatureFlagEnabled(FEATURE_FLAGS.ADVANCED_SEARCH)
);
filters.value = parsedFilters;
// Auto-execute search if query parameter exists
if (route.query.q) {
@@ -321,9 +370,14 @@ onUnmounted(() => {
/>
</div>
<section class="flex flex-col flex-grow w-full h-full overflow-hidden">
<div class="w-full max-w-4xl mx-auto">
<div class="w-full max-w-5xl mx-auto z-[60]">
<div class="flex flex-col w-full px-4">
<SearchHeader :initial-query="query" @search="onSearch" />
<SearchHeader
v-model:filters="filters"
:initial-query="query"
@search="onSearch"
@filter-change="onFilterChange"
/>
<SearchTabs
v-if="query"
:tabs="tabs"
@@ -333,7 +387,7 @@ onUnmounted(() => {
</div>
</div>
<div class="flex-grow w-full h-full overflow-y-auto">
<div class="w-full max-w-4xl mx-auto px-4 pb-6">
<div class="w-full max-w-5xl mx-auto px-4 pb-6">
<div v-if="showResultsSection">
<Policy
:permissions="[...ROLES, CONTACT_PERMISSIONS]"
@@ -345,6 +399,7 @@ onUnmounted(() => {
:contacts="contacts"
:query="query"
:show-title="isSelectedTabAll"
class="mt-0.5"
/>
<NextButton
v-if="showViewMore.contacts"
@@ -367,6 +422,7 @@ onUnmounted(() => {
:messages="messages"
:query="query"
:show-title="isSelectedTabAll"
:class="searchResultSectionClass"
/>
<NextButton
v-if="showViewMore.messages"
@@ -389,6 +445,7 @@ onUnmounted(() => {
:conversations="conversations"
:query="query"
:show-title="isSelectedTabAll"
:class="searchResultSectionClass"
/>
<NextButton
v-if="showViewMore.conversations"
@@ -413,6 +470,7 @@ onUnmounted(() => {
:articles="articles"
:query="query"
:show-title="isSelectedTabAll"
:class="searchResultSectionClass"
/>
<NextButton
v-if="showViewMore.articles"
@@ -425,7 +483,7 @@ onUnmounted(() => {
/>
</Policy>
<div v-if="showLoadMore" class="flex justify-center mt-4 mb-6">
<div v-if="showLoadMore" class="flex justify-center mt-3 mb-6">
<NextButton
v-if="!isSelectedTabAll"
:label="t(`SEARCH.LOAD_MORE`)"