mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 02:57:57 +00:00 
			
		
		
		
	 5bc8219db5
			
		
	
	5bc8219db5
	
	
	
		
			
			* Adds typing indicator for widget * typing indicator for agents in dashboard Co-authored-by: Pranav Raj Sreepuram <pranavrajs@gmail.com>
		
			
				
	
	
		
			230 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			230 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <div class="view-box columns">
 | |
|     <conversation-header
 | |
|       :chat="currentChat"
 | |
|       :is-contact-panel-open="isContactPanelOpen"
 | |
|       @contactPanelToggle="onToggleContactPanel"
 | |
|     />
 | |
|     <ul class="conversation-panel">
 | |
|       <transition name="slide-up">
 | |
|         <li>
 | |
|           <span v-if="shouldShowSpinner" class="spinner message" />
 | |
|         </li>
 | |
|       </transition>
 | |
|       <message
 | |
|         v-for="message in getReadMessages"
 | |
|         :key="message.id"
 | |
|         :data="message"
 | |
|       />
 | |
|       <li v-show="getUnreadCount != 0" class="unread--toast">
 | |
|         <span>
 | |
|           {{ getUnreadCount }} UNREAD MESSAGE{{ getUnreadCount > 1 ? 'S' : '' }}
 | |
|         </span>
 | |
|       </li>
 | |
|       <message
 | |
|         v-for="message in getUnReadMessages"
 | |
|         :key="message.id"
 | |
|         :data="message"
 | |
|       />
 | |
|     </ul>
 | |
|     <div class="conversation-footer">
 | |
|       <div v-if="isAnyoneTyping" class="typing-indicator-wrap">
 | |
|         <div class="typing-indicator">
 | |
|           {{ typingUserNames }}
 | |
|           <img
 | |
|             class="gif"
 | |
|             src="~dashboard/assets/images/typing.gif"
 | |
|             alt="Someone is typing"
 | |
|           />
 | |
|         </div>
 | |
|       </div>
 | |
|       <ReplyBox
 | |
|         :conversation-id="currentChat.id"
 | |
|         @scrollToMessage="focusLastMessage"
 | |
|       />
 | |
|     </div>
 | |
|   </div>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| /* global bus */
 | |
| import { mapGetters } from 'vuex';
 | |
| 
 | |
| import ConversationHeader from './ConversationHeader';
 | |
| import ReplyBox from './ReplyBox';
 | |
| import Message from './Message';
 | |
| import conversationMixin from '../../../mixins/conversations';
 | |
| import { getTypingUsersText } from '../../../helper/commons';
 | |
| 
 | |
