diff --git a/app.js b/app.js index 86feab0..d39ce30 100644 --- a/app.js +++ b/app.js @@ -98,8 +98,7 @@ function enter(res, user) { //login, color, id msg.id = result[0]["max(id)"] + 1; chat.addnewmessage(msg); res.cookie("danchat.token", token, { - path: "/", - httpOnly: true + path: "/" }); res.redirect("/"); }) @@ -521,7 +520,24 @@ app.post("/user/add/friend", parserJSON, (req, res) => { var userId = dt1[0].id; sql.query(`insert into friends_requests(from_id, to_id) values (${u.id}, ${userId})`, (err) => { if (err) console.error(err); - res.json(new ResponseObject(true)); + sql.query(`select token from tokens where id = ${userId}`, (err, data) => { + if (err) console.error(err); + if (data === undefined || data.length === 0) { + res.json(new ResponseObject(true)); + } else { + sql.query(`select login, firstname, lastname, color, sex from users where id = ${u.id}`, (err, dt2) => { + if (err) console.error(err); + io.emit(data[0].token, { + type: "newIncomingRequest", + login: dt2[0].login, + name: `${dt2[0].firstname} ${dt2[0].lastname}`, + color : dt2[0].color, + sex : dt2[0].sex + }) + res.json(new ResponseObject(true)); + }) + } + }) }) }) } @@ -582,7 +598,24 @@ app.post("/user/accept/incomingrequest", parserJSON, (req, res) => { if (err) console.error(err); sql.query(`insert into friends (id_1, id_2) values (${userId}, ${u.id})`, (err) => { if (err) console.error(err); - res.json(new ResponseObject(true)); + sql.query(`select token from tokens where id = ${userId}`, (err, data) => { + if (err) console.error(err); + if (data === undefined || data.length === 0) { + res.json(new ResponseObject(true)); + } else { + sql.query(`select login, firstname, lastname, sex, color from users where id = ${u.id}`, (err, dt2) => { + if (err) console.error(err); + io.emit(data[0].token, { + type: "acceptOutcomingRequest", + login: dt2[0].login, + name: `${dt2[0].firstname} ${dt2[0].lastname}`, + color : dt2[0].color, + sex : dt2[0].sex + }) + res.json(new ResponseObject(true)); + }) + } + }) }) }) }) @@ -609,7 +642,24 @@ app.post("/user/delete/friend", parserJSON, (req, res) => { if (err) console.error(err); sql.query(`insert into friends_requests (from_id, to_id) values (${friendId}, ${u.id})`, (err) => { if (err) console.error(err); - res.json(new ResponseObject(true)); + sql.query(`select token from tokens where id = ${friendId}`, (err, data) => { + if (err) console.error(err); + if (data === undefined || data.length === 0) { + res.json(new ResponseObject(true)); + } else { + sql.query(`select login, firstname, lastname, sex, color from users where id = ${u.id}`, (err, dt2) => { + if (err) console.error(err); + io.emit(data[0].token, { + type: "deletingFromFriends", + login: dt2[0].login, + name: `${dt2[0].firstname} ${dt2[0].lastname}`, + color : dt2[0].color, + sex : dt2[0].sex + }) + res.json(new ResponseObject(true)); + }) + } + }) }) }) }) diff --git a/public/js/functions.js b/public/js/functions.js new file mode 100644 index 0000000..bf48e9f --- /dev/null +++ b/public/js/functions.js @@ -0,0 +1,6 @@ +function getCookie(name) { + var matches = document.cookie.match(new RegExp( + "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)" + )); + return matches ? decodeURIComponent(matches[1]) : undefined; +} diff --git a/public/js/notifications.js b/public/js/notifications.js new file mode 100644 index 0000000..36a5950 --- /dev/null +++ b/public/js/notifications.js @@ -0,0 +1,33 @@ +socket.on(getCookie("danchat.token"), function(update) { + if (update.type === "newIncomingRequest") { + VanillaToasts.create({ + title: "Уведомление", + text: `${update.login} (${update.name}) хочет с вами дружить`, + type: "info", + callback: ()=>{ + location = "/incoming" + }, + timeout:20000 + }); + } else if (update.type === "acceptOutcomingRequest") { + VanillaToasts.create({ + title: "Уведомление", + text: `${update.login} (${update.name}) принял${update.sex?"":"а"} вашу заявку`, + type: "success", + callback: ()=>{ + location = "/friends" + }, + timeout:20000 + }); + } else if (update.type === "deletingFromFriends") { + VanillaToasts.create({ + title: "Уведомление", + text: `${update.login} (${update.name}) удалил${update.sex?"":"а"} вас из друзей`, + type: "error", + callback: ()=>{ + location = "/friends" + }, + timeout:20000 + }); + } +}) diff --git a/public/js/vanillatoasts.js b/public/js/vanillatoasts.js new file mode 100644 index 0000000..16aef96 --- /dev/null +++ b/public/js/vanillatoasts.js @@ -0,0 +1,132 @@ +(function(root, factory) { + try { + // commonjs + if (typeof exports === 'object') { + module.exports = factory(); + // global + } else { + root.VanillaToasts = factory(); + } + } catch(error) { + console.log('Isomorphic compatibility is not supported at this time for VanillaToasts.') + } +})(this, function() { + + // We need DOM to be ready + if (document.readyState === 'complete') { + init(); + } else { + window.addEventListener('DOMContentLoaded', init); + } + + // Create VanillaToasts object + VanillaToasts = { + // In case toast creation is attempted before dom has finished loading! + create: function() { + console.error([ + 'DOM has not finished loading.', + '\tInvoke create method when DOM\s readyState is complete' + ].join('\n')) + }, + //function to manually set timeout after create + setTimeout: function() { + console.error([ + 'DOM has not finished loading.', + '\tInvoke create method when DOM\s readyState is complete' + ].join('\n')) + }, + toasts: {} //store toasts to modify later + }; + var autoincrement = 0; + + // Initialize library + function init() { + // Toast container + var container = document.createElement('div'); + container.id = 'vanillatoasts-container'; + document.body.appendChild(container); + + // @Override + // Replace create method when DOM has finished loading + VanillaToasts.create = function(options) { + var toast = document.createElement('div'); + toast.id = ++autoincrement; + toast.id = 'toast-' + toast.id; + toast.className = 'vanillatoasts-toast'; + + // title + if (options.title) { + var h4 = document.createElement('h4'); + h4.className = 'vanillatoasts-title'; + h4.innerHTML = options.title; + toast.appendChild(h4); + } + + // text + if (options.text) { + var p = document.createElement('p'); + p.className = 'vanillatoasts-text'; + p.innerHTML = options.text; + toast.appendChild(p); + } + + // icon + if (options.icon) { + var img = document.createElement('img'); + img.src = options.icon; + img.className = 'vanillatoasts-icon'; + toast.appendChild(img); + } + + // click callback + if (typeof options.callback === 'function') { + toast.addEventListener('click', options.callback); + } + + // toast api + toast.hide = function() { + toast.className += ' vanillatoasts-fadeOut'; + toast.addEventListener('animationend', removeToast, false); + }; + + // autohide + if (options.timeout) { + setTimeout(toast.hide, options.timeout); + } + + if (options.type) { + toast.className += ' vanillatoasts-' + options.type; + } + + toast.addEventListener('click', toast.hide); + + + function removeToast() { + document.getElementById('vanillatoasts-container').removeChild(toast); + delete VanillaToasts.toasts[toast.id]; //remove toast from object + } + + document.getElementById('vanillatoasts-container').appendChild(toast); + + //add toast to object so its easily gettable by its id + VanillaToasts.toasts[toast.id] = toast; + + return toast; + } + + /* + custom function to manually initiate timeout of + the toast. Useful if toast is created as persistant + because we don't want it to start to timeout until + we tell it to + */ + VanillaToasts.setTimeout = function(toastid, val) { + if(VanillaToasts.toasts[toastid]){ + setTimeout(VanillaToasts.toasts[toastid].hide, val); + } + } + } + + return VanillaToasts; + +}); diff --git a/public/styles/vanillatoasts.css b/public/styles/vanillatoasts.css new file mode 100644 index 0000000..431d580 --- /dev/null +++ b/public/styles/vanillatoasts.css @@ -0,0 +1,98 @@ +#vanillatoasts-container { + position: fixed; + top: 0; + right: 0; + width: 320px; + font-family: 'Helvetica'; +} + +.vanillatoasts-toast { + position: relative; + padding: 20px 17px; + margin: 20px; + border-radius: 10px; + background: #F5F5F5; + cursor: pointer; + box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1); + animation-duration: .3s; + animation-name: VanillaToasts; + animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); +} + +.vanillatoasts-fadeOut { + animation-name: VanillaToastsFadeOut; + animation-duration: .3s; + animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); + animation-fill-mode: forwards; +} + +#vanillatoasts-container p, +#vanillatoasts-container h4 { + margin: 3px 0!important; +} + +.vanillatoasts-title { + font-weight: 700; + font-size: 15px; + margin-bottom: 10px; +} + +.vanillatoasts-text { + font-size: 14px; + color: #2e2e2e; +} + +.vanillatoasts-icon { + position: absolute; + top: 5px; + left: -40px; + width: 50px; + height: 50px; + border-radius: 100%; + box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1); + background: #FFF; +} + +.vanillatoasts-toast a, .vanillatoasts-toast a:hover { + color: #549EDB !important; + text-decoration: none !important; +} + +/** toast types */ +.vanillatoasts-success { + border-bottom: 5px solid #51C625; +} + +.vanillatoasts-warning { + border-bottom: 5px solid #DB9215; +} + +.vanillatoasts-error { + border-bottom: 5px solid #DB2B1D; +} + +.vanillatoasts-info { + border-bottom: 5px solid #27ABDB; +} + +@keyframes VanillaToasts { + from { + transform: translate3d(400px, 0, 0);; + opacity: 0; + } + to { + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +@keyframes VanillaToastsFadeOut { + from { + transform: translate3d(0, 0, 0); + opacity: 1; + } + to { + transform: translate3d(400px, 0, 0); + opacity: 0; + } +} diff --git a/views/chat.ejs b/views/chat.ejs index 76633a3..00a2cda 100644 --- a/views/chat.ejs +++ b/views/chat.ejs @@ -22,7 +22,10 @@


+ + + Онлайн: <%=onlineCounter%> <%- include('partials/footer.ejs') %> diff --git a/views/partials/header.ejs b/views/partials/header.ejs index a0bc9e5..dc8c50a 100644 --- a/views/partials/header.ejs +++ b/views/partials/header.ejs @@ -1,3 +1,4 @@ + diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index 69f0c20..1f47024 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -1,2 +1,5 @@ + + +