From 48987dc11aa17b7b2e8c3395015b968d9a08e9f7 Mon Sep 17 00:00:00 2001 From: iamsivin Date: Mon, 7 Feb 2022 12:43:48 +0530 Subject: [PATCH] feat: Notify the user that new conversations are created --- .../dashboard/components/ChatList.vue | 70 +++++++++- .../dashboard/components/ui/Banner.vue | 6 +- .../widgets/conversation/ReplyBox.vue | 1 + .../dashboard/i18n/locale/en/chatlist.json | 3 +- .../store/modules/conversations/actions.js | 16 ++- .../store/modules/conversations/index.js | 5 + .../specs/conversations/actions.spec.js | 120 +++++++++++++++++- .../dashboard/store/mutation-types.js | 1 + .../FluentIcon/dashboard-icons.json | 1 + 9 files changed, 210 insertions(+), 13 deletions(-) diff --git a/app/javascript/dashboard/components/ChatList.vue b/app/javascript/dashboard/components/ChatList.vue index a1651c534..185956405 100644 --- a/app/javascript/dashboard/components/ChatList.vue +++ b/app/javascript/dashboard/components/ChatList.vue @@ -82,6 +82,15 @@ @chatTabChange="updateAssigneeTab" /> + +

{{ $t('CHAT_LIST.LIST.404') }}

