Merge branch 'develop' into feat/v5-ui-redesign
This commit is contained in:
@@ -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`)"
|
||||
|
||||
Reference in New Issue
Block a user