Building a chat app for the browser is not a very straightforward task. It requires you to learn some realtime technology (like socket.io) and how to manage connections between participants. Not only that, but also you need to make sure your connections are reliable so your app doesn't miss a message sent between users.
The chat dashboard layout is easy to understandable and too responsive. The website is able to access from any location at any time. To make a more fun chat use the filter choice free. Instantly meet any random guys from whole the world. A lot of people are online at any time so, start chat at any time. Developers use CometChat's API and SDK to add voice, video and text chat to websites and mobile apps in minutes!
Pando Media Booster is a Freeware software in the category Games & Entertainment developed by Pando Networks Inc. It was checked for updates 628 times by the users of our client application UpdateStar during the last month. The latest version of Pando Media Booster is. Pando media booster installer. If the issue persists, download Pando Media Booster from the following link and install it: Pando Media Booster Installer Once it is installed you should be able to. Next you must install the Pando Media Booster software to proceed with the download. Once the installation is complete, click Done to exit the installer. Oct 04, 2013 How to create a 3D Terrain with Google Maps and height maps in Photoshop - 3D Map Generator Terrain - Duration: 20:32. Orange Box Ceo 8,326,541 views. Pando Media Booster Studio 16 When downloading any Pinnacle Studio 16 related components that are not available on the local machine you will be presented with a message about Pando Media Booster. This Pando Media Booster is safe and can be installed without issue. Pando Media Booster free download - Driver Booster, VLC Media Player, Windows Media Player, and many more programs.
These are just a few challenges that you can face when implementing your own chat system. But luckily for us, CometChat comes to save us the headache. CometChat doesn't only solve these issues, it also provides us with more cool features like chat groups, user roles, and friends list.
In this tutorial, I'll teach you how to build your own one-on-one chat app in Vue from scratch. After you finish this tutorial, you should have something like this:
You can get the tutorial's source code from GitHub. The instructions on how to run it are included there. It's a good idea to run the demo before diving in to make sure you have the full picture of what we're going to build here.
Creating a new Vue project
Let's create a new Vue project using Vue CLI. If you don't have it installed on your machine yet, install it via npm like this:
{% c-line %} npm install -g @vue/cli{% c-line-end %}
To create a new project, run the following command:
{% c-line %} vue create vue-one-on-one-chat-app{% c-line-end %}
This will ask you to pick a preset. Let's choose typical-spa for this tutorial.
After it's finished, go to the project's directory and run it using: npm run serve.
Now if you open the browser to http://localhost:8080, you should see this:
Great! Now we have a running Vue app. Now let's create and style all necessary pages, and then integrate CometChat into it.
Let's start with the router. Open src/router.js and replace everything there with this:
{% c-block language='javascript' %}
import Vue from 'vue'
import Router from 'vue-router'
import Login from './views/Login.vue'
import Chat from './views/Chat.vue'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'home',
redirect: 'login'
},
{
path: '/login',
name: 'login',
component: Login
},
{
path: '/chat',
name: 'chat',
component: Chat
}
]
})
{% c-block-end %}
import Vue from 'vue'
import Router from 'vue-router'
import Login from './views/Login.vue'
import Chat from './views/Chat.vue'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'home',
redirect: 'login'
},
{
path: '/login',
name: 'login',
component: Login
},
{
path: '/chat',
name: 'chat',
component: Chat
}
]
})
{% c-block-end %}
We'll have only two pages in this app, login and chat. The chat page is where the bulk of our work would be. The login page is just responsible for authenticating the user. And since the user should be authenticated before using the app, we're redirecting the homepage (path: '/') to the login page.
You can also see how we used the history mode in the router to get rid of the hash in the url.
We've told the router about our two pages, but we didn't create them yet. So remove any existing components from src/views and create Login.vue and Chat.vue.
Preparing the pages
Before we start implementing our pages, we need to modify our root component, App.vue, then load the fonts and images that we'll be using in this app.
Open src/App.vue and replace everything with this:
{% c-block language='html' %}
<template>
<div>
<router-view/>
</div>
</template>
<style>
html, body
padding: 0
margin: 0
height: 100vh
*
box-sizing: border-box
#app
-webkit-font-smoothing: antialiased
-moz-osx-font-smoothing: grayscale
height: 100%
</style>
{% c-block-end %}
<template>
<div>
<router-view/>
</div>
</template>
<style>
html, body
padding: 0
margin: 0
height: 100vh
*
box-sizing: border-box
#app
-webkit-font-smoothing: antialiased
-moz-osx-font-smoothing: grayscale
height: 100%
</style>
{% c-block-end %}
Nothing important to explain here — we just removed the *#nav* element and modified the CSS.
We'll use Roboto and Abril Fatface fonts in this app. To load them, open public/index.html, and add this in the <head> section:
{% c-line %} <link href='https://fonts.googleapis.com/css?family=Abril+Fatface|Roboto:400,500&display=swap'>{% c-line-end %}
Finally, let's get the needed images from the demo's repo and add them to src/assets.
Implementing Login.vue
Let's first add the HTML code for this component:
{% c-block language='html' %}
<template>
<div>
<div>
<div>
<h1>
Welcome Back
</h1>
<p>
To access this demo, you can use one of the following four users: <strong>superhero1</strong>, <strong>superhero2</strong>, <strong>superhero3</strong>, or <strong>superhero4</strong>.
</p>
<form
@submit.prevent='login'
>
<div>
<label>
Username
</label>
<div>
<input
v-model='username'
:disabled='loggingIn'
type='text'
required='required'
>
<svg
viewBox='0 0 24 24'
>
<path
fill='#BDCCD7'
d='M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z'
/>
</svg>
</div>
<button
:disabled='loggingIn'
>
<template v-if='!loggingIn'>
LOG IN
</template>
<template v-else>
LOGGING IN.
</template>
</button>
</div>
</form>
</div>
<img
src='./assets/login-illustration.svg'
>
</div>
</div>
</template>
{% c-block-end %}
<template>
<div>
<div>
<div>
<h1>
Welcome Back
</h1>
<p>
To access this demo, you can use one of the following four users: <strong>superhero1</strong>, <strong>superhero2</strong>, <strong>superhero3</strong>, or <strong>superhero4</strong>.
</p>
<form
@submit.prevent='login'
>
<div>
<label>
Username
</label>
<div>
<input
v-model='username'
:disabled='loggingIn'
type='text'
required='required'
>
<svg
viewBox='0 0 24 24'
>
<path
fill='#BDCCD7'
d='M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z'
/>
</svg>
</div>
<button
:disabled='loggingIn'
>
<template v-if='!loggingIn'>
LOG IN
</template>
<template v-else>
LOGGING IN.
</template>
</button>
</div>
</form>
</div>
<img
src='./assets/login-illustration.svg'
>
</div>
</div>
</template>
{% c-block-end %}
Three things to notice here:
- v-model='username' — we're keeping track of the entered username in the username data property, which we'll create later.
- @submit.prevent='login' — when the user submits the login form, we should call a method named login(), which we don't have yet.
- When the user is currently logging in, we should disable the username input and the login button. Note how we do that in the code above using the loggingIn flag (which we'll create in a bit). So we're using :disabled='loggingIn' on the input and the button. We're also updating the button's text to “LOGGING IN.” when loggingIn is true.
Now let's write the JS code for this component:
{% c-block language='javascript' %}
<script>
export default {
data () {
return {
username: ',
loggingIn: false
}
},
methods: {
login () {}
}
}
</script>
{% c-block-end %}
<script>
export default {
data () {
return {
username: ',
loggingIn: false
}
},
methods: {
login () {}
}
}
</script>
{% c-block-end %}
We've defined our data properties, username and loggingIn. We've also added the login method, which we'll implement later.
Lastly, let's add the CSS code:
{% c-block language='css' %}
<style scoped>
.login-page
background: url('./assets/login-background.svg')
background-repeat: no-repeat
background-size: cover
background-position: center center
height: 100%
display: flex
justify-content: center
align-items: center
.login-container
background: #FFFFFE
max-width: 700px
width: calc(100% - 20px)
padding: 60px 50px
border-radius: 6px
box-shadow: 0px 2px 38px rgba(45, 49, 63, 0.397236)
display: flex
justify-content: space-between
.main
flex: 1
text-align: left
padding-right: 30px
.title
font-family: 'Abril Fatface', cursive
font-weight: normal
color: #2D313F
font-size: 26px
line-height: 35px
.description
font-family: 'Roboto', sans-serif
color: #444
line-height: 1.4
.description strong
font-weight: 500
.login-button
font-family: 'Roboto', sans-serif
font-weight: bold
font-size: 13px
line-height: 15px
display: flex
align-items: center
text-align: center
justify-content: center
text-transform: uppercase
color: #FFFFFF
background: #1B47DB
box-shadow: 0px 5px 13px rgba(27, 71, 219, 0.303349)
border-radius: 4.09091px
border: none
width: 100%
padding: 12px
margin-top: 50px
outline: none
cursor: pointer
.login-button:hover
background: lighten(#1B47DB, 5%)
.login-button:disabled
background: lighten(#1B47DB, 20%)
cursor: default
.label
font-family: 'Roboto', sans-serif
font-weight: bold
font-size: 13.0909px
line-height: 15px
color: #BDCCD7
.username-input
font-family: 'Roboto', sans-serif
font-weight: normal
font-size: 13px
line-height: 15px
color: #2D313F
mix-blend-mode: normal
opacity: 0.8
border: none
flex: 1
outline: none
.username-input:disabled
color: #888
.input-group
border-bottom: 1px solid #BDCCD7
display: flex
justify-content: space-between
align-items: center
padding: 3px 0
@media (max-width: 605px)
.illustration
display: none
.main
padding: 0
</style>
{% c-block-end %}
<style scoped>
.login-page
background: url('./assets/login-background.svg')
background-repeat: no-repeat
background-size: cover
background-position: center center
height: 100%
display: flex
justify-content: center
align-items: center
.login-container
background: #FFFFFE
max-width: 700px
width: calc(100% - 20px)
padding: 60px 50px
border-radius: 6px
box-shadow: 0px 2px 38px rgba(45, 49, 63, 0.397236)
display: flex
justify-content: space-between
.main
flex: 1
text-align: left
padding-right: 30px
.title
font-family: 'Abril Fatface', cursive
font-weight: normal
color: #2D313F
font-size: 26px
line-height: 35px
.description
font-family: 'Roboto', sans-serif
color: #444
line-height: 1.4
.description strong
font-weight: 500
.login-button
font-family: 'Roboto', sans-serif
font-weight: bold
font-size: 13px
line-height: 15px
display: flex
align-items: center
text-align: center
justify-content: center
text-transform: uppercase
color: #FFFFFF
background: #1B47DB
box-shadow: 0px 5px 13px rgba(27, 71, 219, 0.303349)
border-radius: 4.09091px
border: none
width: 100%
padding: 12px
margin-top: 50px
outline: none
cursor: pointer
.login-button:hover
background: lighten(#1B47DB, 5%)
.login-button:disabled
background: lighten(#1B47DB, 20%)
cursor: default
.label
font-family: 'Roboto', sans-serif
font-weight: bold
font-size: 13.0909px
line-height: 15px
color: #BDCCD7
.username-input
font-family: 'Roboto', sans-serif
font-weight: normal
font-size: 13px
line-height: 15px
color: #2D313F
mix-blend-mode: normal
opacity: 0.8
border: none
flex: 1
outline: none
.username-input:disabled
color: #888
.input-group
border-bottom: 1px solid #BDCCD7
display: flex
justify-content: space-between
align-items: center
padding: 3px 0
@media (max-width: 605px)
.illustration
display: none
.main
padding: 0
</style>
{% c-block-end %}
If you check the login page in the browser, you should see this:
Preparing Chat.vue
Here's how this page would look like in the end:
Instead of writing all the code into this single component, let's break the content of this component into multiple components. We'll have three components in this page: Navbar.vue, ChatSidebar.vue, and ChatMain.vue.
Let's create these components into src/components and put the following code into Chat.vue:
{% c-block language='javascript' %}
<template>
<div>
<navbar/>
<div>
<chat-sidebar/>
<chat-main/>
</div>
</div>
</template>
<script>
import Navbar from '@/components/Navbar'
import ChatSidebar from '@/components/ChatSidebar'
import ChatMain from '@/components/ChatMain'
export default {
components: {
Navbar,
ChatSidebar,
ChatMain
}
}
</script>
<style scoped>
.chat-page
background: url('./assets/chat-background.svg')
background-repeat: no-repeat
background-size: cover
background-position: top center
min-height: 100%
.chat-container
background: #FFFFFE
box-shadow: 0px 2px 36px rgba(45, 49, 63, 0.357436)
border-radius: 6px
margin: 50px auto 50px
max-width: 800px
width: calc(100% - 20px)
height: 500px
min-height: 500px
display: flex
justify-content: space-between
.chat-sidebar
width: 240px
.chat-main
flex: 1
@media (max-width: 635px)
.chat-sidebar
width: 90px
</style>
{% c-block-end %}
<template>
<div>
<navbar/>
<div>
<chat-sidebar/>
<chat-main/>
</div>
</div>
</template>
<script>
import Navbar from '@/components/Navbar'
import ChatSidebar from '@/components/ChatSidebar'
import ChatMain from '@/components/ChatMain'
export default {
components: {
Navbar,
ChatSidebar,
ChatMain
}
}
</script>
<style scoped>
.chat-page
background: url('./assets/chat-background.svg')
background-repeat: no-repeat
background-size: cover
background-position: top center
min-height: 100%
.chat-container
background: #FFFFFE
box-shadow: 0px 2px 36px rgba(45, 49, 63, 0.357436)
border-radius: 6px
margin: 50px auto 50px
max-width: 800px
width: calc(100% - 20px)
height: 500px
min-height: 500px
display: flex
justify-content: space-between
.chat-sidebar
width: 240px
.chat-main
flex: 1
@media (max-width: 635px)
.chat-sidebar
width: 90px
</style>
{% c-block-end %}
This is just the start for Chat.vue. We'll keep updating it as we're working on the app.
Implementing Navbar.vue
Open src/components/Navbar.vue, and add this to the HTML section:
{% c-block language='html' %}
<template>
<div>
<div>
<img
src='./assets/logo.svg'
>
<span>
Chat
</span>
</div>
<div>
<span>
Welcome <strong>Superhero</strong>
</span>
<spinner
v-if='loggingOut'
:size='20'
/>
<img
v-else
src='https://ui-avatars.com/api/?size=128&name=Superhero'
@click='logout'
>
</div>
</div>
</template>
{% c-block-end %}
<template>
<div>
<div>
<img
src='./assets/logo.svg'
>
<span>
Chat
</span>
</div>
<div>
<span>
Welcome <strong>Superhero</strong>
</span>
<spinner
v-if='loggingOut'
:size='20'
/>
<img
v-else
src='https://ui-avatars.com/api/?size=128&name=Superhero'
@click='logout'
>
</div>
</div>
</template>
{% c-block-end %}
We're here hardcoding the user name and the avatar. Once we have the real data available, we'll get back to this file and update it.
As you can see, we should log out the user if he or she clicked on the avatar — we haven't defined this method yet, but we'll do that later. When the user is currently logging out, we should display a loading indicator, <spinner>, in place of the avatar (that's what loggingOut flag is for).
Now let's add the JS code below the HTML section:
{% c-block language='javascript' %}
<script>
import Spinner from '@/components/Spinner'
export default {
components: { Spinner },
data () {
return {
loggingOut: false
}
},
methods: {
logout () {}
}
}
</script>
{% c-block-end %}
<script>
import Spinner from '@/components/Spinner'
export default {
components: { Spinner },
data () {
return {
loggingOut: false
}
},
methods: {
logout () {}
}
}
</script>
{% c-block-end %}
So we've defined the loggingOut flag and the logout method. Note that we'll implement the logout method later because we need to connect to CometChat for that.
Lastly, let's add the CSS code:
{% c-block language='css' %}
<style scoped>
.navbar
height: 50px
width: 100%
background: #FFFFFE
padding: 0 20px
display: flex
justify-content: space-between
align-items: center
font-family: 'Roboto', sans-serif
.left, .right
display: flex
justify-content: center
align-items: center
.logo
margin-right: 10px
.title
color: #2D313F
font-family: 'Abril Fatface', cursive
font-weight: normal
font-size: 22px
line-height: 30px
.welcome-message
margin-right: 10px
.user-name
font-weight: 500
.avatar
width: 30px
height: 30px
border-radius: 50%
overflow: hidden
cursor: pointer
</style>
{% c-block-end %}
<style scoped>
.navbar
height: 50px
width: 100%
background: #FFFFFE
padding: 0 20px
display: flex
justify-content: space-between
align-items: center
font-family: 'Roboto', sans-serif
.left, .right
display: flex
justify-content: center
align-items: center
.logo
margin-right: 10px
.title
color: #2D313F
font-family: 'Abril Fatface', cursive
font-weight: normal
font-size: 22px
line-height: 30px
.welcome-message
margin-right: 10px
.user-name
font-weight: 500
.avatar
width: 30px
height: 30px
border-radius: 50%
overflow: hidden
cursor: pointer
</style>
{% c-block-end %}
Before moving to the next section, let's add the Spinner component. So in src/components create a new file named Spinner.vue, and put the following into it:
{% c-block language='html' %}
<template>
<div>
<!-- By Sam Herbert (@sherb), for everyone. More @ http://goo.gl/7AJzbL -->
<svg :width='size' :height='size' viewBox='0 0 38 38' xmlns='http://www.w3.org/2000/svg' stroke='#003'>
<g fill='none' fill-rule='evenodd'>
<g transform='translate(1 1)' stroke-width='2'>
<circle stroke-opacity='.5' cx='18' cy='18' r='18'/>
<path d='M36 18c0-9.94-8.06-18-18-18'>
<animateTransform
attributeName='transform'
type='rotate'
from='0 18 18'
to='360 18 18'
dur='1s'
repeatCount='indefinite'/>
</path>
</g>
</g>
</svg>
</div>
</template>
<script>
export default {
props: {
size: {
type: Number,
default: 60
}
}
}
</script>
<style scoped>
.spinner {
display: flex;
justify-content: center;
align-items: center;
}
</style>
{% c-block-end %}
<template>
<div>
<!-- By Sam Herbert (@sherb), for everyone. More @ http://goo.gl/7AJzbL -->
<svg :width='size' :height='size' viewBox='0 0 38 38' xmlns='http://www.w3.org/2000/svg' stroke='#003'>
<g fill='none' fill-rule='evenodd'>
<g transform='translate(1 1)' stroke-width='2'>
<circle stroke-opacity='.5' cx='18' cy='18' r='18'/>
<path d='M36 18c0-9.94-8.06-18-18-18'>
<animateTransform
attributeName='transform'
type='rotate'
from='0 18 18'
to='360 18 18'
dur='1s'
repeatCount='indefinite'/>
</path>
</g>
</g>
</svg>
</div>
</template>
<script>
export default {
props: {
size: {
type: Number,
default: 60
}
}
}
</script>
<style scoped>
.spinner {
display: flex;
justify-content: center;
align-items: center;
}
</style>
{% c-block-end %}
After this, your http://localhost:8080/chat page should look like this:
Implementing ChatMain.vue
As always, let's start with the HTML code.
{% c-block language='html' %}
<template>
<div>
<div>
Active Contact Name
</div>
<!-- Loading Messages State -->
<div
v-if='loadingMessages'
>
<spinner/>
<span>
Loading Messages.
</span>
</div>
<!-- End of Loading Messages State -->
<!-- Empty State -->
<div
v-else-if='messages.length 0'
>
<img
src='./assets/empty-state.svg'
>
<h2>
No new message?
</h2>
<span>
Send your first message below.
</span>
</div>
<!-- End of Empty State -->
<!-- Has Messages State -->
<chat-messages
v-else
ref='messagesContainer'
:messages='messages'
/>
<!-- End of Has Messages State -->
<!-- Message Input -->
<form
@submit.prevent='sendMessage'
>
<input
v-model='messageText'
type='text'
placeholder='Type something'
required='required'
:disabled='sendingMessage'
>
<spinner
v-if='sendingMessage'
:size='20'
/>
</form>
<!-- End of Message Input -->
</div>
</template>
{% c-block-end %}
<template>
<div>
<div>
Active Contact Name
</div>
<!-- Loading Messages State -->
<div
v-if='loadingMessages'
>
<spinner/>
<span>
Loading Messages.
</span>
</div>
<!-- End of Loading Messages State -->
<!-- Empty State -->
<div
v-else-if='messages.length 0'
>
<img
src='./assets/empty-state.svg'
>
<h2>
No new message?
</h2>
<span>
Send your first message below.
</span>
</div>
<!-- End of Empty State -->
<!-- Has Messages State -->
<chat-messages
v-else
ref='messagesContainer'
:messages='messages'
/>
<!-- End of Has Messages State -->
<!-- Message Input -->
<form
@submit.prevent='sendMessage'
>
<input
v-model='messageText'
type='text'
placeholder='Type something'
required='required'
:disabled='sendingMessage'
>
<spinner
v-if='sendingMessage'
:size='20'
/>
</form>
<!-- End of Message Input -->
</div>
</template>
{% c-block-end %}
The main area of the chat can have one of the following three states:
- Loading messages state: when fetching previous messages between participants, we should show a loading view that tells users about that.
- Empty state: when messages are fetched but nothing was returned from the server, then we should display a message that tells the user that there are no messages between you the active contact yet.
- Has messages state: in this state, we display any existing messages between the logged-in user and the selected contact. We're displaying the messages in another component called ChatMessages, which we didn't create yet. But since we're at it, let's create src/components/ChatMessage.vue.
Below the messages section, we have the messages input area. We're keeping track of the currently entered text message inside messageText data property. If the user pressed the Enter key, we should send the message by calling the sendMessage method. And as the message is being sent, we should disable the text input and show a loading indicator. We can know that the message is being sent from the sendingMessage data property, which we'll create next.
Now let's add the JS and CSS code for this component:
{% c-block language='javascript' %}
<script>
import ChatMessages from '@/components/ChatMessages'
import Spinner from '@/components/Spinner'
export default {
components: {
ChatMessages,
Spinner
},
data () {
return {
loadingMessages: false,
messages: [],
messageText: ',
sendingMessage: false
}
},
methods: {
sendMessage () {}
}
}
</script>
{% c-block-end %}
{% c-block language='css' %}
<style scoped>
.chat-main
border-left: 1px solid #BDCCD7
background: #F8F9FB
border-radius: 0 6px 6px 0
display: flex
justify-content: space-between
flex-direction: column
max-height: 100%
.header
background: #FFFFFE
font-family: 'Roboto', sans-serif
font-weight: normal
font-size: 15px
line-height: 18px
color: #2D313F
padding: 20px 25px
border-bottom: 1px solid #BDCCD7
border-radius: 0 6px 0 0
.empty-state
display: flex
justify-content: center
align-items: center
flex-direction: column
margin-top: 50px
.empty-state-title
font-family: 'Abril Fatface', cursive
font-weight: normal
font-size: 26px
line-height: 35px
text-align: center
color: #1B47DB
margin: 15px 0
.empty-state-description
font-family: 'Roboto', sans-serif
font-weight: normal
font-size: 16px
line-height: 22px
text-align: center
color: #2D313F
mix-blend-mode: normal
opacity: 0.8
.chat-input-form
background: #FFFFFF
display: flex
box-shadow: 0px -1px 0px rgba(189, 204, 215, 0.544362)
.sending-message-spinner
padding: 15px
.chat-input
width: 100%
background: #FFFFFF
border: none
outline: none
resize: none
border-radius: 0 0 6px 0
font-family: 'Roboto', sans-serif
font-weight: normal
font-size: 16px
color: #333
padding: 20px
.chat-input::placeholder
color: #BBBEBE
.loading-messages
display: flex
flex-direction: column
align-items: center
justify-content: center
.loading-title
font-family: 'Roboto', sans-serif
margin-top: 20px
font-size: 20px
</style>
{% c-block-end %}
<script>
import ChatMessages from '@/components/ChatMessages'
import Spinner from '@/components/Spinner'
export default {
components: {
ChatMessages,
Spinner
},
data () {
return {
loadingMessages: false,
messages: [],
messageText: ',
sendingMessage: false
}
},
methods: {
sendMessage () {}
}
}
</script>
{% c-block-end %}
{% c-block language='css' %}
<style scoped>
.chat-main
border-left: 1px solid #BDCCD7
background: #F8F9FB
border-radius: 0 6px 6px 0
display: flex
justify-content: space-between
flex-direction: column
max-height: 100%
.header
background: #FFFFFE
font-family: 'Roboto', sans-serif
font-weight: normal
font-size: 15px
line-height: 18px
color: #2D313F
padding: 20px 25px
border-bottom: 1px solid #BDCCD7
border-radius: 0 6px 0 0
.empty-state
display: flex
justify-content: center
align-items: center
flex-direction: column
margin-top: 50px
.empty-state-title
font-family: 'Abril Fatface', cursive
font-weight: normal
font-size: 26px
line-height: 35px
text-align: center
color: #1B47DB
margin: 15px 0
.empty-state-description
font-family: 'Roboto', sans-serif
font-weight: normal
font-size: 16px
line-height: 22px
text-align: center
color: #2D313F
mix-blend-mode: normal
opacity: 0.8
.chat-input-form
background: #FFFFFF
display: flex
box-shadow: 0px -1px 0px rgba(189, 204, 215, 0.544362)
.sending-message-spinner
padding: 15px
.chat-input
width: 100%
background: #FFFFFF
border: none
outline: none
resize: none
border-radius: 0 0 6px 0
font-family: 'Roboto', sans-serif
font-weight: normal
font-size: 16px
color: #333
padding: 20px
.chat-input::placeholder
color: #BBBEBE
.loading-messages
display: flex
flex-direction: column
align-items: center
justify-content: center
.loading-title
font-family: 'Roboto', sans-serif
margin-top: 20px
font-size: 20px
</style>
{% c-block-end %}
Here's what you should see in your browser now:
Installing and initializing CometChat
Now we're ready to start integrating CometChat into our app. To do that, we first have to create a new pro account in CometChat. You can create it from app.cometchat.com/#/register.
For each app you build, you have to create a new app in CometChat. You can do that easily from the dashboard. Just enter the app name in the 'Add New App' box, and hit the '+' button. In our example let's name it 'one-on-one chat app'.
Hold your horses ⚠️?!
To follow this tutorial or run the example source code you'll need to create a V1 application.
To follow this tutorial or run the example source code you'll need to create a V1 application.
v2 will be out of beta soon at which point we will update this tutorial.
For this tutorial, we need to know two pieces of information from CometChat: the App ID and the API Key.
You can get the App Id from the dashboard below the name of the app you've just created.
And for the API Key, click on 'Explore' in the app box. Then go to the 'API Keys' tab from the left sidebar. Then copy the auth-only api key.
Instead of embedding those keys directly into our code, let’s store them as environment variables so we can easily use different ones for different modes (like development, test, and production). To do so, create a new .env.local in your project's root directory. Then add this to it:
{% c-block %}
VUE_APP_COMETCHAT_APP_ID=YOUR_APP_ID
VUE_APP_COMETCHAT_API_KEY=YOUR_API_KEY
{% c-block-end %}
VUE_APP_COMETCHAT_APP_ID=YOUR_APP_ID
VUE_APP_COMETCHAT_API_KEY=YOUR_API_KEY
{% c-block-end %}
Then just replace the values with yours.
Before we can use CometChat, we have to install it first. So, run this from your terminal:
{% c-line %} npm install --save @cometchat-pro/chat{% c-line-end %}
We won't be able to use CometChat until we initialize it with our App ID. Since this is the first thing we need to do in the app, let's initialize it from src/main.js file.
So, open your main.js file, and import CometChat at the top, like this: https://jxexjg.weebly.com/adobe-acrobat-for-mac-catalina-download.html.
{% c-line %} import { CometChat } from '@cometchat-pro/chat'{% c-line-end %}
Then call CometChat.init() below that.
{% c-block language='javascript' %}
const appId = process.env.VUE_APP_COMETCHAT_APP_ID
CometChat.init(appId)
.then(() => {
console.log('CometChat was initialized successfully!')
})
.catch(() => {
console.log('An error occured while initializing CometChat')
})
{% c-block-end %}
const appId = process.env.VUE_APP_COMETCHAT_APP_ID
CometChat.init(appId)
.then(() => {
console.log('CometChat was initialized successfully!')
})
.catch(() => {
console.log('An error occured while initializing CometChat')
})
{% c-block-end %}
Note how we fetched our CometChat appId from our env variables using process.env.VUE_APP_COMETCHAT_APP_ID.
Authenticating the user
Before a user can use CometChat, he or she must be logged in using CometChat.login(username, apiKey) first.
It's important to note that logging in to CometChat is different from logging in to your app in general. CometChat doesn't handle user management. This authentication is only for allowing the user to access CometChat.
So in a real world example, we should authenticate the user as we would normally do (check if the email and the hashed password matches a record in the database, for example), then after that, we can log in that user to CometChat programmatically through CometChat.login.
As this is a demo app, we're going to make things simpler and use CometChat authentication as our app authentication as well.
Let's implement authentication by filling our login() method in Login.vue like this:
{% c-block language='javascript' %}
login () {
const apiKey = process.env.VUE_APP_COMETCHAT_API_KEY
this.loggingIn = true
CometChat.login(this.username, apiKey)
.then(() => {
this.loggingIn = false
this.$router.push({ name: 'chat' })
})
.catch(error => {
this.loggingIn = false
console.log('error', error)
})
}
{% c-block-end %}
login () {
const apiKey = process.env.VUE_APP_COMETCHAT_API_KEY
this.loggingIn = true
CometChat.login(this.username, apiKey)
.then(() => {
this.loggingIn = false
this.$router.push({ name: 'chat' })
})
.catch(error => {
this.loggingIn = false
console.log('error', error)
})
}
{% c-block-end %}
So we're using CometChat.login with the current value of the username input and our auth-only apiKey, which we stored in .env.local.
Now if the user was logged in successfully, we redirect him or her to the chat page using this.$router.push({ name: 'chat' }).
Note that you can test logging in using one of the following test users that CometChat provides us with: superhero1, superhero2, superhero3, superhero4, or superhero5.
Fetching the logged-in user's data
After the user is logged in, we should fetch his or her data so we can use them throughout the application.
We can do this using CometChat.getLoggedinUser. So, let's load the user's data when the chat page is created, which will be inside the created hook function in this case.
Open Chat.vue, and define the created function like this:
{% c-block language='javascript' %}
created () {
this.loadCurrentUser()
}
created () {
this.loadCurrentUser()
}
This means we have to implement the loadCurrentUser method.
methods: {
loadCurrentUser () {
CometChat.getLoggedinUser()
.then(user => {
this.loggedIn = true
Vue.prototype.$currentUser = {
uid: user.uid,
name: user.name,
avatar: user.avatar
}
})
.catch(error => {
this.$router.push({ name: 'login' })
console.log('error', error)
})
}
}
{% c-block-end %}
loadCurrentUser () {
CometChat.getLoggedinUser()
.then(user => {
this.loggedIn = true
Vue.prototype.$currentUser = {
uid: user.uid,
name: user.name,
avatar: user.avatar
}
})
.catch(error => {
this.$router.push({ name: 'login' })
console.log('error', error)
})
}
}
{% c-block-end %}
An important thing to note here is how we're storing the user's data. Instead of storing them inside a data property in Chat.vue, we are storing them inside all Vue instances. This will allow us to access the current user's data directly from any component using this.$currentUser without the needing to pass it as a prop.
Note that adding Vue instance properties is fine as long as you’re building a very small app or a demo. But for anything bigger than this, I would recommend using Vuex instead.
You can also see how we're setting loggedIn to true when data are fetched. You'll see why we need this later. But for now let's not forget to define it in the data list.
{% c-block language='javascript' %}
data () {
return {
loggedIn: false
}
}
{% c-block-end %}
data () {
return {
loggedIn: false
}
}
{% c-block-end %}
To complete this method, let's import CometChat and Vue at the top.
{% c-block language='javascript' %}
import { CometChat } from '@cometchat-pro/chat'
import Vue from 'vue'
{% c-block-end %}
import { CometChat } from '@cometchat-pro/chat'
import Vue from 'vue'
{% c-block-end %}
Update the Navbar with real data
Since we now have the logged-in user's data, let's update the name and the avatar in the nav bar to use them.
Go to src/components/Navbar.vue, and update the displayed name to be like this:
{% c-line %} Welcome <strong>{{ $currentUser.name }}</strong>{% c-line-end %}
And the avatar, like this:
{% c-block language='html' %}
<img
v-else
:src='$currentUser.avatar'
@click='logout'
>
{% c-block-end %}
<img
v-else
:src='$currentUser.avatar'
@click='logout'
>
{% c-block-end %}
If you view the chat page in the browser, you'll see that the navbar is broken. This is expected because we're assuming that the current user's data should be available before the page is loaded. But this isn't true in our case since we don't know when CometChat.getLoggedinUser() will be resolved.
To fix this, we should not display the page until the user's data is available. We can do this by adding this check to the root element of the chat page.
{% c-block language='html' %}
<template>
<div
v-if='loggedIn'
>
<navbar/>
<div>
<chat-sidebar/>
<chat-main/>
</div>
</div>
</template>
{% c-block-end %}
<template>
<div
v-if='loggedIn'
>
<navbar/>
<div>
<chat-sidebar/>
<chat-main/>
</div>
</div>
</template>
{% c-block-end %}
Now it should be clear why we needed to create that loggedIn property.
If you check the browser now, it should work as expected.
Loading contacts
Our next step is to load the contacts that we can chat with. Like loading the current user's data, we'll load them from the created() hook function.
{% c-block language='javascript' %}
created () {
this.loadCurrentUser()
this.loadContacts()
}
{% c-block-end %}
created () {
this.loadCurrentUser()
this.loadContacts()
}
{% c-block-end %}
Here's the implementation of loadContacts:
{% c-block language='javascript' %}
loadContacts () {
const usersRequest = new CometChat.UsersRequestBuilder().setLimit(5).build()
usersRequest.fetchNext()
.then(usersList => {
this.contacts = usersList.map(user => ({
uid: user.uid,
name: user.name,
avatar: user.avatar,
isOnline: user.status 'online'
}))
this.activeContactUid = this.contacts[0].uid
})
}
{% c-block-end %}
loadContacts () {
const usersRequest = new CometChat.UsersRequestBuilder().setLimit(5).build()
usersRequest.fetchNext()
.then(usersList => {
this.contacts = usersList.map(user => ({
uid: user.uid,
name: user.name,
avatar: user.avatar,
isOnline: user.status 'online'
}))
this.activeContactUid = this.contacts[0].uid
})
}
{% c-block-end %}
The returned list contains the first 5 users (excluding the logged-in user) that you have in your CometChat app — you can see them in the dashboard.
After the list is fetched, we store the contacts inside the contacts data property. We also set the first contact in the list as the active user that we're chatting with. We store that inside activeContactUid, as you can see above.
This means we have to add those properties inside our data list.
{% c-block language='javascript' %}
data () {
return {
loggedIn: false,
contacts: [],
activeContactUid: null
}
}
{% c-block-end %}
data () {
return {
loggedIn: false,
contacts: [],
activeContactUid: null
}
}
{% c-block-end %}
You can help FIFA Football Gaming wiki by.FIFA 12 (titled FIFA Soccer 12 in North America) is the 19th game in Electronic Arts' FIFA series of association football video games. It was developed by EA Canada, and published by Electronic Arts worldwide under the EA Sports label.
It was released in September 2011, on consoles for PlayStation 3, Xbox 360, Wii and PlayStation 2; on handhelds for PlayStation Portable, 3DS, Xperia Play, Android, and iOS; and on computers for Microsoft Windows and Mac OS X.
![Fifa 12 for mac os x 10 13 download Fifa 12 for mac os x 10 13 download](/uploads/1/1/8/6/118604366/140086225.jpg)
Showing contacts in the sidebar
Now we have the contacts fetched, let's display them in the sidebar. Before we open the sidebar component, let's pass the contacts list and the active contact id through its props. So, update <chat-sidebar/> in Chat.vue like this:
![Chat Chat](/uploads/1/1/8/6/118604366/940104935.jpg)
{% c-block %}
<chat-sidebar
:contacts='contacts'
:active-contact-id='activeContactUid'
@select-contact='setActiveContactUid'
/>
{% c-block-end %}
<chat-sidebar
:contacts='contacts'
:active-contact-id='activeContactUid'
@select-contact='setActiveContactUid'
/>
{% c-block-end %}
Now add the following into src/components/ChatSidebar.vue:
{% c-block language='html' %}
<template>
<div>
<div>
Contacts
</div>
<div>
<div
v-for='user in contacts'
:key='user.uid'
:class='{
'active': user.uid activeContactId,
'online': user.isOnline
}'
@click='$emit('select-contact', user.uid)'
>
<div>
<img
:src='user.avatar'
>
</div>
<span>
{{ user.name }}
</span>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
contacts: {
type: Array,
default: () => ([])
},
activeContactId: {
type: String,
default: null
}
}
}
</script>
<style scoped>
.header
font-family: 'Roboto', sans-serif
font-weight: normal
font-size: 15px
line-height: 18px
color: #2D313F
padding: 20px 25px
border-bottom: 1px solid #BDCCD7
.contacts-list
padding-bottom: 20px
.contact-item
height: 67px
display: flex
align-items: center
cursor: pointer
border-bottom: 1px solid rgba(189, 204, 215, 0.5)
padding-left: 15px
.contact-item.active
background: #1B47DB
.contact-item:not(.active):hover
background: #ECF0FE
.contact-avatar
width: 37px
height: 37px
border-radius: 50%
margin-right: 10px
.contact-avatar-wrapper
position: relative
display: flex
.contact-avatar-wrapper:after
content: '
display: block
width: 10px
height: 10px
border-radius: 50%
background: #BBBEBE
position: absolute
z-index: 9
right: 10px
bottom: 0
.contact-item.online .contact-avatar-wrapper:after
background: #1BDB72
.contact-name
font-family: 'Roboto', sans-serif
font-size: 14px
line-height: 16px
color: #2D313F
.contact-item:hover .contact-name,
.contact-item.active .contact-name
font-weight: 500
.contact-item.active .contact-name
color: #FFF
@media (max-width: 635px)
.header
padding: 20px 0
text-align: center
.contact-name
display: none
.contact-avatar
width: 40px
height: 40px
margin: 0
.contact-item
justify-content: center
padding: 0
</style>
{% c-block-end %}
<template>
<div>
<div>
Contacts
</div>
<div>
<div
v-for='user in contacts'
:key='user.uid'
:class='{
'active': user.uid activeContactId,
'online': user.isOnline
}'
@click='$emit('select-contact', user.uid)'
>
<div>
<img
:src='user.avatar'
>
</div>
<span>
{{ user.name }}
</span>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
contacts: {
type: Array,
default: () => ([])
},
activeContactId: {
type: String,
default: null
}
}
}
</script>
<style scoped>
.header
font-family: 'Roboto', sans-serif
font-weight: normal
font-size: 15px
line-height: 18px
color: #2D313F
padding: 20px 25px
border-bottom: 1px solid #BDCCD7
.contacts-list
padding-bottom: 20px
.contact-item
height: 67px
display: flex
align-items: center
cursor: pointer
border-bottom: 1px solid rgba(189, 204, 215, 0.5)
padding-left: 15px
.contact-item.active
background: #1B47DB
.contact-item:not(.active):hover
background: #ECF0FE
.contact-avatar
width: 37px
height: 37px
border-radius: 50%
margin-right: 10px
.contact-avatar-wrapper
position: relative
display: flex
.contact-avatar-wrapper:after
content: '
display: block
width: 10px
height: 10px
border-radius: 50%
background: #BBBEBE
position: absolute
z-index: 9
right: 10px
bottom: 0
.contact-item.online .contact-avatar-wrapper:after
background: #1BDB72
.contact-name
font-family: 'Roboto', sans-serif
font-size: 14px
line-height: 16px
color: #2D313F
.contact-item:hover .contact-name,
.contact-item.active .contact-name
font-weight: 500
.contact-item.active .contact-name
color: #FFF
@media (max-width: 635px)
.header
padding: 20px 0
text-align: center
.contact-name
display: none
.contact-avatar
width: 40px
height: 40px
margin: 0
.contact-item
justify-content: center
padding: 0
</style>
{% c-block-end %}
Cometchat Php Cracked Key
Here's what we're doing here:
- We're looping through the contacts list using v-for.
- We mark a contact as active (currently selected) by adding the .active class to it. A contact is active if its id is the same as activeContactId.
- If the contact item has .online class, we show that the user is currently online (green circle).
- If we click on a contact, we set it as active by emitting select-contact event with the contact's id.
We've already listened for the select-contact event but we haven't defined the handler for it yet. So in Chat.vue, add this method:
{% c-block language='javascript' %}
setActiveContactUid (uid) {
this.activeContactUid = uid
}
{% c-block-end %}
setActiveContactUid (uid) {
this.activeContactUid = uid
}
{% c-block-end %}
Now you should be able switch between active contacts.
If you check your browser now, you should see the contacts displayed like this:
Sending messages
Now let's focus on sending messages to the currently selected contact. All messaging related code should go to ChatMain.vue. But before we implement the sendMessage method, we need to pass the active contact object to the ChatMain component.
Currently, we only have the active contact id, not the contact object itself. So let's create a computed property that returns the currently selected contact object based on what's in activeContactUid.
Let's add that computed property in Chat.vue like this:
{% c-block language='javascript' %}
computed: {
activeContact () {
return this.contacts
.find(user => user.uid this.activeContactUid)
}
}
{% c-block-end %}
computed: {
activeContact () {
return this.contacts
.find(user => user.uid this.activeContactUid)
}
}
{% c-block-end %}
Now let's pass it to <chat-main/> component.
<chat-main :active-contact='activeContact'/>
And then accept it in ChatMain.vue.
Cometchat Php Cracked Version
{% c-block language='javascript' %}
props: {
activeContact: {
type: Object,
default: null
}
}
{% c-block-end %}
props: {
activeContact: {
type: Object,
default: null
}
}
{% c-block-end %}
![Cometchat php cracked download Cometchat php cracked download](https://vignette3.wikia.nocookie.net/logopedia/images/5/50/Comet_TV_logo.png/revision/latest?cb=20161104114253)
Now we have the active contact available, let's implement the sendMessage method in ChatMain.vue.
{% c-block language='javascript' %}
sendMessage () {
this.sendingMessage = true
const textMessage = new CometChat.TextMessage(
this.activeContact.uid,
this.messageText,
CometChat.MESSAGE_TYPE.TEXT,
CometChat.RECEIVER_TYPE.USER
)
CometChat.sendMessage(textMessage)
.then(message => {
this.sendingMessage = false
this.messageText = '
this.messages.push(message)
this.$nextTick(() => {
this.scrollToBottom()
})
})
.catch(error => {
console.log(error)
this.sendingMessage = false
})
}
{% c-block-end %}
sendMessage () {
this.sendingMessage = true
const textMessage = new CometChat.TextMessage(
this.activeContact.uid,
this.messageText,
CometChat.MESSAGE_TYPE.TEXT,
CometChat.RECEIVER_TYPE.USER
)
CometChat.sendMessage(textMessage)
.then(message => {
this.sendingMessage = false
this.messageText = '
this.messages.push(message)
this.$nextTick(() => {
this.scrollToBottom()
})
})
.catch(error => {
console.log(error)
this.sendingMessage = false
})
}
{% c-block-end %}
To send a message in CometChat to a specific contact, we have to create a new text message using new CometChat.TextMessage(), and in that message we should specify the contact's id we want to send the message to, the message text, the message type, and the receiver type.
After we have that message, we send it through CometChat.sendMessage(message).
Note that after the message is sent, we add it to the local messages array so it gets displayed immediately.
Before you test this, let's define the scrollToBottom method.
{% c-block language='javascript' %}
scrollToBottom () {
const messagesContainer = this.$refs.messagesContainer
if (messagesContainer) {
messagesContainer.$el.scrollTo(0, messagesContainer.$el.scrollHeight + 30)
}
}
{% c-block-end %}
scrollToBottom () {
const messagesContainer = this.$refs.messagesContainer
if (messagesContainer) {
messagesContainer.$el.scrollTo(0, messagesContainer.$el.scrollHeight + 30)
}
}
{% c-block-end %}
If you try to send a message, you won't see it displayed on the main area because we haven't implemented ChatMessages.vue yet.
So open src/components/ChatMessages.vue, and add this:
{% c-block language='html' %}
<template>
<div>
<div
v-for='message in messages'
:key='message.id'
:class='[message.sender.uid $currentUser.uid ? 'outgoing' : 'incoming']'
>
<img
:src='message.sender.avatar'
>
<div>
{{ message.data.text }}
</div>
</div>
</div>
</template>
<script>
export default {
props: {
messages: {
type: Array,
default: () => ([])
}
}
}
</script>
<style scoped>
.chat-messages
overflow: auto
flex: 1
padding: 20px 10px
.message-item
display: flex
align-items: flex-end
margin-bottom: 15px
.message-item.outgoing
flex-direction: row-reverse
.avatar
width: 40px
height: 40px
border-radius: 50%
overflow: hidden
margin: 0 10px
.message-content
position: relative
background: #FFF
border-radius: 4px
box-shadow: 0px 1px 2px #BDCCD7
padding: 10px
font-family: 'Roboto', sans-serif
font-weight: normal
font-size: 13px
line-height: 21px
color: #2D313F
mix-blend-mode: normal
opacity: 0.8
max-width: 280px
min-width: 100px
margin-left: 10px
.message-item.outgoing .message-content
margin-left: 0
margin-right: 10px
.message-item.outgoing .message-content
background: #1B47DB
color: #FFF
opacity: 1
.message-content:after
content: '
position: absolute
top: calc(100% - 20px)
width: 0
height: 0
border: 12px solid transparent
margin-top: -12px
z-index: 1
transform: skew(0, 30deg)
.message-item.incoming .message-content:after
left: 0
border-right-color: #ffffff
border-left: 0
margin-left: -10px
.message-item.outgoing .message-content:after
right: 0
border-left-color: #1B47DB
border-right: 0
margin-right: -11px
.message-content:before
content: '
position: absolute
z-index: 0
top: calc(100% - 20px)
width: 0
height: 0
border: 10px solid transparent
filter: blur(1px)
margin-top: -10px
transform: skew(0, 30deg)
.message-item.incoming .message-content:before
left: 0
border-right-color: #ffffff
border-left: 0
margin-left: -10px
border-right-color: rgba(0, 0, 0, 0.2)
.message-item.outgoing .message-content:before
right: 0
border-left-color: #1B47DB
border-right: 0
margin-right: -11px
border-right-color: rgba(0, 0, 0, 0.2)
@media (max-width: 635px)
.avatar
display: none
.message-content:before,
.message-content:after
display: none
.message-item
width: 100%
.message-item.outgoing .message-content,
.message-item.incoming .message-content
margin-left: 0
margin-right: 0
width: 100%
max-width: 100%
</style>
{% c-block-end %}
<template>
<div>
<div
v-for='message in messages'
:key='message.id'
:class='[message.sender.uid $currentUser.uid ? 'outgoing' : 'incoming']'
>
<img
:src='message.sender.avatar'
>
<div>
{{ message.data.text }}
</div>
</div>
</div>
</template>
<script>
export default {
props: {
messages: {
type: Array,
default: () => ([])
}
}
}
</script>
<style scoped>
.chat-messages
overflow: auto
flex: 1
padding: 20px 10px
.message-item
display: flex
align-items: flex-end
margin-bottom: 15px
.message-item.outgoing
flex-direction: row-reverse
.avatar
width: 40px
height: 40px
border-radius: 50%
overflow: hidden
margin: 0 10px
.message-content
position: relative
background: #FFF
border-radius: 4px
box-shadow: 0px 1px 2px #BDCCD7
padding: 10px
font-family: 'Roboto', sans-serif
font-weight: normal
font-size: 13px
line-height: 21px
color: #2D313F
mix-blend-mode: normal
opacity: 0.8
max-width: 280px
min-width: 100px
margin-left: 10px
.message-item.outgoing .message-content
margin-left: 0
margin-right: 10px
.message-item.outgoing .message-content
background: #1B47DB
color: #FFF
opacity: 1
.message-content:after
content: '
position: absolute
top: calc(100% - 20px)
width: 0
height: 0
border: 12px solid transparent
margin-top: -12px
z-index: 1
transform: skew(0, 30deg)
.message-item.incoming .message-content:after
left: 0
border-right-color: #ffffff
border-left: 0
margin-left: -10px
.message-item.outgoing .message-content:after
right: 0
border-left-color: #1B47DB
border-right: 0
margin-right: -11px
.message-content:before
content: '
position: absolute
z-index: 0
top: calc(100% - 20px)
width: 0
height: 0
border: 10px solid transparent
filter: blur(1px)
margin-top: -10px
transform: skew(0, 30deg)
.message-item.incoming .message-content:before
left: 0
border-right-color: #ffffff
border-left: 0
margin-left: -10px
border-right-color: rgba(0, 0, 0, 0.2)
.message-item.outgoing .message-content:before
right: 0
border-left-color: #1B47DB
border-right: 0
margin-right: -11px
border-right-color: rgba(0, 0, 0, 0.2)
@media (max-width: 635px)
.avatar
display: none
.message-content:before,
.message-content:after
display: none
.message-item
width: 100%
.message-item.outgoing .message-content,
.message-item.incoming .message-content
margin-left: 0
margin-right: 0
width: 100%
max-width: 100%
</style>
{% c-block-end %}
To distinguish between the sent and received messages, we add either an .outgoing or .incoming class to the message item. Outgoing messages are the messages with the same sender's id as the logged-in user. The rest should be easy to understand.
Now sending messages should work as expected.
If you reload the browser, however, you should see that your messages are gone. This is expected since we don't load previous messages on page load. This means the messages you send via CometChat are stored for you. So you don’t have to handle message persistence by yourself — how cool is CometChat?
Loading previous messages
Go to ChatMain.vue, and add the following method:
{% c-block language='javascript' %}
loadMessages () {
this.loadingMessages = true
const messagesRequest = new CometChat.MessagesRequestBuilder()
.setUID(this.activeContact.uid)
.build()
messagesRequest.fetchPrevious()
.then(messages => {
this.messages = messages
this.loadingMessages = false
this.$nextTick(() => {
this.scrollToBottom()
})
})
.catch(error => {
console.log('error', error)
this.loadingMessages = false
})
}
{% c-block-end %}
loadMessages () {
this.loadingMessages = true
const messagesRequest = new CometChat.MessagesRequestBuilder()
.setUID(this.activeContact.uid)
.build()
messagesRequest.fetchPrevious()
.then(messages => {
this.messages = messages
this.loadingMessages = false
this.$nextTick(() => {
this.scrollToBottom()
})
})
.catch(error => {
console.log('error', error)
this.loadingMessages = false
})
}
{% c-block-end %}
We should call this method every time we switch to a new contact. So let's call it from a watcher, like this:
{% c-block language='javascript' %}
watch: {
'activeContact.uid': {
immediate: true,
handler () {
this.loadMessages()
}
}
}
{% c-block-end %}
watch: {
'activeContact.uid': {
immediate: true,
handler () {
this.loadMessages()
}
}
}
{% c-block-end %}
Note how we're using immediate: true so it gets invoked when the component is mounted. We need this to load messages for the first contact that gets selected automatically when contacts are loaded.
Listening for new messages
Now what would happen if you logged in with another user from another browser and tried to send a message?
If you tried that, you wouldn't see the message until you reload the browser. This means we need to listen for new messages in realtime.
We can achieve that very easily with CometChat by adding this code to the mounted hook function in ChatMain.vue:
{% c-block language='javascript' %}
mounted () {
const listenerID = 'UNIQUE_LISTENER_ID'
CometChat.addMessageListener(
listenerID,
new CometChat.MessageListener({
onTextMessageReceived: message => {
if (message.sender.uid this.activeContact.uid) {
this.messages.push(message)
}
this.$nextTick(() => {
this.scrollToBottom()
})
}
})
)
}
{% c-block-end %}
mounted () {
const listenerID = 'UNIQUE_LISTENER_ID'
CometChat.addMessageListener(
listenerID,
new CometChat.MessageListener({
onTextMessageReceived: message => {
if (message.sender.uid this.activeContact.uid) {
this.messages.push(message)
}
this.$nextTick(() => {
this.scrollToBottom()
})
}
})
)
}
{% c-block-end %}
So we're listening for new messages using CometChat message listener, and we're showing messages only from the contact that's currently selected.
Showing current user statuses in realtime
You might already have noticed that the current statuses of the contacts aren’t updated in realtime — you have to reload the browser to see the current statuses.
Like with listening to messages, we can listen to user statuses using CometChat.addUserListener. Let's add this to the created hook function in Chat.vue.
{% c-block language='javascript' %}
created () {
this.loadCurrentUser()
this.loadContacts()
const listenerID = 'UNIQUE_LISTENER_ID'
CometChat.addUserListener(
listenerID,
new CometChat.UserListener({
onUserOnline: onlineUser => {
const index = this.contacts.findIndex(user => user.uid onlineUser.uid)
this.$set(this.contacts, index, { .this.contacts[index], isOnline: true })
},
onUserOffline: offlineUser => {
const index = this.contacts.findIndex(user => user.uid offlineUser.uid)
this.$set(this.contacts, index, { .this.contacts[index], isOnline: false })
}
})
)
}
{% c-block-end %}
created () {
this.loadCurrentUser()
this.loadContacts()
const listenerID = 'UNIQUE_LISTENER_ID'
CometChat.addUserListener(
listenerID,
new CometChat.UserListener({
onUserOnline: onlineUser => {
const index = this.contacts.findIndex(user => user.uid onlineUser.uid)
this.$set(this.contacts, index, { .this.contacts[index], isOnline: true })
},
onUserOffline: offlineUser => {
const index = this.contacts.findIndex(user => user.uid offlineUser.uid)
this.$set(this.contacts, index, { .this.contacts[index], isOnline: false })
}
})
)
}
{% c-block-end %}
Cometchat Php Cracked Full
So each time a user gets online or offline, we're notified in onUserOnline or onUserOffline callbacks with the user's data. We use the user's id to update the status of the matching user from the contacts list.
Showing the currently selected contact name
If you take a look at the header in the chat's main area, you'll see the text 'Active Contact Name' regardless of the currently selected contact. Instead, we should display the name of that contact.
This can be easily done by replacing 'Active Contact Name' with {{ activeContact.name }} in ChatMain.vue.
Fixing the browser's console error
If you check your browser now, you would see an error telling you that activeContact is null in ChatMain.vue. That's expected since we display the chat page before the contacts are loaded.
We can fix this quickly by including activeContact to the root element's check in the chat page.
{% c-block %}
<div
v-if='loggedIn && activeContact'
>
{% c-block-end %}
<div
v-if='loggedIn && activeContact'
>
{% c-block-end %}
Implementing logging out
Our last step in this tutorial is to implement the logout method in Navbar.vue.
{% c-block %}
logout () {
this.loggingOut = true
CometChat.logout()
.then(() => {
this.loggingOut = false
this.$router.push({ name: 'login' })
})
.catch(error => {
this.loggingOut = false
console.log('error', error)
})
}
{% c-block-end %}
logout () {
this.loggingOut = true
CometChat.logout()
.then(() => {
this.loggingOut = false
this.$router.push({ name: 'login' })
})
.catch(error => {
this.loggingOut = false
console.log('error', error)
})
}
{% c-block-end %}
So logging out is as simple as calling CometChat.logout(), and then redirecting to the login page.
Conclusion
It took time to build this app, but it's mostly because we made it look like a real-world app. CometChat was the easy part as you can see.
So we can conclude the flow of this chat app (or any chat app) like this: keep track of the logged-in user and his or her contacts, specify the contact when sending a message, load any previous messages between participants, and listen for new messages in realtime.
Thanks for reading! By the way, I’m writing a book on how to build a complete single-page application from scratch using Vue. Check outthe book’s landing pageif you’re interested in learning more about what the book will cover.
Download Free PHP Live Chat Pro PHP Script 1.0 – PHP Scripts – CodeCanyon | PHP Reside Chat Professional v1.zero comes with an Straightforward set up, Operator initiated talks, Geolocation, Map with chatting guests, Contact type fallback, Desktop Notifications, Photos & movies within the chat field, File sharing, Sound notifications (10 predefined sounds to select from), Preliminary „welcome” message after visitor logs in, Clear and trendy look, Cell assist (responsive visitor widget), Top quality set of avatar pictures and way more…
Notice: We need to enhance our web site’s efficiency and usefulness in order that you could possibly actually get a terrific profit from our web site. Simply extra one factor is that We publish all content material just for testing goal not for business use, so in case you have cash then we strongly advocate you to purchase the require plugin/theme and many others from unique developer’s web site. Use any theme OR plugin by yourself threat!
Demo
https://codecanyon.net/item/php-live-chat-pro/19932933
Download Links
Kontakt 6 sale. http://www65.zippyshare.com/v/CYQEl1Bw/file.html
https://clicknupload.link/f6zty2cwvr77
http://www.solidfiles.com/d/33rXyjRqDR6RA
http://uptobox.com/g9kog394vnf3
https://userscloud.com/eh6b4a6vvzva
https://www.bigfile.to/file/j8TFMCdjQENa/PHP_Live_Chat_Pro_[v1.0].rar
http://www.datafilehost.com/d/505ff79d
https://tusfiles.net/4bdoywht5ex2
http://uppit.com/jw9kkybe11z7
https://dailyuploads.net/satawu2vo1hu
http://uploadrocket.net/wi86z4b5pmsz/PHP_Live_Chat_Pro__v1.0_.rar.html
http://www.mirrorcreator.com/files/ECSKVK6T/PHP_Live_Chat_Pro_[v1.0].rar_links
https://clicknupload.link/f6zty2cwvr77
http://www.solidfiles.com/d/33rXyjRqDR6RA
http://uptobox.com/g9kog394vnf3
https://userscloud.com/eh6b4a6vvzva
https://www.bigfile.to/file/j8TFMCdjQENa/PHP_Live_Chat_Pro_[v1.0].rar
http://www.datafilehost.com/d/505ff79d
https://tusfiles.net/4bdoywht5ex2
http://uppit.com/jw9kkybe11z7
https://dailyuploads.net/satawu2vo1hu
http://uploadrocket.net/wi86z4b5pmsz/PHP_Live_Chat_Pro__v1.0_.rar.html
http://www.mirrorcreator.com/files/ECSKVK6T/PHP_Live_Chat_Pro_[v1.0].rar_links