feat: Adds the ability to have custom view for conversations (#3666)
* feat: Adds the ability to save custom filters and display folders on the sidebar * Minor fixes * Review fixes * Review fixes * i18n fixes * Shows conversations when the user click on the folder sidebar item * Spacing fixes * Review fixes Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
parent
290196d43b
commit
4398734bdf
21 changed files with 594 additions and 23 deletions
|
@ -1,26 +1,39 @@
|
|||
l<template>
|
||||
<template>
|
||||
<div class="conversations-list-wrap">
|
||||
<slot></slot>
|
||||
<div class="chat-list__top" :class="{ filter__applied: hasAppliedFilters }">
|
||||
<div
|
||||
class="chat-list__top"
|
||||
:class="{ filter__applied: hasAppliedFiltersOrActiveCustomViews }"
|
||||
>
|
||||
<h1 class="page-title text-truncate" :title="pageTitle">
|
||||
{{ pageTitle }}
|
||||
</h1>
|
||||
|
||||
<div class="filter--actions">
|
||||
<chat-filter
|
||||
v-if="!hasAppliedFilters"
|
||||
v-if="!hasAppliedFiltersOrActiveCustomViews"
|
||||
@statusFilterChange="updateStatusType"
|
||||
/>
|
||||
<div v-if="hasAppliedFilters && !hasActiveCustomViews">
|
||||
<woot-button
|
||||
v-tooltip.top-end="$t('FILTER.CUSTOM_VIEWS.ADD.SAVE_BUTTON')"
|
||||
size="tiny"
|
||||
variant="smooth"
|
||||
color-scheme="secondary"
|
||||
icon="save"
|
||||
@click="onClickOpenAddCustomViewsModal"
|
||||
/>
|
||||
<woot-button
|
||||
v-tooltip.top-end="$t('FILTER.CLEAR_BUTTON_LABEL')"
|
||||
size="tiny"
|
||||
variant="smooth"
|
||||
color-scheme="alert"
|
||||
icon="dismiss-circle"
|
||||
@click="resetAndFetchData"
|
||||
/>
|
||||
</div>
|
||||
<woot-button
|
||||
v-else
|
||||
size="small"
|
||||
variant="clear"
|
||||
color-scheme="alert"
|
||||
@click="resetAndFetchData"
|
||||
>
|
||||
{{ $t('FILTER.CLEAR_BUTTON_LABEL') }}
|
||||
</woot-button>
|
||||
<woot-button
|
||||
v-if="!hasActiveCustomViews"
|
||||
v-tooltip.top-end="$t('FILTER.TOOLTIP_LABEL')"
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
|
@ -33,8 +46,14 @@ l<template>
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<add-custom-views
|
||||
v-if="showAddCustomViewsModal"
|
||||
:custom-views-query="customViewsQuery"
|
||||
@close="onCloseAddCustomViewsModal"
|
||||
/>
|
||||
|
||||
<chat-type-tabs
|
||||
v-if="!hasAppliedFilters"
|
||||
v-if="!hasAppliedFiltersOrActiveCustomViews"
|
||||
:items="assigneeTabItems"
|
||||
:active-tab="activeAssigneeTab"
|
||||
class="tab--chat-type"
|
||||
|
@ -51,6 +70,7 @@ l<template>
|
|||
:key="chat.id"
|
||||
:active-label="label"
|
||||
:team-id="teamId"
|
||||
:custom-views-id="customViewsId"
|
||||
:chat="chat"
|
||||
:conversation-type="conversationType"
|
||||
:show-assignee="showAssigneeInConversationCard"
|
||||
|
@ -108,6 +128,7 @@ import conversationMixin from '../mixins/conversations';
|
|||
import wootConstants from '../constants';
|
||||
import advancedFilterTypes from './widgets/conversation/advancedFilterItems';
|
||||
import filterQueryGenerator from '../helper/filterQueryGenerator.js';
|
||||
import AddCustomViews from 'dashboard/routes/dashboard/customviews/AddCustomViews';
|
||||
|
||||
import {
|
||||
hasPressedAltAndJKey,
|
||||
|
@ -116,6 +137,7 @@ import {
|
|||
|
||||
export default {
|
||||
components: {
|
||||
AddCustomViews,
|
||||
ChatTypeTabs,
|
||||
ConversationCard,
|
||||
ChatFilter,
|
||||
|
@ -139,6 +161,10 @@ export default {
|
|||
type: String,
|
||||
default: '',
|
||||
},
|
||||
customViewsId: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -149,6 +175,8 @@ export default {
|
|||
...filter,
|
||||
attributeName: this.$t(`FILTER.ATTRIBUTES.${filter.attributeI18nKey}`),
|
||||
})),
|
||||
customViewsQuery: {},
|
||||
showAddCustomViewsModal: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -163,10 +191,24 @@ export default {
|
|||
activeInbox: 'getSelectedInbox',
|
||||
conversationStats: 'conversationStats/getStats',
|
||||
appliedFilters: 'getAppliedConversationFilters',
|
||||
customViews: 'customViews/getCustomViews',
|
||||
}),
|
||||
hasAppliedFilters() {
|
||||
return this.appliedFilters.length;
|
||||
},
|
||||
hasActiveCustomViews() {
|
||||
return this.activeCustomView.length > 0 && this.customViewsId !== 0;
|
||||
},
|
||||
hasAppliedFiltersOrActiveCustomViews() {
|
||||
return this.hasAppliedFilters || this.hasActiveCustomViews;
|
||||
},
|
||||
savedCustomViewsValue() {
|
||||
if (this.hasActiveCustomViews) {
|
||||
const payload = this.activeCustomView[0].query;
|
||||
this.fetchSavedFilteredConversations(payload);
|
||||
}
|
||||
return {};
|
||||
},
|
||||
assigneeTabItems() {
|
||||
return this.$t('CHAT_LIST.ASSIGNEE_TYPE_TABS').map(item => {
|
||||
const count = this.conversationStats[item.COUNT_KEY] || 0;
|
||||
|
@ -189,7 +231,9 @@ export default {
|
|||
);
|
||||
},
|
||||
currentPageFilterKey() {
|
||||
return this.hasAppliedFilters ? 'appliedFilters' : this.activeAssigneeTab;
|
||||
return this.hasAppliedFiltersOrActiveCustomViews
|
||||
? 'appliedFilters'
|
||||
: this.activeAssigneeTab;
|
||||
},
|
||||
currentFiltersPage() {
|
||||
return this.$store.getters['conversationPage/getCurrentPageFilter'](
|
||||
|
@ -212,6 +256,9 @@ export default {
|
|||
conversationType: this.conversationType
|
||||
? this.conversationType
|
||||
: undefined,
|
||||
customViews: this.hasActiveCustomViews
|
||||
? this.savedCustomViewsValue
|
||||
: undefined,
|
||||
};
|
||||
},
|
||||
pageTitle() {
|
||||
|
@ -227,11 +274,14 @@ export default {
|
|||
if (this.conversationType === 'mention') {
|
||||
return this.$t('CHAT_LIST.MENTION_HEADING');
|
||||
}
|
||||
if (this.hasActiveCustomViews) {
|
||||
return this.activeCustomView[0].name;
|
||||
}
|
||||
return this.$t('CHAT_LIST.TAB_HEADING');
|
||||
},
|
||||
conversationList() {
|
||||
let conversationList = [];
|
||||
if (!this.hasAppliedFilters) {
|
||||
if (!this.hasAppliedFiltersOrActiveCustomViews) {
|
||||
const filters = this.conversationFilters;
|
||||
if (this.activeAssigneeTab === 'me') {
|
||||
conversationList = [...this.mineChatsList(filters)];
|
||||
|
@ -246,6 +296,14 @@ export default {
|
|||
|
||||
return conversationList;
|
||||
},
|
||||
activeCustomView() {
|
||||
if (this.customViewsId) {
|
||||
return this.customViews.filter(
|
||||
view => view.id === Number(this.customViewsId)
|
||||
);
|
||||
}
|
||||
return [];
|
||||
},
|
||||
activeTeam() {
|
||||
if (this.teamId) {
|
||||
return this.$store.getters['teams/getTeam'](this.teamId);
|
||||
|
@ -266,6 +324,9 @@ export default {
|
|||
conversationType() {
|
||||
this.resetAndFetchData();
|
||||
},
|
||||
activeCustomView() {
|
||||
this.resetAndFetchData();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$store.dispatch('setChatFilter', this.activeStatus);
|
||||
|
@ -280,10 +341,17 @@ export default {
|
|||
if (this.$route.name !== 'home') {
|
||||
this.$router.push({ name: 'home' });
|
||||
}
|
||||
this.customViewsQuery = { payload: payload };
|
||||
this.$store.dispatch('conversationPage/reset');
|
||||
this.$store.dispatch('emptyAllConversations');
|
||||
this.fetchFilteredConversations(payload);
|
||||
},
|
||||
onClickOpenAddCustomViewsModal() {
|
||||
this.showAddCustomViewsModal = true;
|
||||
},
|
||||
onCloseAddCustomViewsModal() {
|
||||
this.showAddCustomViewsModal = false;
|
||||
},
|
||||
onToggleAdvanceFiltersModal() {
|
||||
this.showAdvancedFilters = !this.showAdvancedFilters;
|
||||
},
|
||||
|
@ -335,6 +403,13 @@ export default {
|
|||
this.$store.dispatch('conversationPage/reset');
|
||||
this.$store.dispatch('emptyAllConversations');
|
||||
this.$store.dispatch('clearConversationFilters');
|
||||
if (this.hasActiveCustomViews) {
|
||||
const payload = this.activeCustomView[0].query;
|
||||
this.fetchSavedFilteredConversations(payload);
|
||||
}
|
||||
if (this.customViewsId) {
|
||||
return;
|
||||
}
|
||||
this.fetchConversations();
|
||||
},
|
||||
fetchConversations() {
|
||||
|
@ -343,8 +418,12 @@ export default {
|
|||
.then(() => this.$emit('conversation-load'));
|
||||
},
|
||||
loadMoreConversations() {
|
||||
if (!this.hasAppliedFilters) {
|
||||
if (!this.hasAppliedFiltersOrActiveCustomViews) {
|
||||
this.fetchConversations();
|
||||
}
|
||||
if (this.hasActiveCustomViews) {
|
||||
const payload = this.activeCustomView[0].query;
|
||||
this.fetchSavedFilteredConversations(payload);
|
||||
} else {
|
||||
this.fetchFilteredConversations(this.appliedFilters);
|
||||
}
|
||||
|
@ -359,6 +438,15 @@ export default {
|
|||
.then(() => this.$emit('conversation-load'));
|
||||
this.showAdvancedFilters = false;
|
||||
},
|
||||
fetchSavedFilteredConversations(payload) {
|
||||
let page = this.currentFiltersPage + 1;
|
||||
this.$store
|
||||
.dispatch('fetchFilteredConversations', {
|
||||
queryData: payload,
|
||||
page,
|
||||
})
|
||||
.then(() => this.$emit('conversation-load'));
|
||||
},
|
||||
updateAssigneeTab(selectedTab) {
|
||||
if (this.activeAssigneeTab !== selectedTab) {
|
||||
bus.$emit('clearSearchInput');
|
||||
|
@ -413,7 +501,7 @@ export default {
|
|||
}
|
||||
|
||||
.filter__applied {
|
||||
padding: var(--space-slab) 0 !important;
|
||||
padding: 0 0 var(--space-slab) 0 !important;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
:inboxes="inboxes"
|
||||
:labels="labels"
|
||||
:teams="teams"
|
||||
:custom-views="customViews"
|
||||
:menu-config="activeSecondaryMenu"
|
||||
:current-role="currentRole"
|
||||
@add-label="showAddLabelPopup"
|
||||
|
@ -87,6 +88,7 @@ export default {
|
|||
currentUser: 'getCurrentUser',
|
||||
globalConfig: 'globalConfig/get',
|
||||
inboxes: 'inboxes/getInboxes',
|
||||
customViews: 'customViews/getCustomViews',
|
||||
accountId: 'getCurrentAccountId',
|
||||
currentRole: 'getCurrentRole',
|
||||
labels: 'labels/getLabelsOnSidebar',
|
||||
|
@ -122,6 +124,7 @@ export default {
|
|||
mounted() {
|
||||
this.$store.dispatch('labels/get');
|
||||
this.$store.dispatch('inboxes/get');
|
||||
this.$store.dispatch('customViews/get');
|
||||
this.$store.dispatch('notifications/unReadCount');
|
||||
this.$store.dispatch('teams/get');
|
||||
this.$store.dispatch('attributes/get');
|
||||
|
|
|
@ -14,6 +14,8 @@ const conversations = accountId => ({
|
|||
'conversations_through_team',
|
||||
'conversation_mentions',
|
||||
'conversation_through_mentions',
|
||||
'custom_view_conversations',
|
||||
'conversations_through_custom_view',
|
||||
],
|
||||
menuItems: [
|
||||
{
|
||||
|
|
|
@ -40,6 +40,10 @@ export default {
|
|||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
customViews: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
menuConfig: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
|
@ -150,11 +154,35 @@ export default {
|
|||
})),
|
||||
};
|
||||
},
|
||||
customViewsSection() {
|
||||
return {
|
||||
icon: 'folder',
|
||||
label: 'CUSTOM_VIEWS',
|
||||
hasSubMenu: true,
|
||||
key: 'custom_view',
|
||||
children: this.customViews
|
||||
.filter(view => view.filter_type === 'conversation')
|
||||
.map(view => ({
|
||||
id: view.id,
|
||||
label: view.name,
|
||||
truncateLabel: true,
|
||||
toState: frontendURL(
|
||||
`accounts/${this.accountId}/custom_view/${view.id}`
|
||||
),
|
||||
})),
|
||||
};
|
||||
},
|
||||
additionalSecondaryMenuItems() {
|
||||
let conversationMenuItems = [this.inboxSection, this.labelSection];
|
||||
if (this.teams.length) {
|
||||
conversationMenuItems = [this.teamSection, ...conversationMenuItems];
|
||||
}
|
||||
if (this.customViews.length) {
|
||||
conversationMenuItems = [
|
||||
this.customViewsSection,
|
||||
...conversationMenuItems,
|
||||
];
|
||||
}
|
||||
return {
|
||||
conversations: conversationMenuItems,
|
||||
contacts: [this.contactLabelSection],
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
v-else
|
||||
class="secondary-menu--title secondary-menu--link fs-small"
|
||||
:class="computedClass"
|
||||
:to="menuItem.toState"
|
||||
:to="menuItem && menuItem.toState"
|
||||
>
|
||||
<fluent-icon
|
||||
:icon="menuItem.icon"
|
||||
|
|
|
@ -130,6 +130,10 @@ export default {
|
|||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
customViewsId: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
showAssignee: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
|
@ -248,6 +252,7 @@ export default {
|
|||
id: chat.id,
|
||||
label: this.activeLabel,
|
||||
teamId: this.teamId,
|
||||
customViewsId: this.customViewsId,
|
||||
conversationType: this.conversationType,
|
||||
});
|
||||
router.push({ path: frontendURL(path) });
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue