Initial comit ver2
This commit is contained in:
commit
69b3aa215d
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
node_modules/
|
||||||
|
src/utils/roomsIDs.json
|
||||||
|
src/utils/roomsIDs.json
|
BIN
Kacper-Maj-Karta-projekt.pdf
Normal file
BIN
Kacper-Maj-Karta-projekt.pdf
Normal file
Binary file not shown.
2
README.md
Normal file
2
README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Watch With Friends
|
||||||
|
**Watch with friends** to projekt, który ma za zadanie umożliwić „spotkanie” się znajomych na wspólnym oglądaniu filmów w dobie pandemii. Postawiłem sobie za zadanie umożliwić połączenie możliwie wielu przyjaciół jednocześnie w jednym, generowanym losowo pokoju do którego dostęp otrzymują osoby, które dostaną unikatowy link. W pokoju tym użytkownicy poproszeni zostaną o ustawienie swojej nazwy a następnie mogą zarządzać puszczanym aktualnie filmem z YouTube, wkleić link do wybranego przez siebie filmu, dowolnie zatrzymywać i puszczać film. Jako dodatkowy element pokoju dodany zostanie chat, który będzie pozwalał na komunikację pomiędzy użytkownikami serwisu w czasie rzeczywistym.
|
1526
package-lock.json
generated
Normal file
1526
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
package.json
Normal file
21
package.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "chat-app",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node src/index.js",
|
||||||
|
"dev": "nodemon src/index.js"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"bad-words": "^3.0.4",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"socket.io": "^3.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"nodemon": "^2.0.7"
|
||||||
|
}
|
||||||
|
}
|
42
public/chat.html
Normal file
42
public/chat.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!doctype html>
|
||||||
|
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
|
||||||
|
<title>Chat</title>
|
||||||
|
<link rel="icon" href="/img/favicon.png">
|
||||||
|
<link rel="stylesheet" href="/css/styles.min.css">
|
||||||
|
<link rel="stylesheet" href="/css/styles.css">
|
||||||
|
<meta name="description" content="Chat">
|
||||||
|
<meta name="author" content="SitePoint">
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/3.0.1/mustache.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/qs/6.6.0/qs.min.js"></script>
|
||||||
|
<script defer src="/socket.io/socket.io.js"></script>
|
||||||
|
<script defer src="/js/chat.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="chat">
|
||||||
|
<div class="chat__sidebar">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="chat__main">
|
||||||
|
<div id="messages-container" class="chat__messages"> </div>
|
||||||
|
|
||||||
|
<div class="compose">
|
||||||
|
<form action="POST" id="sendMessForm">
|
||||||
|
<input placeholder="Write your message">
|
||||||
|
<button type="submit" id="formButton">Send</button>
|
||||||
|
</form>
|
||||||
|
<button id="sendLocation">Send location!</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
public/css/.DS_Store
vendored
Normal file
BIN
public/css/.DS_Store
vendored
Normal file
Binary file not shown.
196
public/css/styles.css
Normal file
196
public/css/styles.css
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
/* General Styles */
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
line-height: 1.4;
|
||||||
|
color: #333333;
|
||||||
|
font-family: Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
border: 1px solid #eeeeee;
|
||||||
|
padding: 12px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 12px;
|
||||||
|
background: #7c5cbf;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
font-size: 16px;
|
||||||
|
transition: background 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: #6b47b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
cursor: default;
|
||||||
|
background: #7c5cbf94;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Join Page Styles */
|
||||||
|
|
||||||
|
.centered-form {
|
||||||
|
background: #333744;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered-form__box {
|
||||||
|
box-shadow: 0px 0px 17px 1px #1d1f26;
|
||||||
|
background: #f7f7fa;
|
||||||
|
padding: 24px;
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered-form button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered-form input {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chat Page Layout */
|
||||||
|
|
||||||
|
.chat {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat__sidebar {
|
||||||
|
height: 100vh;
|
||||||
|
color: rgb(223, 223, 223);
|
||||||
|
background: #333744;
|
||||||
|
width: 225px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chat styles */
|
||||||
|
|
||||||
|
.chat__main {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat__messages {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: 24px 24px 0 24px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Message Styles */
|
||||||
|
|
||||||
|
.message {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message__name {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message__meta {
|
||||||
|
color: #777;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message a {
|
||||||
|
color: #0070cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Message Composition Styles */
|
||||||
|
|
||||||
|
.compose {
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 16px;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compose form {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compose input {
|
||||||
|
border: 1px solid #eeeeee;
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
|
margin: 0 16px 0 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compose button {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chat Sidebar Styles */
|
||||||
|
|
||||||
|
.room-title {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 20px;
|
||||||
|
background: #2c2f3a;
|
||||||
|
padding: 24px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-title {
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 20px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
padding: 12px 24px 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.users {
|
||||||
|
text-align: center;
|
||||||
|
list-style-type: none;
|
||||||
|
font-weight: 100;
|
||||||
|
font-style: italic;
|
||||||
|
padding: 12px 24px 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-mess {
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-right: 8px;
|
||||||
|
color: #333333;
|
||||||
|
}
|
147
public/css/styles.min.css
vendored
Normal file
147
public/css/styles.min.css
vendored
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
line-height: 1.4;
|
||||||
|
color: #333;
|
||||||
|
font-family: Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
border: 1px solid #eee;
|
||||||
|
padding: 12px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 12px;
|
||||||
|
background: #7c5cbf;
|
||||||
|
border: none;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 16px;
|
||||||
|
transition: background 0.3s ease;
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
background: #6b47b8;
|
||||||
|
}
|
||||||
|
button:disabled {
|
||||||
|
cursor: default;
|
||||||
|
background: #7c5cbf94;
|
||||||
|
}
|
||||||
|
.centered-form {
|
||||||
|
background: #333744;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.centered-form__box {
|
||||||
|
box-shadow: 0 0 17px 1px #1d1f26;
|
||||||
|
background: #f7f7fa;
|
||||||
|
padding: 24px;
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
.centered-form button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.centered-form input {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.chat {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.chat__sidebar {
|
||||||
|
height: 100vh;
|
||||||
|
color: #fff;
|
||||||
|
background: #333744;
|
||||||
|
width: 225px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
.chat__main {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-height: 100vh;
|
||||||
|
}
|
||||||
|
.chat__messages {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: 24px 24px 0;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.message__name {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
.message__meta {
|
||||||
|
color: #777;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.message a {
|
||||||
|
color: #0070cc;
|
||||||
|
}
|
||||||
|
.compose {
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 16px;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
.compose form {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
.compose input {
|
||||||
|
border: 1px solid #eee;
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
|
margin: 0 16px 0 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
.compose button {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.room-title {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 22px;
|
||||||
|
background: #2c2f3a;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
.list-title {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 18px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
padding: 12px 24px 0;
|
||||||
|
}
|
||||||
|
.users {
|
||||||
|
list-style-type: none;
|
||||||
|
font-weight: 300;
|
||||||
|
padding: 12px 24px 0;
|
||||||
|
}
|
||||||
|
.myPar {
|
||||||
|
text-align: center;
|
||||||
|
font-family: Helvetica, sans-serif;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
BIN
public/img/favicon.png
Normal file
BIN
public/img/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
33
public/index.html
Normal file
33
public/index.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<!doctype html>
|
||||||
|
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
|
||||||
|
<title>Chat</title>
|
||||||
|
<link rel="icon" href="/img/favicon.png">
|
||||||
|
<link rel="stylesheet" href="/css/styles.min.css">
|
||||||
|
<meta name="description" content="Chat">
|
||||||
|
<meta name="author" content="SitePoint">
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="centered-form">
|
||||||
|
<div class="centered-form__box">
|
||||||
|
<h1>Join</h1>
|
||||||
|
<form action="/chat.html">
|
||||||
|
<label>Display name</label>
|
||||||
|
<input type="text" name="username" placeholder="Display name" required>
|
||||||
|
<label>Room</label>
|
||||||
|
<input type="text" name="room" placeholder="Room" required>
|
||||||
|
<button type="submit">Join</button>
|
||||||
|
</form>
|
||||||
|
<p class="myPar">or</p>
|
||||||
|
<button type="submit">Generate room</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
152
public/js/chat.js
Normal file
152
public/js/chat.js
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
'use strict';
|
||||||
|
const socket = io();
|
||||||
|
const buttonLocation = document.querySelector('#sendLocation');
|
||||||
|
const form = document.querySelector('#sendMessForm');
|
||||||
|
const formButton = document.querySelector('#formButton');
|
||||||
|
const input = form.childNodes[1];
|
||||||
|
const button = form.childNodes[3];
|
||||||
|
const messageContainer = document.querySelector('#messages-container');
|
||||||
|
const sidebarContainer = document.querySelector('.chat__sidebar');
|
||||||
|
|
||||||
|
// TEMPLATES
|
||||||
|
const sidebarTemplate = `<h2 class="room-title">{{room}}</h2>
|
||||||
|
<h3 class="list-title">Users</h3>
|
||||||
|
<ul class="users">
|
||||||
|
{{#users}}
|
||||||
|
<li>{{username}}</li>
|
||||||
|
{{/users}}
|
||||||
|
</ul>`;
|
||||||
|
|
||||||
|
const htmlTemplate = [
|
||||||
|
`<div class="message">
|
||||||
|
<p>
|
||||||
|
<span class="message__name"> {{user}} </span>
|
||||||
|
<span class="message__meta"> {{createdAt}} </span>
|
||||||
|
</p>
|
||||||
|
<p>{{string}}</p>
|
||||||
|
</div>`,
|
||||||
|
`<div class="message">
|
||||||
|
<p>
|
||||||
|
<span class="message__name"> {{user}} </span>
|
||||||
|
<span class="message__meta"> {{createdAt}} </span>
|
||||||
|
</p>
|
||||||
|
<p><a href="{{string}}">Link</a></p>
|
||||||
|
</div>`,
|
||||||
|
`<div class="message">
|
||||||
|
<p class="welcome-mess">{{string}}</p>
|
||||||
|
</div>`,
|
||||||
|
];
|
||||||
|
|
||||||
|
let message = '';
|
||||||
|
// let user = window.prompt('Please state your username', 'User');
|
||||||
|
|
||||||
|
const autoscroll = () => {
|
||||||
|
// New message elemnt
|
||||||
|
const newMessage = messageContainer.lastElementChild;
|
||||||
|
|
||||||
|
// Height of the new message
|
||||||
|
const newMessageStyles = getComputedStyle(newMessage);
|
||||||
|
const newMessageMargin = parseInt(newMessageStyles.marginBottom);
|
||||||
|
const newMessageHeight = newMessage.offsetHeight + newMessageMargin;
|
||||||
|
|
||||||
|
// Visible height
|
||||||
|
const visibleHeight = messageContainer.offsetHeight;
|
||||||
|
|
||||||
|
// Height of messages container
|
||||||
|
const containerHeight = messageContainer.scrollHeight;
|
||||||
|
|
||||||
|
// scrolloffset
|
||||||
|
const scrolloffset = messageContainer.scrollTop + visibleHeight + 15;
|
||||||
|
|
||||||
|
if (containerHeight - newMessageHeight <= scrolloffset) {
|
||||||
|
console.log('should scroll down');
|
||||||
|
messageContainer.scrollTop = messageContainer.scrollHeight;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const { username, room } = Qs.parse(location.search, {
|
||||||
|
ignoreQueryPrefix: true,
|
||||||
|
});
|
||||||
|
console.log(username, room);
|
||||||
|
|
||||||
|
socket.on('message', (object) => {
|
||||||
|
console.log(object);
|
||||||
|
const string = object.text;
|
||||||
|
const user = object.username;
|
||||||
|
const createdAt = moment(object.createdAt).format('HH:mm:ss');
|
||||||
|
|
||||||
|
if (string.includes('https') || string.includes('http')) {
|
||||||
|
const html = Mustache.render(htmlTemplate[1], {
|
||||||
|
user,
|
||||||
|
string,
|
||||||
|
createdAt,
|
||||||
|
});
|
||||||
|
messageContainer.insertAdjacentHTML('beforeend', html);
|
||||||
|
autoscroll();
|
||||||
|
|
||||||
|
console.log('not includes');
|
||||||
|
} else if (string.includes('Welcome to the server')) {
|
||||||
|
const html = Mustache.render(htmlTemplate[2], {
|
||||||
|
string,
|
||||||
|
});
|
||||||
|
messageContainer.insertAdjacentHTML('beforeend', html);
|
||||||
|
autoscroll();
|
||||||
|
} else {
|
||||||
|
const html = Mustache.render(htmlTemplate[0], {
|
||||||
|
string,
|
||||||
|
user,
|
||||||
|
createdAt,
|
||||||
|
});
|
||||||
|
messageContainer.insertAdjacentHTML('beforeend', html);
|
||||||
|
autoscroll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
form.addEventListener('submit', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
input.focus();
|
||||||
|
|
||||||
|
// Disable form
|
||||||
|
|
||||||
|
if (input.value === '') return;
|
||||||
|
button.setAttribute('disabled', 'disabled');
|
||||||
|
|
||||||
|
socket.emit('message', input.value, (error) => {
|
||||||
|
// Re-enable form
|
||||||
|
button.removeAttribute('disabled');
|
||||||
|
if (error) return console.log(error);
|
||||||
|
console.log('Message delivered');
|
||||||
|
input.value = '';
|
||||||
|
input.focus();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send location
|
||||||
|
buttonLocation.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!navigator.geolocation) return alert('No geolocation');
|
||||||
|
buttonLocation.setAttribute('disabled', 'disabled');
|
||||||
|
|
||||||
|
navigator.geolocation.getCurrentPosition((position) => {
|
||||||
|
const { latitude, longitude } = position.coords;
|
||||||
|
const coordsObj = `https://www.google.com/maps/?q=${latitude},${longitude}`;
|
||||||
|
|
||||||
|
socket.emit('message', coordsObj, () => {
|
||||||
|
console.log('Location delivered');
|
||||||
|
buttonLocation.removeAttribute('disabled');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('roomData', ({ room, users }) => {
|
||||||
|
const html = Mustache.render(sidebarTemplate, { room, users });
|
||||||
|
sidebarContainer.innerHTML = html;
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.emit('join', { username, room }, (error) => {
|
||||||
|
if (error) {
|
||||||
|
alert(error);
|
||||||
|
location.href = '/';
|
||||||
|
}
|
||||||
|
});
|
86
src/index.js
Normal file
86
src/index.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const http = require('http');
|
||||||
|
const path = require('path');
|
||||||
|
const socketio = require('socket.io');
|
||||||
|
const Filter = require('bad-words');
|
||||||
|
const { generateMessage } = require('./utils/messages');
|
||||||
|
const {
|
||||||
|
addUser,
|
||||||
|
removeUser,
|
||||||
|
getUser,
|
||||||
|
getUsersInRoom,
|
||||||
|
} = require('./utils/users');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const server = http.createServer(app);
|
||||||
|
const io = socketio(server);
|
||||||
|
|
||||||
|
const port = process.env.PORT || 3000;
|
||||||
|
const publicDirectoryPath = path.join(__dirname, '../public');
|
||||||
|
|
||||||
|
app.use(express.static(publicDirectoryPath));
|
||||||
|
|
||||||
|
io.on('connection', (socket) => {
|
||||||
|
// Welcome message
|
||||||
|
|
||||||
|
socket.on('join', ({ username, room }, callback) => {
|
||||||
|
const { error, user } = addUser({ id: socket.id, username, room });
|
||||||
|
if (error) return callback(error);
|
||||||
|
|
||||||
|
socket.join(user.room); //Join the room
|
||||||
|
|
||||||
|
// emit the message to() specific room
|
||||||
|
socket.emit(
|
||||||
|
'message',
|
||||||
|
generateMessage(`Welcome to the server, ${username}!`)
|
||||||
|
);
|
||||||
|
socket.broadcast
|
||||||
|
.to(user.room)
|
||||||
|
.emit('message', generateMessage(`${user.username} has joined`));
|
||||||
|
io.to(user.room).emit('roomData', {
|
||||||
|
room: user.room,
|
||||||
|
users: getUsersInRoom(user.room),
|
||||||
|
});
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
|
||||||
|
// On recv message
|
||||||
|
socket.on('message', (message, callback) => {
|
||||||
|
const user = getUser(socket.id);
|
||||||
|
const filter = new Filter();
|
||||||
|
|
||||||
|
if (filter.isProfane(message)) message = filter.clean(message);
|
||||||
|
//callback('Profanity is not allowed');
|
||||||
|
console.log(user);
|
||||||
|
try {
|
||||||
|
io.to(user.room).emit(
|
||||||
|
'message',
|
||||||
|
generateMessage(message, user.username)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('disconnect', () => {
|
||||||
|
const user = removeUser(socket.id);
|
||||||
|
if (user)
|
||||||
|
io.to(user.room).emit(
|
||||||
|
'message',
|
||||||
|
generateMessage(`${user.username} has left!`)
|
||||||
|
);
|
||||||
|
io.to(user.room).emit('roomData', {
|
||||||
|
room: user.room,
|
||||||
|
users: getUsersInRoom(user.room),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('sendLocation', (object, callback) => {
|
||||||
|
callback('Location shared');
|
||||||
|
socket.broadcast.emit('recvObject', generateMessage(object));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(port, () => console.log(`Server is listening at ${port}`));
|
11
src/utils/messages.js
Normal file
11
src/utils/messages.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const generateMessage = (text, username) => {
|
||||||
|
return {
|
||||||
|
text,
|
||||||
|
username,
|
||||||
|
createdAt: new Date().getTime(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
generateMessage,
|
||||||
|
};
|
54
src/utils/users.js
Normal file
54
src/utils/users.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
const users = [];
|
||||||
|
|
||||||
|
// addUser, removeUser, getUser, getUsersInRoom
|
||||||
|
|
||||||
|
const addUser = ({ id, username, room }) => {
|
||||||
|
// Clean the data
|
||||||
|
// username = username.trim().toLowerCase();
|
||||||
|
// room = room.trim().toLowerCase();
|
||||||
|
if (!room || !username)
|
||||||
|
return {
|
||||||
|
error: 'Username and room are required',
|
||||||
|
};
|
||||||
|
// Check for existing user
|
||||||
|
const existingUser = users.find((user) => {
|
||||||
|
return user.room === room && user.username === username;
|
||||||
|
});
|
||||||
|
// Validate username
|
||||||
|
if (existingUser)
|
||||||
|
return {
|
||||||
|
error: 'Username is in use!',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Store user
|
||||||
|
const user = { id, username, room };
|
||||||
|
users.push(user);
|
||||||
|
return { user };
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeUser = (id) => {
|
||||||
|
const index = users.findIndex((user) => user.id === id);
|
||||||
|
if (index !== -1) {
|
||||||
|
// console.log(users[id])
|
||||||
|
return users.splice(index, 1)[0];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getUser = (id) => {
|
||||||
|
const foundUser = users.find((user) => user.id === id);
|
||||||
|
if (!foundUser) return undefined;
|
||||||
|
return foundUser;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getUsersInRoom = (room) => {
|
||||||
|
const usersInRoom = users.filter((user) => user.room === room);
|
||||||
|
if (!usersInRoom) return [];
|
||||||
|
return usersInRoom;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addUser,
|
||||||
|
removeUser,
|
||||||
|
getUser,
|
||||||
|
getUsersInRoom,
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user