Custom Live Conversation Component – vue-quick-chat

The vue-quick-chat component allows you to insert a custom live chat on web applications.

Key Features:

  • Handle on type event and on message submit
  • Chat with multiple participants
  • Support for async actions like message uploaded status
  • Send images
  • Support for profile pictures

How to use it:

1. Import the component and stylesheet into your project.

import { Chat } from 'vue-quick-chat'
import '/path/to/vue-quick-chat.css';

2. Add the chat component to your template.

<template>
  <div id="app">
    <div class="content">
      <div class="chat-container">
        <Chat v-if="visible"
              :participants="participants"
              :myself="myself"
              :messages="messages"
              :chat-title="chatTitle"
              :placeholder="placeholder"
              :colors="colors"
              :border-style="borderStyle"
              :hide-close-button="hideCloseButton"
              :close-button-icon-size="closeButtonIconSize"
              :submit-icon-size="submitIconSize"
              :submit-image-icon-size="submitImageIconSize"
              :load-more-messages="toLoad.length > 0 ? loadMoreMessages : null"
              :async-mode="asyncMode"
              :scroll-bottom="scrollBottom"
              :display-header="true"
              :send-images="true"
              :profile-picture-config="profilePictureConfig"
              @onImageClicked="onImageClicked"
              @onImageSelected="onImageSelected"
              @onMessageSubmit="onMessageSubmit"
              @onType="onType"
              @onClose="onClose('param value')"/>
      </div>
      <div class="external-controller">
        <div class="controller-btn-container">
          <button class="btn-message" @click="addMessage">Add menssage</button>
          <button class="btn-participant" @click="addParticipant">Add participant</button>
          <button class="btn-participant" @click="changeAllProps">Change All Props</button>
        </div>
        <div class="message-list">
          <ol>
            <li v-for="(message, index) in messages" :key="index">
              {{message.content}}
            </li>
          </ol>
        </div>
      </div>
    </div>
  </div>
</template>

3. Register the component and initialize your data as follows:

