feat: Add infinite loader, option for increasing page size (#8525)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
@@ -160,6 +160,6 @@ class ConversationFinder
|
|||||||
:taggings, :inbox, { assignee: { avatar_attachment: [:blob] } }, { contact: { avatar_attachment: [:blob] } }, :team, :contact_inbox
|
:taggings, :inbox, { assignee: { avatar_attachment: [:blob] } }, { contact: { avatar_attachment: [:blob] } }, :team, :contact_inbox
|
||||||
)
|
)
|
||||||
sort_by = SORT_OPTIONS[params[:sort_by]] || SORT_OPTIONS['latest']
|
sort_by = SORT_OPTIONS[params[:sort_by]] || SORT_OPTIONS['latest']
|
||||||
@conversations.send(sort_by).page(current_page)
|
@conversations.send(sort_by).page(current_page).per(ENV.fetch('CONVERSATION_RESULTS_PER_PAGE', '25').to_i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -126,49 +126,41 @@
|
|||||||
@assign-team="onAssignTeamsForBulk"
|
@assign-team="onAssignTeamsForBulk"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
ref="activeConversation"
|
ref="conversationList"
|
||||||
class="conversations-list flex-1"
|
class="conversations-list flex-1"
|
||||||
:class="{ 'overflow-hidden': isContextMenuOpen }"
|
:class="{ 'overflow-hidden': isContextMenuOpen }"
|
||||||
>
|
>
|
||||||
<div>
|
<conversation-card
|
||||||
<conversation-card
|
v-for="chat in conversationList"
|
||||||
v-for="chat in conversationList"
|
:key="chat.id"
|
||||||
:key="chat.id"
|
:active-label="label"
|
||||||
:active-label="label"
|
:team-id="teamId"
|
||||||
:team-id="teamId"
|
:folders-id="foldersId"
|
||||||
:folders-id="foldersId"
|
:chat="chat"
|
||||||
:chat="chat"
|
:conversation-type="conversationType"
|
||||||
:conversation-type="conversationType"
|
:show-assignee="showAssigneeInConversationCard"
|
||||||
:show-assignee="showAssigneeInConversationCard"
|
:selected="isConversationSelected(chat.id)"
|
||||||
:selected="isConversationSelected(chat.id)"
|
@select-conversation="selectConversation"
|
||||||
@select-conversation="selectConversation"
|
@de-select-conversation="deSelectConversation"
|
||||||
@de-select-conversation="deSelectConversation"
|
@assign-agent="onAssignAgent"
|
||||||
@assign-agent="onAssignAgent"
|
@assign-team="onAssignTeam"
|
||||||
@assign-team="onAssignTeam"
|
@assign-label="onAssignLabels"
|
||||||
@assign-label="onAssignLabels"
|
@update-conversation-status="toggleConversationStatus"
|
||||||
@update-conversation-status="toggleConversationStatus"
|
@context-menu-toggle="onContextMenuToggle"
|
||||||
@context-menu-toggle="onContextMenuToggle"
|
@mark-as-unread="markAsUnread"
|
||||||
@mark-as-unread="markAsUnread"
|
@assign-priority="assignPriority"
|
||||||
@assign-priority="assignPriority"
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div v-if="chatListLoading" class="text-center">
|
<div v-if="chatListLoading" class="text-center">
|
||||||
<span class="spinner mt-4 mb-4" />
|
<span class="spinner mt-4 mb-4" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<woot-button
|
|
||||||
v-if="!hasCurrentPageEndReached && !chatListLoading"
|
|
||||||
variant="clear"
|
|
||||||
size="expanded"
|
|
||||||
class="load-more--button"
|
|
||||||
@click="loadMoreConversations"
|
|
||||||
>
|
|
||||||
{{ $t('CHAT_LIST.LOAD_MORE_CONVERSATIONS') }}
|
|
||||||
</woot-button>
|
|
||||||
|
|
||||||
<p v-if="showEndOfListMessage" class="text-center text-muted p-4">
|
<p v-if="showEndOfListMessage" class="text-center text-muted p-4">
|
||||||
{{ $t('CHAT_LIST.EOF') }}
|
{{ $t('CHAT_LIST.EOF') }}
|
||||||
</p>
|
</p>
|
||||||
|
<intersection-observer
|
||||||
|
v-if="!showEndOfListMessage && !chatListLoading"
|
||||||
|
:options="infiniteLoaderOptions"
|
||||||
|
@observed="loadMoreConversations"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<woot-modal
|
<woot-modal
|
||||||
:show.sync="showAdvancedFilters"
|
:show.sync="showAdvancedFilters"
|
||||||
@@ -222,6 +214,7 @@ import {
|
|||||||
isOnUnattendedView,
|
isOnUnattendedView,
|
||||||
} from '../store/modules/conversations/helpers/actionHelpers';
|
} from '../store/modules/conversations/helpers/actionHelpers';
|
||||||
import { CONVERSATION_EVENTS } from '../helper/AnalyticsHelper/events';
|
import { CONVERSATION_EVENTS } from '../helper/AnalyticsHelper/events';
|
||||||
|
import IntersectionObserver from './IntersectionObserver.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -232,6 +225,7 @@ export default {
|
|||||||
DeleteCustomViews,
|
DeleteCustomViews,
|
||||||
ConversationBulkActions,
|
ConversationBulkActions,
|
||||||
ConversationBasicFilter,
|
ConversationBasicFilter,
|
||||||
|
IntersectionObserver,
|
||||||
},
|
},
|
||||||
mixins: [
|
mixins: [
|
||||||
timeMixin,
|
timeMixin,
|
||||||
@@ -291,6 +285,10 @@ export default {
|
|||||||
selectedInboxes: [],
|
selectedInboxes: [],
|
||||||
isContextMenuOpen: false,
|
isContextMenuOpen: false,
|
||||||
appliedFilter: [],
|
appliedFilter: [],
|
||||||
|
infiniteLoaderOptions: {
|
||||||
|
root: this.$refs.conversationList,
|
||||||
|
rootMargin: '100px 0px 100px 0px',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -635,10 +633,10 @@ export default {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
getKeyboardListenerParams() {
|
getKeyboardListenerParams() {
|
||||||
const allConversations = this.$refs.activeConversation.querySelectorAll(
|
const allConversations = this.$refs.conversationList.querySelectorAll(
|
||||||
'div.conversations-list div.conversation'
|
'div.conversations-list div.conversation'
|
||||||
);
|
);
|
||||||
const activeConversation = this.$refs.activeConversation.querySelector(
|
const activeConversation = this.$refs.conversationList.querySelector(
|
||||||
'div.conversations-list div.conversation.active'
|
'div.conversations-list div.conversation.active'
|
||||||
);
|
);
|
||||||
const activeConversationIndex = [...allConversations].indexOf(
|
const activeConversationIndex = [...allConversations].indexOf(
|
||||||
@@ -697,6 +695,9 @@ export default {
|
|||||||
.then(() => this.$emit('conversation-load'));
|
.then(() => this.$emit('conversation-load'));
|
||||||
},
|
},
|
||||||
loadMoreConversations() {
|
loadMoreConversations() {
|
||||||
|
if (this.hasCurrentPageEndReached || this.chatListLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!this.hasAppliedFiltersOrActiveFolders) {
|
if (!this.hasAppliedFiltersOrActiveFolders) {
|
||||||
this.fetchConversations();
|
this.fetchConversations();
|
||||||
}
|
}
|
||||||
|
|||||||
34
app/javascript/dashboard/components/IntersectionObserver.vue
Normal file
34
app/javascript/dashboard/components/IntersectionObserver.vue
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<div ref="observedElement" class="h-6 w-full" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
options: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({ root: document, rootMargin: '100px 0 100px 0)' }),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.intersectionObserver = null;
|
||||||
|
this.registerInfiniteLoader();
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.unobserveInfiniteLoadObserver();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
registerInfiniteLoader() {
|
||||||
|
this.intersectionObserver = new IntersectionObserver(entries => {
|
||||||
|
if (entries && entries[0].isIntersecting) {
|
||||||
|
this.$emit('observed');
|
||||||
|
}
|
||||||
|
}, this.options);
|
||||||
|
this.intersectionObserver.observe(this.$refs.observedElement);
|
||||||
|
},
|
||||||
|
unobserveInfiniteLoadObserver() {
|
||||||
|
this.intersectionObserver.unobserve(this.$refs.observedElement);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user