Add Media Uploads to a Laravel Vue.js Chat App Using Twilio Programmable Chat

February 11, 2020
Written by
Chimezie Enyinnaya
Contributor
Opinions expressed by Twilio contributors are their own

Add Media Uploads to a Laravel-Vue.js Chat App

In my last tutorial, I showed you how to add chat to a Laravel app using Twilio Chat. In this tutorial, I’ll be showing you how to enhance the app by adding media support to it using Twilio Programmable Chat. That is, allowing users to send media files as message.

Prerequisites

In order to follow this tutorial, you will need the following:

Getting Twilio Credentials

Login to your Twilio dashboard and copy both your ACCOUNT SID and AUTH TOKEN.

Twilio Account Credentials

Before you can start using the Twilio Programmable Chat, you need to first create a chat service:

Twilio Programmable Chat Dashboard

Take note of your SERVICE SID.

Twilio Programmable Chat Configuration

Lastly, you need to create an API key:

Twilio New API Key

Also, take note of both your API SECRET and API SID.

Getting Started

To make sure we are all on the same page, let’s clone the chat app that was built in my last tutorial:

$ git clone https://github.com/ammezie/laravel-twilio-chat.git

Once that’s done, we need to install the project’s dependencies:

$ cd laravel-twilio-chat
$ composer install
$ npm install

Next, rename .env.example to .env and run the command below to generate an app key:

$ php artisan key:generate

You will need to set up a database. We’ll be making use of SQLite for our database. Update the .env file as below:

// .env

DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database/database.sqlite

Create the database.sqlite file:

$ touch database/database.sqlite

Now, run the migration:

$ php artisan migrate

Next, add your Twilio credentials to the .env file:

// .env

TWILIO_AUTH_SID=YOUR_TWILIO_AUTH_SID
TWILIO_AUTH_TOKEN=YOUR_TWILIO_AUTH_TOKEN
TWILIO_SERVICE_SID=YOUR_TWILIO_CHAT_SERVICE_SID
TWILIO_API_SECRET=YOUR_TWILIO_API_SECRET
TWILIO_API_SID=YOUR_TWILIO_API_SID

Adding the Upload Button

Let’s start by adding an upload button in addition to the message input field. This will allow us to select the file we want to send as a message.

Within the <template> section of ChatComponent.vue, update the card footer as below:

// resources/js/components/ChatComponent.vue

<div class="card-footer">
  <div class="form-row">
    <div class="form-group col-md-8">
      <input
        type="text"
        v-model="newMessage"
        class="form-control"
        placeholder="Type your message..."
        @keyup.enter="sendMessage"
      />
    </div>
    <div class="form-group col-md-4">
      <input type="file" accept="image/*" @change="sendMediaMessage">
    </div>
  </div>
</div>

We are restricting the media type to only images. Once the file has been selected we call a sendMediaMessage method, which will handle sending the message.

Message upload bar

Implementing the Upload Functionality

Let’s create the sendMediaMessage method we referred to earlier. Still inside ChatComponent.vue, add the following code inside the methods object in the <script> section:

// resources/js/components/ChatComponent.vue

sendMediaMessage({ target }) {
  const formData = new FormData();
  formData.append('file', target.files[0]);


  this.channel.sendMessage(formData);
  target.value = "";
},

There are a couple of ways to get media files across to the Twilio Chat such as FormData, String, or Node.js Buffer. For the purpose of this tutorial, we’ll be using FormData. The sendMediaMessage method accepts the input element it is being called on. Using object destructing, we extract the target from the input element. Then we create a new instance of FormData and append the selected file to it. Just as we did when sending text messages, we make use of the sendMessage method of the channel, but this time instead of passing body for the content, we pass the FormData (which now holds the selected file) for the message. Lastly, we clear out the file input.

Displaying Media Messages

As it stands there’s no way to see media messages that were sent. Let’s fix that. Twilio Chat supports two types of message: text and media. So at the point of displaying chat messages, we need to check the message type and display it appropriately. Because of the way Twilio Chat handles media, we can’t simply do just that. When we fetch a media message, we don’t get the media itself, we only get the metadata (type, filename, size, etc.) of the media. To get the media, we need to make a separate request, which returns a temporary URL of the media.

We want our chat app to display messages regardless of their type, directly in the chat window. To achieve this, we need to update the fetchMessages method as below:

// resources/js/components/ChatComponent.vue

async fetchMessages() {
  const messages = (await this.channel.getMessages()).items;


  for (const message of messages) {
    this.pushToArray(message)
  }
},

Instead of making use of the fetched messages directly, we’ll iterate over them and populate the messages array data property. We are using a pushToArray method which we are yet to create. Let’s create it.


// resources/js/components/ChatComponent.vue

async pushToArray (message) {
  if (message.type === 'media') {
    const mediaUrl = await message.media.getContentUrl()


    this.messages.push({
      type: message.type,
      author: message.author,
      filename: message.media.filename,
      mediaUrl
    })
  } else {
    this.messages.push({
      type: message.type,
      author: message.author,
      body: message.body,
    })
  }
}

We check the message type. If it’s media, we fetch a URL for it. Then we create a new  message object containing the message’s type, author, media filename, and media URL. Then we push the message object to the messages array data property. Otherwise (that is, type is text), we push a new message object containing the message’s type, author, and body to the messages array data property.

Before we wrap up, we need to do something similar for when a new message is sent. Update the code where we are listening for the messageAdded event inside the initializeClient method as below:

// resources/js/components/ChatComponent.vue

this.channel.on("messageAdded", message => {
  this.pushToArray(message)
});

Finally, let’s update the template to display the messages. Replace the {{ message.body }} line with the following code:

// resources/js/components/ChatComponent.vue

<template v-if="message.type === 'media'">
  <img class="img-thumbnail" :src="message.mediaUrl" :alt="message.filename" width="150px">
</template>
<template v-else>
  {{ message.body }}
</template>

If the message is media, we display a thumbnail of the media. Otherwise, we simply display the body of the message.

Testing Our Application

Let’s test what we’ve been building so far. First, let’s make sure our app is running:

$ php artisan serve

Then compile the JavaScript:

$ npm run dev

Laravel Chat Window

Conclusion

In this tutorial, we learned how to add media support to a Laravel chat application using Twilio Programmable Chat. Though this tutorial showed how to upload images, you can as well extend it to support other media types. To learn more about Twilio Programmable Chat, what you can do with it as well as some best practices when working with media, check out the docs.

You can find the complete source for this tutorial on GitHub.

Chimezie Enyinnaya is a software developer and instructor. You can learn more about him via:

Additional Reading

If you would like to learn more about building chat-based products with Twilio, check out the following documentation: