chore: Inbox view enhancements

This commit is contained in:
iamsivin
2024-02-09 15:40:12 +05:30
parent 6a630bc489
commit 43de19f685
9 changed files with 107 additions and 74 deletions
@@ -129,7 +129,7 @@ export default {
name,
} = this.$route;
if (this.isInboxView) {
return frontendURL(`accounts/${accountId}/inbox`);
return frontendURL(`accounts/${accountId}/inbox-view`);
}
return conversationListPageURL({
accountId,
@@ -4,7 +4,6 @@
"TITLE": "Inbox",
"DISPLAY_DROPDOWN": "Display",
"LOADING": "Fetching notifications",
"EOF": "All notifications loaded 🎉",
"404": "There are no active notifications in this group.",
"NO_NOTIFICATIONS": "No notifications",
"NOTE": "Notifications from all subscribed inboxes",
@@ -50,6 +50,7 @@ import AddLabelModal from 'dashboard/routes/dashboard/settings/labels/AddLabel.v
import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel.vue';
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import wootConstants from 'dashboard/constants/globals';
import resizeListenerMixin from 'shared/mixins/resizeListenerMixin';
export default {
components: {
@@ -61,7 +62,7 @@ export default {
AddLabelModal,
NotificationPanel,
},
mixins: [uiSettingsMixin],
mixins: [uiSettingsMixin, resizeListenerMixin],
data() {
return {
showAccountModal: false,
@@ -109,33 +110,20 @@ export default {
},
mounted() {
this.handleResize();
window.addEventListener('resize', this.handleResize);
bus.$on(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize);
bus.$off(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
},
methods: {
handleResize() {
const { SMALL_SCREEN_BREAKPOINT, LAYOUT_TYPES } = wootConstants;
let throttled = false;
const delay = 150;
if (throttled) {
return;
if (window.innerWidth <= SMALL_SCREEN_BREAKPOINT) {
this.displayLayoutType = LAYOUT_TYPES.EXPANDED;
} else {
this.displayLayoutType = LAYOUT_TYPES.CONDENSED;
}
throttled = true;
setTimeout(() => {
throttled = false;
if (window.innerWidth <= SMALL_SCREEN_BREAKPOINT) {
this.displayLayoutType = LAYOUT_TYPES.EXPANDED;
} else {
this.displayLayoutType = LAYOUT_TYPES.CONDENSED;
}
}, delay);
},
toggleSidebar() {
this.updateUISettings({
@@ -15,12 +15,12 @@ export default {
},
},
{
path: frontendURL('accounts/:accountId/inbox-view/:conversation_id'),
path: frontendURL('accounts/:accountId/inbox-view/:notification_id'),
name: 'inbox_view_conversation',
roles: ['administrator', 'agent'],
component: InboxView,
props: route => {
return { inboxId: 0, conversationId: route.params.conversation_id };
return { inboxId: 0, notificationId: route.params.notification_id };
},
},
{
@@ -3,7 +3,11 @@
class="flex flex-col h-full w-full ltr:border-r border-slate-50 dark:border-slate-800/50"
:class="isOnExpandedLayout ? '' : 'min-w-[360px] max-w-[360px]'"
>
<inbox-list-header @filter="onFilterChange" />
<inbox-list-header
:is-context-menu-open="isContextMenuOpen"
@filter="onFilterChange"
@redirect="redirectToInbox"
/>
<div
ref="notificationList"
class="flex flex-col w-full h-[calc(100%-56px)] overflow-x-hidden overflow-y-auto"
@@ -15,6 +19,8 @@
@mark-notification-as-read="markNotificationAsRead"
@mark-notification-as-unread="markNotificationAsUnRead"
@delete-notification="deleteNotification"
@context-menu-open="isContextMenuOpen = true"
@context-menu-close="isContextMenuOpen = false"
/>
<div v-if="uiFlags.isFetching" class="text-center">
<span class="spinner mt-4 mb-4" />
@@ -25,12 +31,6 @@
>
{{ $t('INBOX.LIST.NO_NOTIFICATIONS') }}
</p>
<p
v-if="showEndOfListMessage"
class="text-center text-slate-400 dark:text-slate-400 p-4"
>
{{ $t('INBOX.LIST.EOF') }}
</p>
<intersection-observer
v-if="!showEndOfList && !uiFlags.isFetching"
:options="infiniteLoaderOptions"
@@ -57,7 +57,7 @@ export default {
},
mixins: [alertMixin, uiSettingsMixin],
props: {
conversationId: {
notificationId: {
type: [String, Number],
default: 0,
},
@@ -76,6 +76,7 @@ export default {
status: '',
type: '',
sortOrder: wootConstants.INBOX_SORT_BY.NEWEST,
isContextMenuOpen: false,
};
},
computed: {
@@ -102,9 +103,6 @@ export default {
showEmptyState() {
return !this.uiFlags.isFetching && !this.notifications.length;
},
showEndOfListMessage() {
return this.showEndOfList && this.notifications.length;
},
},
mounted() {
this.setSavedFilter();
@@ -119,17 +117,15 @@ export default {
this.$store.dispatch('notifications/index', filter);
},
redirectToInbox() {
if (!this.conversationId) return;
if (!this.notificationId) return;
if (this.$route.name === 'inbox_view') return;
this.$router.push({ name: 'inbox_view' });
},
loadMoreNotifications() {
if (this.uiFlags.isAllNotificationsLoaded) return;
this.$store.dispatch('notifications/index', {
...this.inboxFilters,
page: this.page + 1,
status: this.status,
type: this.type,
sortOrder: this.sortOrder,
});
this.page += 1;
},
@@ -2,7 +2,7 @@
<section class="flex w-full h-full bg-white dark:bg-slate-900">
<inbox-list
v-show="showConversationList"
:conversation-id="conversationId"
:notification-id="notificationId"
:is-on-expanded-layout="isOnExpandedLayout"
/>
<div
@@ -51,6 +51,7 @@ import InboxList from './InboxList.vue';
import InboxItemHeader from './components/InboxItemHeader.vue';
import ConversationBox from 'dashboard/components/widgets/conversation/ConversationBox.vue';
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import resizeListenerMixin from 'shared/mixins/resizeListenerMixin';
import wootConstants from 'dashboard/constants/globals';
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
import { BUS_EVENTS } from 'shared/constants/busEvents';
@@ -62,17 +63,22 @@ export default {
InboxItemHeader,
ConversationBox,
},
mixins: [uiSettingsMixin],
mixins: [uiSettingsMixin, resizeListenerMixin],
props: {
inboxId: {
type: [String, Number],
default: 0,
},
conversationId: {
notificationId: {
type: [String, Number],
default: 0,
},
},
data() {
return {
isOnExpandedLayout: false,
};
},
computed: {
...mapGetters({
currentAccountId: 'getCurrentAccountId',
@@ -82,9 +88,10 @@ export default {
uiFlags: 'notifications/getUIFlags',
}),
activeNotification() {
return this.notifications.find(
n => n.primary_actor.id === Number(this.conversationId)
);
return this.notifications.find(n => n.id === Number(this.notificationId));
},
conversationId() {
return this.activeNotification?.primary_actor.id;
},
isInboxViewEnabled() {
return this.$store.getters['accounts/isFeatureEnabledGlobally'](
@@ -93,14 +100,14 @@ export default {
);
},
showConversationList() {
return this.isOnExpandedLayout ? !this.conversationId : true;
return this.isOnExpandedLayout ? !this.notificationId : true;
},
isFetchingInitialData() {
return this.uiFlags.isFetching && !this.notifications.length;
},
showInboxMessageView() {
return (
Boolean(this.conversationId) &&
Boolean(this.notificationId) &&
Boolean(this.currentChat.id) &&
!this.isFetchingInitialData
);
@@ -109,20 +116,11 @@ export default {
return this.notifications?.length ?? 0;
},
activeNotificationIndex() {
const conversationId = Number(this.conversationId);
const notificationIndex = this.notifications.findIndex(
n => n.primary_actor.id === conversationId
n => n.id === Number(this.notificationId)
);
return notificationIndex >= 0 ? notificationIndex + 1 : 0;
},
isOnExpandedLayout() {
const {
LAYOUT_TYPES: { CONDENSED },
} = wootConstants;
const { conversation_display_type: conversationDisplayType = CONDENSED } =
this.uiSettings;
return conversationDisplayType !== CONDENSED;
},
isContactPanelOpen() {
if (this.currentChat.id) {
const { is_contact_sidebar_open: isContactSidebarOpen } =
@@ -149,10 +147,19 @@ export default {
});
}
this.$store.dispatch('agents/get');
this.handleResize();
},
methods: {
handleResize() {
const { SMALL_SCREEN_BREAKPOINT } = wootConstants;
if (window.innerWidth <= SMALL_SCREEN_BREAKPOINT) {
this.isOnExpandedLayout = true;
} else {
this.isOnExpandedLayout = false;
}
},
async fetchConversationById() {
if (!this.conversationId) return;
if (!this.notificationId || !this.conversationId) return;
const chat = this.findConversation();
if (!chat) {
await this.$store.dispatch('getConversation', this.conversationId);
@@ -169,8 +176,9 @@ export default {
});
},
findConversation() {
const conversationId = Number(this.conversationId);
return this.allConversation.find(c => c.id === conversationId);
return this.allConversation.find(
c => c.id === Number(this.conversationId)
);
},
navigateToConversation(activeIndex, direction) {
const indexOffset = direction === 'next' ? 0 : -2;
@@ -180,7 +188,7 @@ export default {
id,
primary_actor_id: primaryActorId,
primary_actor_type: primaryActorType,
primary_actor: { id: conversationId, meta: { unreadCount } = {} },
primary_actor: { meta: { unreadCount } = {} },
notification_type: notificationType,
} = targetNotification;
@@ -197,7 +205,7 @@ export default {
this.$router.push({
name: 'inbox_view_conversation',
params: { conversation_id: conversationId },
params: { notification_id: id },
});
}
},
@@ -166,11 +166,11 @@ export default {
id,
primary_actor_id: primaryActorId,
primary_actor_type: primaryActorType,
primary_actor: { id: conversationId, inbox_id: inboxId },
primary_actor: { inbox_id: inboxId },
notification_type: notificationType,
} = notification;
if (this.$route.params.conversation_id !== conversationId) {
if (this.$route.params.notification_id !== id) {
this.$track(INBOX_EVENTS.OPEN_CONVERSATION_VIA_INBOX, {
notificationType,
});
@@ -184,13 +184,14 @@ export default {
this.$router.push({
name: 'inbox_view_conversation',
params: { inboxId, conversation_id: conversationId },
params: { inboxId, notification_id: id },
});
}
},
closeContextMenu() {
this.isContextMenuOpen = false;
this.contextMenuPosition = { x: null, y: null };
this.$emit('context-menu-close');
},
openContextMenu(e) {
this.closeContextMenu();
@@ -200,6 +201,7 @@ export default {
y: e.pageY || e.clientY,
};
this.isContextMenuOpen = true;
this.$emit('context-menu-open');
},
handleAction(key) {
switch (key) {
@@ -69,12 +69,29 @@ export default {
InboxDisplayMenu,
},
mixins: [clickaway, alertMixin],
props: {
isContextMenuOpen: {
type: Boolean,
default: false,
},
},
data() {
return {
showInboxDisplayMenu: false,
showInboxOptionMenu: false,
};
},
watch: {
isContextMenuOpen: {
handler(val) {
if (val) {
this.showInboxDisplayMenu = false;
this.showInboxOptionMenu = false;
}
},
immediate: true,
},
},
methods: {
markAllRead() {
this.$track(INBOX_EVENTS.MARK_ALL_NOTIFICATIONS_AS_READ);
@@ -100,21 +117,19 @@ export default {
},
onInboxOptionMenuClick(key) {
this.showInboxOptionMenu = false;
if (key === 'mark_all_read') {
this.markAllRead();
}
if (key === 'delete_all') {
this.deleteAll();
}
if (key === 'delete_all_read') {
this.deleteAllRead();
}
const actions = {
mark_all_read: () => this.markAllRead(),
delete_all: () => this.deleteAll(),
delete_all_read: () => this.deleteAllRead(),
};
const action = actions[key];
if (action) action();
this.$emit('redirect');
},
onFilterChange(option) {
this.$emit('filter', option);
this.showInboxDisplayMenu = false;
if (this.$route.name === 'inbox_view') return;
this.$router.push({ name: 'inbox_view' });
this.$emit('redirect');
},
},
};
@@ -0,0 +1,25 @@
export default {
mounted() {
window.addEventListener('resize', this.handleResize);
},
beforeDestroy() {
window.removeEventListener('resize', this.onResizeHandler);
},
methods: {
// Resize event for layout changes
onResizeHandler() {
let throttled = false;
const delay = 150;
if (throttled) {
return;
}
throttled = true;
setTimeout(() => {
throttled = false;
this.handleResize();
}, delay);
},
},
};