diff --git a/app/javascript/dashboard/api/notifications.js b/app/javascript/dashboard/api/notifications.js index 183642742..65fc937b7 100644 --- a/app/javascript/dashboard/api/notifications.js +++ b/app/javascript/dashboard/api/notifications.js @@ -6,8 +6,15 @@ class NotificationsAPI extends ApiClient { super('notifications', { accountScoped: true }); } - get(page) { - return axios.get(`${this.url}?page=${page}`); + get({ page, status, type, sortOrder }) { + return axios.get(this.url, { + params: { + page, + status, + type, + sort_order: sortOrder, + }, + }); } getNotifications(contactId) { diff --git a/app/javascript/dashboard/api/specs/notifications.spec.js b/app/javascript/dashboard/api/specs/notifications.spec.js index 5bdf88d7f..bc06eaa2b 100644 --- a/app/javascript/dashboard/api/specs/notifications.spec.js +++ b/app/javascript/dashboard/api/specs/notifications.spec.js @@ -28,10 +28,20 @@ describe('#NotificationAPI', () => { }); it('#get', () => { - notificationsAPI.get(1); - expect(axiosMock.get).toHaveBeenCalledWith( - '/api/v1/notifications?page=1' - ); + notificationsAPI.get({ + page: 1, + status: 'read', + type: 'Conversation', + sortOrder: 'desc', + }); + expect(axiosMock.get).toHaveBeenCalledWith('/api/v1/notifications', { + params: { + page: 1, + status: 'read', + type: 'Conversation', + sort_order: 'desc', + }, + }); }); it('#getNotifications', () => { @@ -65,5 +75,30 @@ describe('#NotificationAPI', () => { '/api/v1/notifications/read_all' ); }); + + it('#snooze', () => { + notificationsAPI.snooze({ id: 1, snoozedUntil: 12332211 }); + expect(axiosMock.post).toHaveBeenCalledWith( + '/api/v1/notifications/1/snooze', + { + snoozed_until: 12332211, + } + ); + }); + + it('#delete', () => { + notificationsAPI.delete(1); + expect(axiosMock.delete).toHaveBeenCalledWith('/api/v1/notifications/1'); + }); + + it('#deleteAll', () => { + notificationsAPI.deleteAll({ type: 'all' }); + expect(axiosMock.post).toHaveBeenCalledWith( + '/api/v1/notifications/destroy_all', + { + type: 'all', + } + ); + }); }); }); diff --git a/app/javascript/dashboard/constants/globals.js b/app/javascript/dashboard/constants/globals.js index 303f828cd..b8014ce6c 100644 --- a/app/javascript/dashboard/constants/globals.js +++ b/app/javascript/dashboard/constants/globals.js @@ -46,5 +46,18 @@ export default { }, EXAMPLE_URL: 'https://example.com', EXAMPLE_WEBHOOK_URL: 'https://example/api/webhook', + INBOX_SORT_BY: { + NEWEST: 'desc', + OLDEST: 'asc', + }, + INBOX_DISPLAY_BY: { + SNOOZED: 'snoozed', + READ: 'read', + }, + INBOX_FILTER_TYPE: { + STATUS: 'status', + TYPE: 'type', + SORT_ORDER: 'sort_order', + }, }; export const DEFAULT_REDIRECT_URL = '/app/'; diff --git a/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfo.vue b/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfo.vue index eb2bc2bb4..ad2ea5d25 100644 --- a/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfo.vue +++ b/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfo.vue @@ -306,7 +306,7 @@ export default { }); } else if (isAInboxViewRoute(this.$route.name)) { this.$router.push({ - name: 'inbox-view', + name: 'inbox_view', }); } else if (this.$route.name !== 'contacts_dashboard') { this.$router.push({ diff --git a/app/javascript/dashboard/routes/dashboard/inbox/InboxList.vue b/app/javascript/dashboard/routes/dashboard/inbox/InboxList.vue index e0924b9c0..bb0f2e7df 100644 --- a/app/javascript/dashboard/routes/dashboard/inbox/InboxList.vue +++ b/app/javascript/dashboard/routes/dashboard/inbox/InboxList.vue @@ -3,13 +3,13 @@ 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]'" > - +
import { mapGetters } from 'vuex'; +import wootConstants from 'dashboard/constants/globals'; import InboxCard from './components/InboxCard.vue'; import InboxListHeader from './components/InboxListHeader.vue'; import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events'; import IntersectionObserver from 'dashboard/components/IntersectionObserver.vue'; import alertMixin from 'shared/mixins/alertMixin'; +import uiSettingsMixin from 'dashboard/mixins/uiSettings'; export default { components: { InboxCard, InboxListHeader, IntersectionObserver, }, - mixins: [alertMixin], + mixins: [alertMixin, uiSettingsMixin], props: { conversationId: { type: [String, Number], @@ -71,38 +73,64 @@ export default { rootMargin: '100px 0px 100px 0px', }, page: 1, + status: '', + type: '', + sortOrder: wootConstants.INBOX_SORT_BY.NEWEST, }; }, computed: { ...mapGetters({ accountId: 'getCurrentAccountId', meta: 'notifications/getMeta', - records: 'notifications/getNotifications', uiFlags: 'notifications/getUIFlags', + notification: 'notifications/getFilteredNotifications', }), + inboxFilters() { + return { + page: this.page, + status: this.status, + type: this.type, + sortOrder: this.sortOrder, + }; + }, + notifications() { + return this.notification(this.inboxFilters); + }, showEndOfList() { return this.uiFlags.isAllNotificationsLoaded && !this.uiFlags.isFetching; }, showEmptyState() { - return !this.uiFlags.isFetching && !this.records.length; + return !this.uiFlags.isFetching && !this.notifications.length; }, showEndOfListMessage() { - return this.showEndOfList && this.records.length; + return this.showEndOfList && this.notifications.length; }, }, mounted() { - this.$store.dispatch('notifications/clear'); - this.$store.dispatch('notifications/index', { page: 1 }); + this.setSavedFilter(); + this.fetchNotifications(); }, methods: { + fetchNotifications() { + this.page = 1; + this.$store.dispatch('notifications/clear'); + const filter = this.inboxFilters; + + this.$store.dispatch('notifications/index', filter); + }, redirectToInbox() { if (!this.conversationId) return; - if (this.$route.name === 'inbox-view') return; - this.$router.push({ name: 'inbox-view' }); + if (this.$route.name === 'inbox_view') return; + this.$router.push({ name: 'inbox_view' }); }, loadMoreNotifications() { if (this.uiFlags.isAllNotificationsLoaded) return; - this.$store.dispatch('notifications/index', { page: this.page + 1 }); + this.$store.dispatch('notifications/index', { + page: this.page + 1, + status: this.status, + type: this.type, + sortOrder: this.sortOrder, + }); this.page += 1; }, markNotificationAsRead(notification) { @@ -148,6 +176,25 @@ export default { this.showAlert(this.$t('INBOX.ALERTS.DELETE')); }); }, + onFilterChange(option) { + if (option.type === wootConstants.INBOX_FILTER_TYPE.STATUS) { + this.status = option.selected ? option.key : ''; + } + if (option.type === wootConstants.INBOX_FILTER_TYPE.TYPE) { + this.type = option.selected ? option.key : ''; + } + if (option.type === wootConstants.INBOX_FILTER_TYPE.SORT_ORDER) { + this.sortOrder = option.key; + } + this.fetchNotifications(); + }, + setSavedFilter() { + const { inbox_filter_by: filterBy = {} } = this.uiSettings; + const { status, type, sort_by: sortBy } = filterBy; + this.status = status; + this.type = type; + this.sortOrder = sortBy || wootConstants.INBOX_SORT_BY.NEWEST; + }, }, }; diff --git a/app/javascript/dashboard/routes/dashboard/inbox/InboxView.vue b/app/javascript/dashboard/routes/dashboard/inbox/InboxView.vue index 23f32cbbe..edc36da15 100644 --- a/app/javascript/dashboard/routes/dashboard/inbox/InboxView.vue +++ b/app/javascript/dashboard/routes/dashboard/inbox/InboxView.vue @@ -148,6 +148,7 @@ export default { name: 'home', }); } + this.$store.dispatch('agents/get'); }, methods: { async fetchConversationById() { diff --git a/app/javascript/dashboard/routes/dashboard/inbox/components/InboxCard.vue b/app/javascript/dashboard/routes/dashboard/inbox/components/InboxCard.vue index c514f24f7..8e100f7b5 100644 --- a/app/javascript/dashboard/routes/dashboard/inbox/components/InboxCard.vue +++ b/app/javascript/dashboard/routes/dashboard/inbox/components/InboxCard.vue @@ -29,7 +29,8 @@ v-if="assigneeMeta" :src="assigneeMeta.thumbnail" :username="assigneeMeta.name" - size="20px" + size="16px" + class="relative bottom-0.5" />
{{ option.name }} @@ -74,19 +73,19 @@ >