feat: Search improvements for conversations (#6645)

* feat: Shows search as a popover

* Reverts search from popover to page

* Fixes review comments on usability

* Fixes keyboard navigation issues
This commit is contained in:
Nithin David Thomas
2023-03-14 13:09:43 +05:30
committed by GitHub
parent da76537011
commit cae3ac94cd
10 changed files with 203 additions and 98 deletions

View File

@@ -1,46 +1,63 @@
<template>
<section class="search-root">
<woot-button
color-scheme="secondary"
size="large"
icon="dismiss"
variant="smooth"
class="modal--close"
@click="onBack"
/>
<header>
<search-header @search="search" />
<search-tabs :tabs="tabs" @tab-change="tab => (selectedTab = tab)" />
</header>
<div class="search-results">
<woot-loading-state v-if="uiFlags.isFetching" :message="'Searching'" />
<div v-else>
<div v-if="all.length">
<search-result-contacts-list
v-if="filterContacts"
:contacts="contacts"
:query="query"
/>
<search-result-messages-list
v-if="filterMessages"
:messages="messages"
:query="query"
/>
<search-result-conversations-list
v-if="filterConversations"
:conversations="conversations"
:query="query"
/>
</div>
<div v-else-if="showEmptySearchResults" class="empty">
<fluent-icon icon="info" size="16px" class="icon" />
<p class="empty-state__text">
{{ $t('SEARCH.EMPTY_STATE_FULL', { query }) }}
</p>
<div class="width-100">
<div class="page-header">
<woot-button
icon="chevron-left"
variant="smooth"
size="small "
class="back-button"
@click="onBack"
>
{{ $t('GENERAL_SETTINGS.BACK') }}
</woot-button>
</div>
<section class="search-root">
<header>
<search-header @search="onSearch" />
<search-tabs
v-if="query"
:tabs="tabs"
@tab-change="tab => (selectedTab = tab)"
/>
</header>
<div class="search-results">
<woot-loading-state v-if="uiFlags.isFetching" :message="'Searching'" />
<div v-else>
<div v-if="all.length">
<search-result-contacts-list
v-if="filterContacts"
:contacts="contacts"
:query="query"
/>
<search-result-messages-list
v-if="filterMessages"
:messages="messages"
:query="query"
/>
<search-result-conversations-list
v-if="filterConversations"
:conversations="conversations"
:query="query"
/>
</div>
<div v-else-if="showEmptySearchResults && !all.length" class="empty">
<fluent-icon icon="info" size="16px" class="icon" />
<p class="empty-state__text">
{{ $t('SEARCH.EMPTY_STATE_FULL', { query }) }}
</p>
</div>
<div v-else class="empty text-center">
<p class="text-center">
<fluent-icon icon="search" size="24px" class="icon" />
</p>
<p class="empty-state__text">
{{ $t('SEARCH.EMPTY_STATE_DEFAULT') }}
</p>
</div>
</div>
</div>
</div>
</section>
</section>
</div>
</template>
<script>
@@ -51,6 +68,7 @@ import SearchResultMessagesList from './SearchResultMessagesList.vue';
import SearchResultContactsList from './SearchResultContactsList.vue';
import { isEmptyObject } from 'dashboard/helper/commons.js';
import { mixin as clickaway } from 'vue-clickaway';
import { mapGetters } from 'vuex';
import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events';
export default {
@@ -61,12 +79,14 @@ export default {
SearchResultConversationsList,
SearchResultMessagesList,
},
mixins: [clickaway],
data() {
return {
selectedTab: 'all',
query: '',
};
},
computed: {
...mapGetters({
fullSearchRecords: 'conversationSearch/getFullSearchRecords',
@@ -147,48 +167,68 @@ export default {
);
},
},
beforeDestroy() {
this.query = '';
this.$store.dispatch('conversationSearch/clearSearchResults');
},
mounted() {
this.$store.dispatch('conversationSearch/clearSearchResults');
},
methods: {
search(q) {
onSearch(q) {
this.query = q;
if (!q) {
this.$store.dispatch('conversationSearch/clearSearchResults');
return;
}
this.$track(CONVERSATION_EVENTS.SEARCH_CONVERSATION);
this.$store.dispatch('conversationSearch/fullSearch', { q });
},
onBack() {
this.$router.push({ name: 'home' });
if (window.history.length > 2) {
this.$router.go(-1);
} else {
this.$router.push({ name: 'home' });
}
},
},
};
</script>
<style lang="scss" scoped>
.page-header {
display: flex;
padding: var(--space-normal);
}
.search-root {
max-width: 800px;
width: 100%;
margin: 0 auto;
height: 100%;
max-width: 64rem;
min-height: 48rem;
width: 100%;
height: fit-content;
box-shadow: var(--shadow);
display: flex;
position: relative;
padding: var(--space-normal);
flex-direction: column;
background: white;
border-radius: var(--border-radius-large);
margin-top: var(--space-large);
border-top: 1px solid var(--s-25);
.search-results {
flex-grow: 1;
height: 100%;
max-height: 80vh;
overflow-y: auto;
margin-top: var(--space-normal);
padding: 0 var(--space-small);
}
}
.modal--close {
position: fixed;
right: var(--space-small);
top: var(--space-small);
}
.empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: var(--space-medium) var(--space-normal);
background: var(--s-25);
border-radius: var(--border-radius-medium);
.icon {
color: var(--s-500);
@@ -196,7 +236,7 @@ export default {
.empty-state__text {
text-align: center;
color: var(--s-500);
margin: 0 var(--space-small);
margin: var(--space-small);
}
}
</style>