@@ -152,6 +161,7 @@ import advancedFilterTypes from './widgets/conversation/advancedFilterItems'; import filterQueryGenerator from '../helper/filterQueryGenerator.js'; import AddCustomViews from 'dashboard/routes/dashboard/customviews/AddCustomViews'; import DeleteCustomViews from 'dashboard/routes/dashboard/customviews/DeleteCustomViews.vue'; +import Banner from 'dashboard/components/ui/Banner.vue'; import { hasPressedAltAndJKey, @@ -166,6 +176,7 @@ export default { ChatFilter, ConversationAdvancedFilter, DeleteCustomViews, + Banner, }, mixins: [timeMixin, conversationMixin, eventListenerMixins], props: { @@ -202,6 +213,8 @@ export default { foldersQuery: {}, showAddFoldersModal: false, showDeleteFoldersModal: false, + hasNewConversationAvailable: false, + isRefreshFolderButtonClicked: false, }; }, computed: { @@ -313,12 +326,38 @@ export default { } else { conversationList = [...this.allChatList(filters)]; } + } else if (this.hasAppliedFiltersOrActiveFolders) { + const converstionsCreatedWhenFilterActive = this.chatLists.find( + conversation => conversation && conversation.hasActiveFilter === true + ); + if (converstionsCreatedWhenFilterActive) { + conversationList = [ + ...this.chatLists.filter( + conversation => !conversation.hasActiveFilter + ), + ]; + if (this.isRefreshFolderButtonClicked === false) { + this.showReloadBanner(); + } + } else { + conversationList = [...this.chatLists]; + } } else { conversationList = [...this.chatLists]; } return conversationList; }, + getLastSavedFolderId() { + const lastItemOfFolder = this.folders[this.folders.length - 1]; + return lastItemOfFolder.id; + }, + isLastSavedFolderOpen() { + if (this.getLastSavedFolderId === Number(this.foldersId)) { + return true; + } + return false; + }, activeFolder() { if (this.foldersId) { const activeView = this.folders.filter( @@ -336,6 +375,7 @@ export default { return {}; }, }, + watch: { activeTeam() { this.resetAndFetchData(); @@ -350,7 +390,10 @@ export default { this.resetAndFetchData(); }, activeFolder() { - if (!this.hasAppliedFilters) { + if ( + !this.hasAppliedFilters || + (this.isLastSavedFolderOpen === false && this.$route.name !== 'home') + ) { this.resetAndFetchData(); } }, @@ -388,6 +431,13 @@ export default { onToggleAdvanceFiltersModal() { this.showAdvancedFilters = !this.showAdvancedFilters; }, + showReloadBanner() { + this.hasNewConversationAvailable = true; + }, + closeReloadBanner() { + this.hasNewConversationAvailable = false; + this.isRefreshFolderButtonClicked = true; + }, getKeyboardListenerParams() { const allConversations = this.$refs.activeConversation.querySelectorAll( 'div.conversations-list div.conversation' @@ -439,6 +489,9 @@ export default { if (this.hasActiveFolders) { const payload = this.activeFolder.query; this.fetchSavedFilteredConversations(payload); + this.$store.dispatch('hasActiveFolder', this.foldersId); + this.isRefreshFolderButtonClicked = false; + this.hasNewConversationAvailable = false; } if (this.foldersId) { return; @@ -495,12 +548,21 @@ export default { this.resetAndFetchData(); } }, + onClickRefreshFolder() { + this.closeReloadBanner(); + const payload = this.activeFolder.query; + const page = 1; + this.$store + .dispatch('fetchFilteredConversations', { + queryData: payload, + page, + }) + .then(() => this.$emit('conversation-load')); + }, openLastSavedItemInFolder() { - const lastItemOfFolder = this.folders[this.folders.length - 1]; - const lastItemId = lastItemOfFolder.id; this.$router.push({ name: 'folder_conversations', - params: { id: lastItemId }, + params: { id: this.getLastSavedFolderId }, }); }, openLastItemAfterDeleteInFolder() { diff --git a/app/javascript/dashboard/components/ui/Banner.vue b/app/javascript/dashboard/components/ui/Banner.vue index 52d7c5740..f2ecce8a5 100644 --- a/app/javascript/dashboard/components/ui/Banner.vue +++ b/app/javascript/dashboard/components/ui/Banner.vue @@ -15,7 +15,7 @@ v-if="hasActionButton" size="small" variant="link" - icon="arrow-right" + :icon="actionButtonIcon" color-scheme="primary" class-names="banner-action__button" @click="onClick" @@ -58,6 +58,10 @@ export default { type: String, default: '', }, + actionButtonIcon: { + type: String, + default: '', + }, colorScheme: { type: String, default: '', diff --git a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue index 257b7bd3a..d34abc7eb 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue @@ -6,6 +6,7 @@ :banner-message="$t('CONVERSATION.NOT_ASSIGNED_TO_YOU')" :has-action-button="true" :action-button-label="$t('CONVERSATION.ASSIGN_TO_ME')" + action-button-icon="arrow-right" @click="onClickSelfAssign" /> { commit, rootState: { route: { name: 'home' } }, dispatch, - state: { currentInbox: 1, appliedFilters: [] }, + state: { currentInbox: 1, appliedFilters: [], activeFolder: '' }, }, conversation ); @@ -111,12 +111,72 @@ describe('#actions', () => { commit, rootState: { route: { name: 'home' } }, dispatch, - state: { currentInbox: 1, appliedFilters: [{ id: 'random-filter' }] }, + state: { + currentInbox: 1, + appliedFilters: [{ id: 'random-filter' }], + activeFolder: '1', + }, }, conversation ); - expect(commit.mock.calls).toEqual([]); - expect(dispatch.mock.calls).toEqual([]); + expect(commit.mock.calls).toEqual([ + [ + types.ADD_CONVERSATION, + { + ...conversation, + hasActiveFilter: true, + }, + ], + ]); + expect(dispatch.mock.calls).toEqual([ + [ + 'contacts/setContact', + { + id: 1, + name: 'john-doe', + }, + ], + ]); + }); + + it('doesnot send mutation if the view is in folder', () => { + const conversation = { + id: 1, + messages: [], + meta: { sender: { id: 1, name: 'john-doe' } }, + inbox_id: 1, + }; + actions.addConversation( + { + commit, + rootState: { route: { name: 'folder_conversations' } }, + dispatch, + state: { + currentInbox: 1, + appliedFilters: [], + activeFolder: '1', + }, + }, + conversation + ); + expect(commit.mock.calls).toEqual([ + [ + types.ADD_CONVERSATION, + { + ...conversation, + hasActiveFilter: true, + }, + ], + ]); + expect(dispatch.mock.calls).toEqual([ + [ + 'contacts/setContact', + { + id: 1, + name: 'john-doe', + }, + ], + ]); }); it('doesnot send mutation if the view is conversation mentions', () => { @@ -131,7 +191,7 @@ describe('#actions', () => { commit, rootState: { route: { name: 'conversation_mentions' } }, dispatch, - state: { currentInbox: 1, appliedFilters: [{ id: 'random-filter' }] }, + state: { currentInbox: 1, appliedFilters: [], activeFolder: '' }, }, conversation ); @@ -139,6 +199,46 @@ describe('#actions', () => { expect(dispatch.mock.calls).toEqual([]); }); + it('send mutation if conversation filters are applied or the view is in folder', () => { + const conversation = { + id: 1, + messages: [], + meta: { sender: { id: 1, name: 'john-doe' } }, + inbox_id: 1, + }; + actions.addConversation( + { + commit, + rootState: { route: { name: 'home' } }, + dispatch, + state: { + currentInbox: 1, + appliedFilters: [{ id: 'random-filter' }], + activeFolder: '1', + }, + }, + conversation + ); + expect(commit.mock.calls).toEqual([ + [ + types.ADD_CONVERSATION, + { + ...conversation, + hasActiveFilter: true, + }, + ], + ]); + expect(dispatch.mock.calls).toEqual([ + [ + 'contacts/setContact', + { + id: 1, + name: 'john-doe', + }, + ], + ]); + }); + it('sends correct mutations', () => { const conversation = { id: 1, @@ -151,7 +251,7 @@ describe('#actions', () => { commit, rootState: { route: { name: 'home' } }, dispatch, - state: { currentInbox: 1, appliedFilters: [] }, + state: { currentInbox: 1, appliedFilters: [], activeFolder: '' }, }, conversation ); @@ -372,6 +472,14 @@ describe('#actions', () => { expect(commit.mock.calls).toEqual([[types.CLEAR_CONVERSATION_FILTERS]]); }); }); + + describe('#hasActiveFolder', () => { + it('commits the correct mutation and check has filter', () => { + const folderId = '1'; + actions.hasActiveFolder({ commit }, folderId); + expect(commit.mock.calls).toEqual([[types.HAS_ACTIVE_FILTER, folderId]]); + }); + }); }); describe('#deleteMessage', () => { diff --git a/app/javascript/dashboard/store/mutation-types.js b/app/javascript/dashboard/store/mutation-types.js index 734e0b5e5..bf72546fe 100755 --- a/app/javascript/dashboard/store/mutation-types.js +++ b/app/javascript/dashboard/store/mutation-types.js @@ -21,6 +21,7 @@ export default { CLEAR_CONTACT_CONVERSATIONS: 'CLEAR_CONTACT_CONVERSATIONS', SET_CONVERSATION_FILTERS: 'SET_CONVERSATION_FILTERS', CLEAR_CONVERSATION_FILTERS: 'CLEAR_CONVERSATION_FILTERS', + HAS_ACTIVE_FILTER: 'HAS_ACTIVE_FILTER', SET_CURRENT_CHAT_WINDOW: 'SET_CURRENT_CHAT_WINDOW', CLEAR_CURRENT_CHAT_WINDOW: 'CLEAR_CURRENT_CHAT_WINDOW', diff --git a/app/javascript/shared/components/FluentIcon/dashboard-icons.json b/app/javascript/shared/components/FluentIcon/dashboard-icons.json index 46bb92a22..5c062c49b 100644 --- a/app/javascript/shared/components/FluentIcon/dashboard-icons.json +++ b/app/javascript/shared/components/FluentIcon/dashboard-icons.json @@ -12,6 +12,7 @@ "arrow-swap-outline": "m14.783 2.22 4.495 4.494a.75.75 0 0 1 .073.976l-.072.085-4.495 4.504a.75.75 0 0 1-1.135-.975l.073-.084 3.217-3.223H5.243A.75.75 0 0 1 4.5 7.35l-.007-.101a.75.75 0 0 1 .648-.743l.102-.007 11.697-.001-3.218-3.217a.75.75 0 0 1-.072-.976l.072-.084a.75.75 0 0 1 .977-.073l.084.073 4.495 4.494-4.495-4.494ZM19.5 16.65l.006.1a.75.75 0 0 1-.648.744l-.102.007L7.063 17.5l3.22 3.22a.75.75 0 0 1 .074.976l-.073.084a.75.75 0 0 1-.976.073l-.085-.072-4.5-4.497a.75.75 0 0 1-.073-.976l.073-.084 4.5-4.504a.75.75 0 0 1 1.134.976l-.073.084L7.066 16h11.692a.75.75 0 0 1 .743.65l.006.1-.006-.1Z", "arrow-trending-lines-outline": "M16.749 2h4.554l.1.014.099.028.06.026c.08.034.153.085.219.15l.04.044.044.057.054.09.039.09.019.064.014.064.009.095v4.532a.75.75 0 0 1-1.493.102l-.007-.102V4.559l-6.44 6.44a.75.75 0 0 1-.976.073L13 11 9.97 8.09l-5.69 5.689a.75.75 0 0 1-1.133-.977l.073-.084 6.22-6.22a.75.75 0 0 1 .976-.072l.084.072 3.03 2.91L19.438 3.5h-2.69a.75.75 0 0 1-.742-.648l-.007-.102a.75.75 0 0 1 .648-.743L16.75 2ZM3.75 17a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5a.75.75 0 0 1 .75-.75Zm5.75-3.25a.75.75 0 0 0-1.5 0v7.5a.75.75 0 0 0 1.5 0v-7.5ZM13.75 15a.75.75 0 0 1 .75.75v5.5a.75.75 0 0 1-1.5 0v-5.5a.75.75 0 0 1 .75-.75Zm5.75-4.25a.75.75 0 0 0-1.5 0v10.5a.75.75 0 0 0 1.5 0v-10.5Z", "arrow-up-outline": "M4.21 10.733a.75.75 0 0 0 1.086 1.034l5.954-6.251V20.25a.75.75 0 0 0 1.5 0V5.516l5.955 6.251a.75.75 0 0 0 1.086-1.034l-7.067-7.42a.995.995 0 0 0-.58-.3.754.754 0 0 0-.29.001.995.995 0 0 0-.578.3L4.21 10.733Z", + "reload-arrow-outline": "M12 4.75a7.25 7.25 0 1 0 7.201 6.406c-.068-.588.358-1.156.95-1.156.515 0 .968.358 1.03.87a9.25 9.25 0 1 1-3.432-6.116V4.25a1 1 0 1 1 2.001 0v2.698l.034.052h-.034v.25a1 1 0 0 1-1 1h-3a1 1 0 1 1 0-2h.666A7.219 7.219 0 0 0 12 4.75Z", "attach-outline": "M11.772 3.743a6 6 0 0 1 8.66 8.302l-.19.197-8.8 8.798-.036.03a3.723 3.723 0 0 1-5.489-4.973.764.764 0 0 1 .085-.13l.054-.06.086-.088.142-.148.002.003 7.436-7.454a.75.75 0 0 1 .977-.074l.084.073a.75.75 0 0 1 .074.976l-.073.084-7.594 7.613a2.23 2.23 0 0 0 3.174 3.106l8.832-8.83A4.502 4.502 0 0 0 13 4.644l-.168.16-.013.014-9.536 9.536a.75.75 0 0 1-1.133-.977l.072-.084 9.549-9.55h.002Z", "autocorrect-outline": "M13.461 4.934c.293.184.548.42.752.698l.117.171 2.945 4.696H21.5a.75.75 0 0 1 .743.649l.007.102a.75.75 0 0 1-.75.75l-3.284-.001.006.009-.009-.01a4.75 4.75 0 1 1-3.463-1.5h.756L13.059 6.6a1.25 1.25 0 0 0-2.04-.112l-.078.112-7.556 12.048a.75.75 0 0 1-1.322-.699l.052-.098L9.67 5.803a2.75 2.75 0 0 1 3.791-.869ZM14.751 12a3.25 3.25 0 1 0 0 6.5 3.25 3.25 0 0 0 0-6.5Z", "automation-outline": [