Skip to content

Commit

Permalink
feat(inApp-notification): Implement in-app notification feature for new
Browse files Browse the repository at this point in the history
travel request

- [x] Install socket.io and sockect.io-client
- [x] Create in-app client
- [x] Create sockect io server
- [x] Create endpoint that test inapp feature from through a browser
- [x] Modify new trip request method

[Finishes #167891584]
  • Loading branch information
Pomile committed Sep 17, 2019
1 parent 578696d commit 34f9819
Show file tree
Hide file tree
Showing 17 changed files with 191 additions and 128 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Barefoot Nomad - Making company travel and accommodation easy and convenient.

[![Build Status](https://travis-ci.org/andela/banshee-bn-backend.svg?branch=develop)](https://travis-ci.org/andela/banshee-bn-backend)
[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com)
[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com) [![Coverage Status](https://coveralls.io/repos/github/andela/banshee-bn-backend/badge.svg?branch=develop)](https://coveralls.io/github/andela/banshee-bn-backend?branch=develop)

## Vision

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
"sequelize": "^5.15.0",
"sequelize-cli": "^5.5.0",
"sequelize-replace-enum-postgres": "1.5.0",
"socket.io": "^2.2.0",
"socket.io-client": "^2.2.0",
"swagger-ui-express": "^4.0.7",
"underscore": "^1.9.1",
"uuid-validate": "0.0.3"
Expand Down
17 changes: 17 additions & 0 deletions src/controllers/Trip.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import Response from '../helpers/Response';
import SearchDatabase from '../helpers/SearchDatabase';
import EmailNotifications from '../helpers/EmailNotifications';
import addNotification from '../helpers/addNotification';
import { inAppStyle } from '../helpers/template/styles';
import script from '../helpers/template/inAppScript';
import inAppHTMLContent from '../helpers/template/inAppContent';
import templateIndex from '../helpers/template/index';
import inAppBot from '../helpers/inAppBot';

const {
Trip, Branch, User, Stop, Accomodation, Location
Expand Down Expand Up @@ -99,6 +104,7 @@ class TripController {
const recipients = emails.includes(email) ? [...emails] : [...emails, email];
data.trips = { ...data.trips, ...tripData };
EmailNotifications.sendNewTrip(emails, message, data);
inAppBot.send('New trip request', { message, recipients });
await addNotification(trip.id, message, recipients);
const response = new Response(
true,
Expand Down Expand Up @@ -446,6 +452,17 @@ class TripController {
);
}
}

/**
*
* @param {req} req
* @param {res} res
* @return {object} object
*/
static sendInAppPage(req, res) {
const temp = templateIndex(inAppStyle, inAppHTMLContent, script);
res.status(200).send(temp);
}
}

export default TripController;
48 changes: 0 additions & 48 deletions src/database/migrations/20190905031542-create-reads.js

This file was deleted.

24 changes: 0 additions & 24 deletions src/database/models/read.js

This file was deleted.

2 changes: 1 addition & 1 deletion src/helpers/EmailNotifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import mailer from './Mailer';
import template from './emailTemplate';
import templateIndex from './template';
import newTripRequestEmailContent from './template/newTripRequestEmailContent';
import newTripStyle from './template/styles';
import { newTripStyle } from './template/styles';

/**
* @class EmailNotifications
Expand Down
16 changes: 16 additions & 0 deletions src/helpers/inAppBot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import client from 'socket.io-client';

const port = process.env.PORT;
const socket = client.connect(process.env.NODE_ENV === 'production' ? 'https ://banshee-backend.herokuapp.com/admin/inapp' : `http://localhost:${port}/admin/inapp`);
/*
* @param(string) event
* @param(object) data
@return
*/
const inAppBot = {
send: (event, data) => {
socket.emit(event, data);
}
};

export default inAppBot;
16 changes: 16 additions & 0 deletions src/helpers/socketIo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import socketIO from 'socket.io';

const socketIo = (server) => {
const io = socketIO(server);
const adminInApp = io
.of('/admin/inapp')
.on('connection', (socket) => {
socket.emit('New connection', 'Connected');
socket.on('New trip request', (data) => {
io.of('/admin/inapp')
.emit('New trip request', data);
});
});
};

export default socketIo;
13 changes: 13 additions & 0 deletions src/helpers/template/inAppContent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const inAppHtmlContent = `
<div class="container">
<div class="notification-btn dropdown" id="notificationBtn">
<i class="material-icons iconSettings dropbtn" id="bell">notifications_active</i>
<ul class="notifications dropdown-content" id="notificationList">
<li>Notifications</li>
</ul>
</div>
</div>
`;

export default inAppHtmlContent;
23 changes: 23 additions & 0 deletions src/helpers/template/inAppScript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const port = process.env.PORT;
const url = process.env.NODE_ENV === 'production' ? 'https ://banshee-backend.herokuapp.com/admin/inapp' : `'http://localhost:${port}/admin/inapp'`;
const script = `
const email = 'banshee.admin@gmail.com';
const appendMessage = (data) => {
const elem = document.createElement('li');
elem.innerHTML = data.message;
const messageList = document.getElementById("notificationList");
messageList.appendChild(elem);
}
const adminInAppClient = io.connect(${url});
adminInAppClient.on('New connection', (data) => {
adminInAppClient.emit('User info', {email});
});
adminInAppClient.on('New trip request', (data) => {
if(data.recipients.includes(email)){
appendMessage(data);
}
});`;

export default script;
12 changes: 5 additions & 7 deletions src/helpers/template/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
/**
*
* @param {string} style
* @param {string} content
* @return {string} string
*/
const index = (style, content) => `<!DOCTYPE html>
const index = (style, content, script) => `<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
<script>
${script}
</script>
<style>
${style}
</style>
Expand Down
16 changes: 8 additions & 8 deletions src/helpers/template/newTripRequestEmailContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@
* @returns {string} string
*/
const newTripRequestEmailTemplate = (data) => {
const requesterName = `${data.user.firstName} ${data.user.lastName}`;
const requesterEmail = `${data.user.email}`;
const requeterStartLocation = `${data.startLocation.name} ${data.startLocation.location.city} ${data.startLocation.location.country}`;
const departureDate = `${data.trips.departureDate}`;
const reason = `${data.trips.reason}`;
const type = `${data.trips.type}`;
const destinations = data.destinations.reduce((initial, destination) => `
const requesterName = `${data.user.firstName} ${data.user.lastName}`;
const requesterEmail = `${data.user.email}`;
const requeterStartLocation = `${data.startLocation.name} ${data.startLocation.location.city} ${data.startLocation.location.country}`;
const departureDate = `${data.trips.departureDate}`;
const reason = `${data.trips.reason}`;
const type = `${data.trips.type}`;
const destinations = data.destinations.reduce((initial, destination) => `
${initial}<tr>
<td>${destination.branch.name} ${destination.branch.location.city} ${destination.branch.location.country}</td>
<td>${destination.accomodation.name}</td>
<td>Indefinite</td>
</tr>`, '');
return `
return `
<div class="container">
<div class="logo">
<center><img src="https://res.cloudinary.com/pomile/image/upload/c_scale,w_120/v1567691280/nomadTravel_lg_logo_sqbl9o.png" /></center>
Expand Down
44 changes: 43 additions & 1 deletion src/helpers/template/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,46 @@ const newTripStyle = `
}
`;

export default newTripStyle;
const inAppStyle = `
*{ margin: 0; padding: 0; }
.container{ width: 100%; height: 100vh; display: flex; flex-flow: row wrap ;justify-content: center; margin-top: 100px; }
ul { list-style-type: none; margin: 0; padding: 0; }
.dropbtn { background-color: gray; color: white; padding: 16px; font-size: 28px; border: none; cursor: pointer; border-radius: 50%;}
/* The container <div> - needed to position the dropdown content */
.dropdown {
position: relative;
display: inline-block;
}
/* Dropdown Content (Hidden by Default) */
.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 300px;
width: 350px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
/* Links inside the dropdown */
.dropdown-content li {
color: black;
padding: 12px 20px;
text-decoration: none;
display: block;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden
}
/* Change color of dropdown links on hover */
.dropdown-content li:hover {background-color: #f1f1f1; cursor: pointer}
/* Show the dropdown menu on hover */
.dropdown:hover .dropdown-content {
display: block;
}
/* Change the background color of the dropdown button when the dropdown content is shown */
.dropdown:hover .dropbtn {
color: #D6DBDF;
}
`;

export { newTripStyle, inAppStyle };
12 changes: 11 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ import dotenv from 'dotenv';
import swaggerUi from 'swagger-ui-express';
import logger from 'morgan';
import passport from 'passport';
import http from 'http';
import socketIo from './helpers/socketIo';
import router from './routes';
import swaggerDoc from '../swagger.json';

const { NODE_ENV } = process.env;
const app = express();
const server = http.Server(app);

dotenv.config();
if (NODE_ENV === 'development' || NODE_ENV === 'production') {
app.use(logger('dev'));
Expand All @@ -29,6 +33,12 @@ app.use('/api/v1/docs', swaggerUi.serve, swaggerUi.setup(swaggerDoc));

const port = process.env.PORT || 3000;

app.listen(port);
server.listen(port);
socketIo(server);
// io.on('connection', (socket) => {
// socket.on('admin in-app', (data) => {
// io.emit('admin in-app', data);
// });
// });

export default app;
5 changes: 5 additions & 0 deletions src/routes/trip.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,9 @@ tripRoutes.patch(

tripRoutes.get('/mostvisited', Token.verifyToken, TripController.getMostVisitedBranch);

tripRoutes.get(
'/test/in_app',
TripController.sendInAppPage,
);

export default tripRoutes;
Loading

0 comments on commit 34f9819

Please sign in to comment.