| export default {
 | |
|   components: {
 | |
|     ConversationHeader,
 | |
|     Message,
 | |
|     ReplyBox,
 | |
|   },
 | |
| 
 | |
|   mixins: [conversationMixin],
 | |
| 
 | |
|   props: {
 | |
|     inboxId: {
 | |
|       type: [Number, String],
 | |
|       required: true,
 | |
|     },
 | |
|     isContactPanelOpen: {
 | |
|       type: Boolean,
 | |
|       default: false,
 | |
|     },
 | |
|   },
 | |
| 
 | |
|   data() {
 | |
|     return {
 | |
|       isLoadingPrevious: true,
 | |
|       heightBeforeLoad: null,
 | |
|       conversationPanel: null,
 | |
|     };
 | |
|   },
 | |
| 
 | |
|   computed: {
 | |
|     ...mapGetters({
 | |
|       currentChat: 'getSelectedChat',
 | |
|       allConversations: 'getAllConversations',
 | |
|       inboxesList: 'inboxes/getInboxes',
 | |
|       listLoadingStatus: 'getAllMessagesLoaded',
 | |
|       getUnreadCount: 'getUnreadCount',
 | |
|       loadingChatList: 'getChatListLoadingStatus',
 | |
|     }),
 | |
| 
 | |
|     typingUsersList() {
 | |
|       const userList = this.$store.getters[
 | |
|         'conversationTypingStatus/getUserList'
 | |
|       ](this.currentChat.id);
 | |
|       return userList;
 | |
|     },
 | |
|     isAnyoneTyping() {
 | |
|       const userList = this.typingUsersList;
 | |
|       return userList.length !== 0;
 | |
|     },
 | |
|     typingUserNames() {
 | |
|       const userList = this.typingUsersList;
 | |
| 
 | |
|       if (this.isAnyoneTyping) {
 | |
|         const userListAsName = getTypingUsersText(userList);
 | |
|         return userListAsName;
 | |
|       }
 | |
| 
 | |
|       return '';
 | |
|     },
 | |
| 
 | |
|     getMessages() {
 | |
|       const [chat] = this.allConversations.filter(
 | |
|         c => c.id === this.currentChat.id
 | |
|       );
 | |
|       return chat;
 | |
|     },
 | |
|     // Get current FB Page ID
 | |
|     getPageId() {
 | |
|       let stateInbox;
 | |
|       if (this.inboxId) {
 | |
|         const inboxId = Number(this.inboxId);
 | |
|         [stateInbox] = this.inboxesList.filter(
 | |
|           inbox => inbox.channel_id === inboxId
 | |
|         );
 | |
|       } else {
 | |
|         [stateInbox] = this.inboxesList;
 | |
|       }
 | |
|       return !stateInbox ? 0 : stateInbox.page_id;
 | |
|     },
 | |
|     // Get current FB Page ID link
 | |
|     linkToMessage() {
 | |
|       return `https://m.me/${this.getPageId}`;
 | |
|     },
 | |
|     getReadMessages() {
 | |
|       const chat = this.getMessages;
 | |
|       return chat === undefined ? null : this.readMessages(chat);
 | |
|     },
 | |
|     getUnReadMessages() {
 | |
|       const chat = this.getMessages;
 | |
|       return chat === undefined ? null : this.unReadMessages(chat);
 | |
|     },
 | |
|     shouldShowSpinner() {
 | |
|       return (
 | |
|         this.getMessages.dataFetched === undefined ||
 | |
|         (!this.listLoadingStatus && this.isLoadingPrevious)
 | |
|       );
 | |
|     },
 | |
| 
 | |
|     shouldLoadMoreChats() {
 | |
|       return !this.listLoadingStatus && !this.isLoadingPrevious;
 | |
|     },
 | |
|   },
 | |
| 
 | |
|   created() {
 | |
|     bus.$on('scrollToMessage', () => {
 | |
|       this.focusLastMessage();
 | |
|       this.makeMessagesRead();
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   methods: {
 | |
|     focusLastMessage() {
 | |
|       setTimeout(() => {
 | |
|         this.attachListner();
 | |
|       }, 0);
 | |
|     },
 | |
| 
 | |
|     onToggleContactPanel() {
 | |
|       this.$emit('contactPanelToggle');
 | |
|     },
 | |
| 
 | |
|     attachListner() {
 | |
|       this.conversationPanel = this.$el.querySelector('.conversation-panel');
 | |
|       this.heightBeforeLoad =
 | |
|         this.getUnreadCount === 0
 | |
|           ? this.conversationPanel.scrollHeight
 | |
|           : this.$el.querySelector('.conversation-panel .unread--toast')
 | |
|               .offsetTop - 56;
 | |
|       this.conversationPanel.scrollTop = this.heightBeforeLoad;
 | |
|       this.conversationPanel.addEventListener('scroll', this.handleScroll);
 | |
|       this.isLoadingPrevious = false;
 | |
|     },
 | |
| 
 | |
|     handleScroll(e) {
 | |
|       const dataFetchCheck =
 | |
|         this.getMessages.dataFetched === true && this.shouldLoadMoreChats;
 | |
|       if (
 | |
|         e.target.scrollTop < 100 &&
 | |
|         !this.isLoadingPrevious &&
 | |
|         dataFetchCheck
 | |
|       ) {
 | |
|         this.isLoadingPrevious = true;
 | |
|         this.$store
 | |
|           .dispatch('fetchPreviousMessages', {
 | |
|             conversationId: this.currentChat.id,
 | |
|             before: this.getMessages.messages[0].id,
 | |
|           })
 | |
|           .then(() => {
 | |
|             this.conversationPanel.scrollTop =
 | |
|               this.conversationPanel.scrollHeight -
 | |
|               (this.heightBeforeLoad - this.conversationPanel.scrollTop);
 | |
|             this.isLoadingPrevious = false;
 | |
|             this.heightBeforeLoad =
 | |
|               this.getUnreadCount === 0
 | |
|                 ? this.conversationPanel.scrollHeight
 | |
|                 : this.$el.querySelector('.conversation-panel .unread--toast')
 | |
|                     .offsetTop - 56;
 | |
|           });
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     makeMessagesRead() {
 | |
|       if (this.getUnreadCount !== 0 && this.getMessages !== undefined) {
 | |
|         this.$store.dispatch('markMessagesRead', {
 | |
|           id: this.currentChat.id,
 | |
|           lastSeen: this.getMessages.messages.last().created_at,
 | |
|         });
 | |
|       }
 | |
|     },
 | |
|   },
 | |
| };
 | |
| </script>
 |