Skip to content

Commit

Permalink
ft(Chat): user can chat on barefoot nomad
Browse files Browse the repository at this point in the history
[Finishes #169817577]
  • Loading branch information
victor-abz committed Mar 13, 2020
1 parent b44d14e commit 25c3f10
Show file tree
Hide file tree
Showing 21 changed files with 6,062 additions and 88 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
src/public/chat/js/
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"find-up": "^4.1.0",
"istanbul-lib-instrument": "^3.3.0",
"jsonwebtoken": "^8.5.1",
"moment": "^2.24.0",
"morgan": "^1.9.1",
"node-mocks-http": "^1.8.1",
"passport": "^0.4.1",
Expand Down
1 change: 1 addition & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ app.use(express.urlencoded({ extended: false }));
app.use(express.json());
app.use(passport.initialize());


// running all event listeners
NotificationListeners();

Expand Down
77 changes: 77 additions & 0 deletions src/controllers/chat.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Op } from 'sequelize';
import { users, io } from '../helpers/eventEmmiters/socket';
import ResponseService from '../services/response.service';
import ChatService from '../services/chat.service';
import UserService from '../services/user.service';

/** Class representing comments controller. */
class ChatController {
/**
* Save a new message.
* @param {object} req request
* @param {object} res response
* @returns {object} response object
*/
static async saveMessage(req, res) {
const newMessage = await ChatService.saveMessage({ ...req.body, sender: req.userData.email });
ChatService.sendMessage(req.body.receiver, req.userData.email, req.body.message);

ResponseService.setSuccess(200, 'message added successfully', newMessage);
ResponseService.send(res);
}

/**
* gets all messages for a user
* @param {object} req request
* @param {object} res response
* @returns {object} response
*/
static async getMessages(req, res) {
const message = await ChatService.getMessages({
[Op.or]: [{ receiver: req.userData.email }, { sender: req.userData.email }]
});

ResponseService.setSuccess(200, 'messages fetched successfully', message);
ResponseService.send(res);
}

/**
* gets all messages for a user
* @param {object} req request
* @param {object} res response
* @returns {object} response
*/
static async getAllUsers(req, res) {
const allUsers = await UserService.getAllUsers();


const chatUsers = allUsers.map((user) => {
const chatUser = {
id: user.id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
profilePicture: user.profilePicture
};

const onlineUser = users[user.email];

if (onlineUser) {
chatUser.isOnline = true;
return chatUser;
}
chatUser.isOnline = false;
return chatUser;
});

const sortedUsers = chatUsers.sort((a, b) => a.isOnline.toString()
.localeCompare(b.isOnline.toString())).reverse();

io.emit('updateUsersList', sortedUsers);

ResponseService.setSuccess(200, 'All users', sortedUsers);
return ResponseService.send(res);
}
}

export default ChatController;
21 changes: 15 additions & 6 deletions src/helpers/eventEmmiters/socket.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import moment from 'moment';

const io = require('socket.io')();

const socketioJwt = require('socketio-jwt');

const generateMessage = (from, text) => ({
from,
text,
createdAt: moment().valueOf()
});

const users = {};
const startSocket = (server) => {
io.attach(server);
Expand All @@ -12,15 +21,15 @@ const startSocket = (server) => {
timeout: 15000 // 15 seconds to send the authentication message
}))
.on('authenticated', (socket) => {
socket.emit('success', socket.decoded_token.email); // Emit success message for front-end
socket.emit('success', socket.decoded_token); // Emit success message for front-end
socket.on('new-user', (user) => { // save a new user for future needs
userName = user;
users[user] = socket;
io.sockets.emit('user-connected', `${user} has joined.`);
userName = user.email;
users[user.email] = socket;
socket.broadcast.emit('user-connected', generateMessage('Admin', `${user.firstName} ${user.lastName} Joined!`));
});
socket.on('private message', (msg) => {
const fromMsg = { from: userName, txt: msg.txt };
users[msg.to].emit('private message', fromMsg);
socket.emit('newMessage', generateMessage(`You --> ${msg.to}`, msg.text));
users[msg.to].emit('newMessage', generateMessage(`${userName}--> ${msg.to}`, msg.text));
});
socket.on('disconnect', () => {
delete users[userName];
Expand Down
33 changes: 33 additions & 0 deletions src/migrations/20200126114026-create-chat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const chatMigrations = {
up: (queryInterface, Sequelize) => queryInterface.createTable('Chats', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
sender: {
type: Sequelize.STRING
},
receiver: {
type: Sequelize.STRING
},
message: {
type: Sequelize.STRING
},
isRead: {
type: Sequelize.BOOLEAN,
defaultValue: false,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
}),
down: (queryInterface) => queryInterface.dropTable('Chats')
};
export default chatMigrations;
12 changes: 12 additions & 0 deletions src/models/chat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export default (sequelize, DataTypes) => {
const Chat = sequelize.define('Chat', {
sender: DataTypes.STRING,
receiver: DataTypes.STRING,
message: DataTypes.STRING,
isRead: DataTypes.BOOLEAN
}, {});
Chat.associate = () => {
// associations can be defined here
};
return Chat;
};
46 changes: 46 additions & 0 deletions src/public/chat.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<script defer src="http://localhost:3000/socket.io/socket.io.js"></script>
<meta name="viewport" content="width=device-width, inital-scale=1, user-scalable=no">
<link rel="stylesheet" href="./css/styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body class="chat">

<div class="chat__sidebar">
<h3>People</h3>
<div id="users"></div>
</div>

<div class="chat__main">
<ol id="messages" class="chat__messages"></ol>

<div class="chat__footer">
<form id="message-form">
<input name="message" type="text" placeholder="Message" autofocus autocomplete="off"/>
<button id="submit-btn">Send</button>
</form>
</div>
</div>

<script id="message-template" type="text/template">
<li class="message">
<div class="message__title">
<h4>{{from}}</h4>
<span>{{createdAt}}</span>
</div>
<div class="message__body">
<p>{{text}}</p>
</div>
</li>
</script>

<!-- <script src="/socket.io/socket.io.js"></script> -->
<script defer type="module" src="./script.js"></script>
<script type="text/javascript" src="./chat/js/libs/moment.js"></script>
<script type="text/javascript" src="./chat/js/libs/mustache.js"></script>
</body>
</html>
40 changes: 40 additions & 0 deletions src/public/chat/js/libs/http-requests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const messageContainer = document.getElementById('message-container');

export const saveMessages = async (API, token, data) => {
const response = await fetch(API, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
Authorization: token,
},
redirect: 'follow',
referrerPolicy: 'no-referrer',
body: JSON.stringify(data)
});

const result = await response.json();

return result;
};

export const getAllUsers = async (API, token) => {
const response = await fetch(API, {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
Authorization: token,
},
redirect: 'follow',
referrerPolicy: 'no-referrer',
});

const result = await response.json();

return result;
};
Loading

0 comments on commit 25c3f10

Please sign in to comment.