mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-03 20:48:07 +00:00 
			
		
		
		
	* 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>
 |