Messenger UI

A messenger UI with a simple chatbot to demonstrate its functionality.

by Perry Kaufman

HTML

<section id="messager" class="messager">
    <div id="messager-screen" class="messager-screen">

    </div>
  <form id="messager-form" class="messager-form">
    <input class="messager-input" type="text" />
    <button class="messager-button" type="submit">
      send
    </button>
  </form>
</section>

CSS

@import url('https://fonts.googleapis.com/css?family=Open+Sans|Source+Sans+Pro');

html,
body {
  box-sizing: border-box;
  font-family: 'Open Sans', sans-serif;
  font-size: 20px;
  height: 100%;
  padding: 0;
  margin: 0;
  width: 100%;
}

* {
  box-sizing: inherit;
}

.messager {
  display: flex;
  height: 100%;
  flex-flow: column nowrap;
  width: 100%;
}

.messager-screen {
  background-color: white;
  display: flex;
  flex: 1;
  flex-flow: column nowrap;
  padding: 10px;
  overflow-y: scroll;
  width: 100%;
}

.message {
  display: flex;
  flex-flow: column nowrap;
  flex-shrink: 0;
  margin-bottom: 5px;
  max-width: 70%;
}

.message.send {
  align-items: flex-end;
  align-self: flex-end;
}

.message.receive {
  align-items: flex-start;
  align-self: flex-start;
}

.message-content {
  border: none;
  border-radius: 10px;
  display: inline-block;
  font-size: 1em;
  max-width: 100%;
  padding: 5px 8px;
  overflow-wrap: break-word;
  white-space: normal;
}

.receive>.message-content {
  background-color: lightgray;
  border-bottom-left-radius: 0;
}

.send>.message-content {
  background-color: blue;
  border-bottom-right-radius: 0;
  color: white;
}

.message-time {
  color: rgb(0, 0, 0, 0.75);
  display: inline-block;
  font-size: .6em;
  margin-top: 3px;
}

.messager-form {
  background-color: lightgray;
  display: flex;
  flex: 0 0 auto;
  padding: 10px;
  width: 100%;
}

.messager-input {
  border: 2px solid gray;
  border-radius: 10px;
  flex: 1;
  font-size: inherit;
  margin-right: 2px;
  min-width: 0;
  padding: 2px 10px;
  transition: all .2s ease-in-out;
}

.messager-input:focus {
  border-color: blue;
  outline: 0;
}

.messager-button {
  background-color: blue;
  border: none;
  border-radius: 10px;
  box-shadow: 2px 2px 3px rgb(0, 0, 0, 0.66);
  color: white;
  flex: none;
  font-size: inherit;
  padding: 2px 10px;
  transition: all .25s ease-in-out, transform .1s ease-in-out;
}

.messager-button:focus,
.messager-button:hover {
 ...

JavaScript

const formatDate = function(date) {
  let minutes = date.getMinutes();
  let hours = date.getHours();
  let day = date.getDate();
  let month = date.getMonth() + 1;
  let year = date.getFullYear();

  let output = '';
  if (hours === 0) output += '12';
  else if (hours <= 12) output += String(hours);
  else if (hours <= 23) output += String(hours - 12);
  output += ':';
  if (minutes < 10) output += '0';
  output += String(minutes);

  if (hours < 12) output += ' AM, '
  else output += ' PM, '

  output += String(month) + '/' + String(day) + '/' + String(year);

  return output;
}

class Message {
  constructor(content, date, type) {
    this.content = content.trim();
    if (this.content === '') throw new Error('Message cannot be empty.');
    this.date = date;
    this.type = type;
  }
}

class ChatBot {
  constructor(client) {
    this.client = client;
    this.client.setListener((message) => {
      this._respondToMessage(message);
    });
    this._postGreeting();
  }
  _postGreeting() {
    let greeting = 'Hello! I am a chatbot! I will repeat anything you say!';
    this.client.postMessage(new Message(greeting, new Date(), 'receive'));
  }
  _respondToMessage(message) {
    let length = message.content.length;
    setTimeout(() => {
      this.client.postMessage(new Message(message.content, new Date(), 'receive'));
    }, 250 + 25 * length);
  }
}

class MessagerUI {
  constructor() {
    this._listener = null;
    let messager = document.querySelector('#messager');
    if (!messager) {
      throw new Error('Messager incorrectly formatted.');
    }
    this._screen = messager.querySelector('#messager-screen')
    if (!this._screen) {
      throw new Error('Messager incorrectly formatted.');
    }
    this._form = messager.querySelector('#messager-form')
    if (!this._form) {
      throw new Error('Messager incorrectly formatted.');
    }
    this._input = this._form.querySelector('input');
    if (!this._input) {
      throw new Error('Messager...