1

I have created a messenger system with vue and a Laravel backend and I want to group the messages that are mine (Jim, the person I'm currently signed in as) on the right in blue and Debbie (The user I'm talking to) on the left in yellow using flexbox. Like Facebook or twitter:


enter image description here


Mock JSON Output

{
    "0": {
        "name": "Debbie",
        "message": "Good, Thinks for asking."
    },
    "1": {
        "name": "Jim",
        "message": "I'm good, how are you?"
    },
    "2": {
        "name": "Debbie",
        "message": "How are you?"
    },
    "3": {
        "name": "Jim",
        "message": "Hi Debbie"
    },
    "4": {
        "name": "Debbie",
        "message": "Hi Jim"
    }
}

What would I have to send through my JSON API to identify myself from any other user and thier messages? Or is there a way I could do that without having to do it without having to alter the JSON output?

How would I implement this into this messenger system that I've built using flexbox? The main component that I'm working with is the conversation-messages component:

Vue.component('conversation-messages',{
      template: '#conversation-messages',
      props: ['conversationId'],
      data: function() {
        return {
          messages: [],
          url: ''
        }
      },
      mounted() {
        console.log("message mounted")
        this.getOldMessages(this.conversationId);
      },
});

Here's a link to this question being answered only using css.

From the CSS link on how to create a chat bubble system like FB

HTML Structure Example From Link Using Floats Not Flexbox

<ul>
 <li class="him">By Other User</li>
 <li class="me">By this User, first message</li>
 <li class="me">By this User, secondmessage</li>
 <li class="me">By this User, third message</li>
 <li class="me">By this User, fourth message</li>
</ul>

CSS Example From Answer In Link

ul{
  list-style: none;
  margin: 0;
  padding: 0;
}

ul li{
  display:inline-block;
  clear: both;
  padding: 20px;
  border-radius: 30px;
  margin-bottom: 2px;
  font-family: Helvetica, Arial, sans-serif;
}

.him{
  background: #eee;
  float: left;
}

.me{
  float: right;
  background: #0084ff;
  color: #fff;
}

.him + .me{
  border-bottom-right-radius: 5px;
}

.me + .me{
  border-top-right-radius: 5px;
  border-bottom-right-radius: 5px;
}

.me:last-of-type {
  border-bottom-right-radius: 30px;
}
Boussadjra Brahim
  • 82,684
  • 19
  • 144
  • 164
user3325126
  • 1,284
  • 4
  • 15
  • 36

1 Answers1

1

You could assign a class named msgs to the div that wraps your messages, that class is defined by the following rules :

tag:

 <div v-for="message in messages" class="msgs">

style :

 .msgs{
      display:flex;
      flex-direction:column;
      align-items:center;
      justify-content:space-between;
   }

for each message you should detect if it's yours. if it's, align it at the end else align it at the start by binding classes and using v-if and v-else like :

    <div class="p-4 border-b"  v-if='message.name=="Jim"' :class="{me:message.name='Jim'}">
      <p>{{message.message}}</p>
    </div>
    <div class="p-4 border-b" v-else :class="{him:true}">
      <p>{{message.message}}</p>
    </div>    

instead of message.name=="Jim" you can use a data object property called itSMe which detect the connected user messages

Vue.component('conversations',{
      template: '#conversations',
      data: function(){
        return{
          showConversation: false,
          conversationId: null
        }
      },

      methods: {
         getConversation(conversation_id){
           this.conversationId = conversation_id
           this.showConversation = true
           console.log(this.conversationId)
        }
      },
});

Vue.component('converstations-list',{
      template: '#conversations-list',
      data: function() {
        return {
          conversations: [
            {id: 1, name: "Conversation with Debbie"},
            {id: 2, name: "Conversation with Steve"},
            {id: 3, name: "Conversation with Martin"},
          ]
        }
      },

      methods: {
        getConversation(conversation_id){
          this.$emit('open-conversation', conversation_id);
        }
      },
});

Vue.component('conversation-messages',{
      template: '#conversation-messages',
      props: ['conversationId'],
      data: function() {
        return {
          messages: [],
          url: ''
        }
      },
      mounted() {
        console.log("message mounted")
        this.getOldMessages(this.conversationId);
      },
      methods: {
        getOldMessages(conversation_id){
              
              //This will be replaced with backend conversation_id routes
              if(conversation_id === 1){
                this.url = 'https://codepen.io/Corbin/pen/YJppoL.js';
              }else if(conversation_id === 2) {
                this.url = 'https://codepen.io/Corbin/pen/EdNZjX.js';
              }else if(conversation_id === 3) {
                this.url = 'https://codepen.io/Corbin/pen/LgbxGd.js';
              }
                
              setTimeout(function() {
              axios({
                  method: 'get',
                  url: this.url,
              }).then(function(response) {
                  //console.log(response.data);

                  this.messages = response.data;
              }.bind(this))
              .catch(function(error) {
                  
              });
          }.bind(this))
      },
      }
});

new Vue({
  el: '#app',
});
.border-b{
padding:0 10px;
}
.msgs{
  
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:space-between;
}
.me{
  align-self:flex-end;
  background: #0084ff;
  color: #fff;
}

.him{
  align-self:flex-start;
  background: #eee;
  float: left;
  border-radius: 20px 20px 20px 0;
}




.me {
  border-radius: 20px 0px 20px 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
      rel="stylesheet">

<!-- Conversations -->
<script type="x/template" id="conversations">
  <div>
    <div class="flex w-full border-b">
       <button v-show="showConversation" class="pl-4 font-bold rounded" @click="showConversation = false" ><i class="material-icons">
        arrow_back_ios
       </i></button>
       <h1 class="py-4  text-center w-full" v-if="showConversation == false">All Conversations</h1>
       <h1 class="py-4 text-center w-full" v-if="showConversation">Conversation With</h1>
    </div>
    <converstations-list v-if="showConversation == false" v-on:open-conversation="getConversation($event)"></converstations-list>
    <conversation-messages :conversation-id="conversationId" v-if="showConversation"></conversation-messages>
  </div>
</script>

<!--Conversations List -->
<script type="x/template" id="conversations-list">
  <div>
    <div v-for="conversation in conversations">
      <h3 @click="getConversation( conversation.id)" class="cursor-pointer border-b p-4 hover:bg-blue">{{conversation.name}}</h3>
    </div>
  </div>
</script>

<!--Conversations Messages -->
<script type="x/template" id="conversation-messages">
  <div> 
      <div v-for="message in messages" class="msgs">
        <div class="p-4 border-b"  v-if='message.name=="Jim"' :class="{me:message.name='Jim'}">
        
          <p>{{message.message}}</p>
        </div>
     <div class="p-4 border-b" v-else :class="{him:true}">
         
          <p>{{message.message}}</p>
        </div>
      </div>
  </div>
</script>

<div id="app">

  <conversations></conversations>

</div>
Boussadjra Brahim
  • 82,684
  • 19
  • 144
  • 164