export default {
  name: 'app',
  components: {
      Chat
  },
  data() {
      return {
          visible: true,
          participants: [
              {
                  name: 'Arnaldo',
                  id: 1,
                  profilePicture: 'https://upload.wikimedia.org/wikipedia/en/thumb/a/a1/NafSadh_Profile.jpg/768px-NafSadh_Profile.jpg'
              },
              {
                  name: 'Adam',
                  id: 2,
                  profilePicture: 'https://lh3.googleusercontent.com/-G1d4-a7d_TY/AAAAAAAAAAI/AAAAAAAAAAA/AAKWJJPez_wX5UCJztzEUeCxOd7HBK7-jA.CMID/s83-c/photo.jpg'
              }
          ],
          myself: {
              name: 'John Doe',
              id: 3,
              profilePicture: 'https://lh3.googleusercontent.com/-G1d4-a7d_TY/AAAAAAAAAAI/AAAAAAAAAAA/AAKWJJPez_wX5UCJztzEUeCxOd7HBK7-jA.CMID/s83-c/photo.jpg'
          },
          messages: [
              {
                  content: "Really?! I don't care! Haha",
                  participantId: 1,
                  timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
                  uploaded: true,
                  viewed: true,
                  type: 'text'
              },
              {
                  content: "Really?! I don't care! Haha",
                  participantId: 1,
                  timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
                  uploaded: true,
                  viewed: true,
                  type: 'text'
              },
              {
                  content: "Really?! I don't care! Haha",
                  participantId: 1,
                  timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
                  uploaded: true,
                  viewed: true,
                  type: 'text'
              },
              {
                  content: "Hey, Jhon Doe! How are you today",
                  participantId: 1,
                  timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
                  uploaded: true,
                  viewed: true,
                  type: 'text'
              },
              {
                  content: "Hey, Adam! I'm felling really fine this evening.",
                  participantId: 3,
                  timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
                  uploaded: true,
                  viewed: true,
                  type: 'text'
              },
              {
                  content: "Really?! I don't care! Haha",
                  participantId: 1,
                  timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
                  uploaded: true,
                  viewed: true,
                  type: 'text'
              },
          ],
          chatTitle: 'My chat title',
          placeholder: 'send your message',
          colors: {
              header: {
                  bg: '#d30303',
                  text: '#fff'
              },
              message: {
                  myself: {
                      bg: '#fff',
                      text: '#525252'
                  },
                  others: {
                      bg: '#fb4141',
                      text: '#fff'
                  },
                  messagesDisplay: {
                      //bg: 'rgb(247, 243, 243)',
                      //bg: '#f7f3f3'
                      bg: '#f7f3f3'
                  }
              },
              submitIcon: '#b91010',
              submitImageIcon: '#b91010',
          },
          borderStyle: {
              topLeft: "10px",
              topRight: "10px",
              bottomLeft: "10px",
              bottomRight: "10px",
          },
          hideCloseButton: false,
          submitIconSize: 24,
          submitImageIconSize: 24,
          closeButtonIconSize: "20px",
          asyncMode: true,
          toLoad: [
              {
                  content: 'Hey, John Doe! How are you today?',
                  participantId: 2,
                  timestamp: { year: 2016, month: 3, day: 5, hour: 10, minute: 10, second: 3, millisecond: 123 },
                  uploaded: true,
                  viewed: true
              },
              {
                  content: "Hey, Adam! I'm feeling really fine this evening.",
                  participantId: 3,
                  timestamp: { year: 2016, month: 1, day: 5, hour: 19, minute: 10, second: 3, millisecond:123 },
                  uploaded: true,
                  viewed: true
              },
          ],
          scrollBottom: {
              messageSent: true,
              messageReceived: false
          },
          profilePictureConfig: {
              others: true,
              myself: true,
              styles: {
                  width: '30px',
                  height: '30px',
                  borderRadius: '50%'
              }
          }
      }
  },
  methods: {
      // eslint-disable-next-line
      onType: function (e) {
          // eslint-disable-next-line
          console.log('typing');
      },
      loadMoreMessages(resolve) {
          setTimeout(() => {
              resolve(this.toLoad);
              //Make sure the loaded messages are also added to our local messages copy or they will be lost
              this.messages.unshift(...this.toLoad);
              this.toLoad = [];
          }, 1000);
      },
      onMessageSubmit(message) {
          /*
          * example simulating an upload callback.
          * It's important to notice that even when your message wasn't send
          * yet to the server you have to add the message into the array
          */
          this.messages.push(message);
          /*
          * you can update message state after the server response
          */
          // timeout simulating the request
          setTimeout(() => {
              message.uploaded = true
              message.viewed = true
          }, 2000)
      },
      onClose(param) {
          console.log(param)
          this.visible = false;
      },
      addMessage() {
          /* this.messages.push(
              {
                  content: "Update state",
                  // myself: false,
                  participantId: 1,
                  timestamp: {year: 2014, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
                  uploaded: true,
                  viewed: true
              }
          ) */
          this.messages.push(
              {
                  type: 'image',
                  preview: null,
                  src: 'https://149364066.v2.pressablecdn.com/wp-content/uploads/2017/03/vue.jpg',
                  content: 'image',
                  participantId: 1,
                  timestamp: {year: 2014, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
                  uploaded: true,
                  viewed: false
              }
          )
      },
      addParticipant() {
          let participant = {
              name: 'Karl',
              id: 4
          };
          this.participants.push(participant)
      },
      changeAllProps() {
          this.myself = {
              name: 'I Qanah',
              id: 3
          };
          this.participants = [
              {
                  name: 'Ibrahim',
                  id: 5
              },
              {
                  name: 'Ana',
                  id: 6
              }
          ];
          this.messages = [
              {
                  content: "Really?! I don't care! Haha",
                  participantId: 5,
                  timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
                  uploaded: true,
                  viewed: true
              },
              {
                  content: "Really?! I don't care! Haha",
                  participantId: 6,
                  timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
                  uploaded: true,
                  viewed: true
              },
              {
                  content: "Really?! I don't care! Haha",
                  participantId: 3,
                  timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
                  uploaded: true,
                  viewed: true
              }
          ];
          this.toLoad = [
              {
                  content: 'Hey, John Doe! How are you today?',
                  participantId: 6,
                  timestamp: { year: 2016, month: 3, day: 5, hour: 10, minute: 10, second: 3, millisecond: 123 },
                  uploaded: true,
                  viewed: true
              },
              {
                  content: "Hey, Adam! I'm feeling really fine this evening.",
                  participantId: 3,
                  timestamp: { year: 2016, month: 10, day: 5, hour: 19, minute: 10, second: 3, millisecond:123 },
                  uploaded: true,
                  viewed: true
              },
          ];
          this.chatTitle = 'Change All Participants';
          this.placeholder = 'اكتب رسالتك هنا';
      },
      onImageSelected({file, message}){
          let src = 'https://149364066.v2.pressablecdn.com/wp-content/uploads/2017/03/vue.jpg'
          this.messages.push(message);
          /**
           * This timeout simulates a requisition that uploads the image file to the server.
           * It's up to you implement the request and deal with the response in order to
           * update the message status and the message URL
           */
          setTimeout((res) => {
              message.uploaded = true
              message.src = res.src
          }, 3000, {src});
      },
      onImageClicked(message){
          /**
           * This is the callback function that is going to be executed when some image is clicked.
           * You can add your code here to do whatever you need with the image clicked. A common situation is to display the image clicked in full screen.
           */
          console.log('Image clicked', message.src)
      }
  }
}

4. All possible props.

participants: {
  type: Array,
  required: true
},
messages: {
  type: Array,
  required: true
},
myself: {
  type: Object,
  required: true
},
chatTitle: {
  type: String,
  required: false,
  default: ''
},
placeholder: {
  type: String,
  required: false,
  default: 'type your message here'
},
colors: {
  type: Object,
  required: true
},
borderStyle: {
  type: Object,
  required: false,
  default: () => {
      return {
          topLeft: "10px",
          topRight: "10px",
          bottomLeft: "10px",
          bottomRight: "10px",
      }
  }
},
hideCloseButton: {
  type: Boolean,
  required: false,
  default: false
},
submitIconSize: {
  type: Number,
  required: false,
  default: 24
},
submitImageIconSize: {
  type: Number,
  required: false,
  default: 24
},
closeButtonIconSize: {
  type: String,
  required: false,
  default: "15px"
},
asyncMode: {
  type: Boolean,
  required: false,
  default: false
},
loadMoreMessages: {
  type: Function,
  required: false,
  default: null
},
scrollBottom:{
  type: Object,
  required: false,
  default: () => {
      return {
          messageSent: true,
          messageReceived: false
      }
  }
},
displayHeader: {
  type: Boolean,
  required: false,
  default: true
},
sendImages: {
    type: Boolean,
    required: false,
    default: true
},
profilePictureConfig: {
  type: Object,
  required: false,
  default: () => {
      return {
          others: true,
          myself: false,
          styles: {
              width: '25px',
              height: '25px',
              borderRadius: '50%'
          }
      }
  }
}

Preview:

Custom Live Conversation Component - vue-quick-chat

Changelog:

v1.2.8 (02/07/2021)

  • Fix setMessages

v1.2.7 (01/16/2021)

  • Remove package-lock and Fix null timestamps to current time

v1.2.6 (09/12/2020)

  • Add verification regex to avoid empty messages

v1.2.5 (08/01/2020)

  • Implement acceptImageTypes prop

Download Details:

Author: MatheusrdSantos

Live Demo: https://github.com/MatheusrdSantos/vue-quick-chat/tree/master/public

Download Link: https://github.com/MatheusrdSantos/vue-quick-chat/archive/master.zip

Official Website: https://github.com/MatheusrdSantos/vue-quick-chat

Install & Download:

Tags:

Add Comment