added joining to room
This commit is contained in:
parent
a1b39a3a45
commit
f318afe071
@ -17,8 +17,9 @@ const getJoinableRoom = async () => {
|
||||
return await Room.findOne({ full: false, started: false }).exec();
|
||||
};
|
||||
|
||||
const createNewRoom = () => {
|
||||
const room = new Room();
|
||||
const createNewRoom = data => {
|
||||
const room = new Room(data);
|
||||
room.save();
|
||||
return room;
|
||||
};
|
||||
|
||||
|
||||
@ -1,17 +1,15 @@
|
||||
const { getRoom, updateRoom, getJoinableRoom, createNewRoom, findPlayer } = require('../controllers/roomController');
|
||||
const { getRoom, updateRoom } = require('../controllers/roomController');
|
||||
const { colors } = require('../utils/constants');
|
||||
|
||||
module.exports = socket => {
|
||||
const req = socket.request;
|
||||
|
||||
const handleLogin = async data => {
|
||||
if (await findPlayer(req.sessionID)) return;
|
||||
const room = await getJoinableRoom();
|
||||
if (room) {
|
||||
const room = await getRoom(data.roomId);
|
||||
if (room.isFull()) return socket.emit('error:changeRoom');
|
||||
if (room.started) return socket.emit('error:changeRoom');
|
||||
if (room.private && room.password !== data.password) return socket.emit('error:wrongPassword');
|
||||
addPlayerToExistingRoom(room, data);
|
||||
} else {
|
||||
addNewRoom(data);
|
||||
}
|
||||
};
|
||||
|
||||
const handleReady = async () => {
|
||||
@ -23,13 +21,6 @@ module.exports = socket => {
|
||||
await updateRoom(room);
|
||||
};
|
||||
|
||||
const addNewRoom = async data => {
|
||||
const room = createNewRoom();
|
||||
room.addPlayer(data.name, req.sessionID);
|
||||
await room.save();
|
||||
reloadSession(room);
|
||||
};
|
||||
|
||||
const addPlayerToExistingRoom = async (room, data) => {
|
||||
room.addPlayer(data.name);
|
||||
if (room.isFull()) {
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
const { getRooms, getRoom, updateRoom } = require('../controllers/roomController');
|
||||
const { getRooms, getRoom, updateRoom, createNewRoom } = require('../controllers/roomController');
|
||||
const { sendToOnePlayerRooms, sendToOnePlayerData, sendToPlayersData } = require('../socket/emits');
|
||||
|
||||
module.exports = socket => {
|
||||
const req = socket.request;
|
||||
|
||||
const getData = async () => {
|
||||
const handleGetData = async () => {
|
||||
const room = await getRoom(req.session.roomId);
|
||||
// Handle the situation when the server crashes and any player reconnects after the time has expired
|
||||
// Typically, the responsibility for changing players is managed by gameHandler.js.
|
||||
@ -15,23 +15,17 @@ module.exports = socket => {
|
||||
sendToOnePlayerData(socket.id, room);
|
||||
};
|
||||
|
||||
const getAllRooms = async () => {
|
||||
const handleGetAllRooms = async () => {
|
||||
let rooms = await getRooms();
|
||||
const response = [];
|
||||
rooms.forEach(room => {
|
||||
if (!room.isStarted && !room.isFull()) {
|
||||
response.push({
|
||||
_id: room._id,
|
||||
private: room.private,
|
||||
name: room.name,
|
||||
players: room.players,
|
||||
isStarted: room.isStarted,
|
||||
});
|
||||
}
|
||||
});
|
||||
sendToOnePlayerRooms(socket.id, response);
|
||||
sendToOnePlayerRooms(socket.id, rooms);
|
||||
};
|
||||
|
||||
socket.on('room:data', getData);
|
||||
socket.on('room:rooms', getAllRooms);
|
||||
const handleCreateRoom = async data => {
|
||||
createNewRoom(data);
|
||||
socket.to(socket.id).emit('room:created');
|
||||
};
|
||||
|
||||
socket.on('room:data', handleGetData);
|
||||
socket.on('room:rooms', handleGetAllRooms);
|
||||
socket.on('room:create', handleCreateRoom);
|
||||
};
|
||||
|
||||
@ -7,7 +7,7 @@ const PlayerSchema = require('./player');
|
||||
|
||||
const RoomSchema = new mongoose.Schema({
|
||||
name: String,
|
||||
private: { type: Boolean, default: true },
|
||||
private: { type: Boolean, default: false },
|
||||
password: String,
|
||||
createDate: { type: Date, default: Date.now },
|
||||
started: { type: Boolean, default: false },
|
||||
|
||||
35
src/components/LoginPage/AddServer/AddServer.css
Normal file
35
src/components/LoginPage/AddServer/AddServer.css
Normal file
@ -0,0 +1,35 @@
|
||||
.refresh {
|
||||
display: flex;
|
||||
margin-left: auto;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 40px;
|
||||
height: 100%;
|
||||
border: 1px solid white;
|
||||
}
|
||||
.refresh > img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.private-container {
|
||||
margin-left: 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
input:disabled {
|
||||
background-color: black;
|
||||
color: #999;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
58
src/components/LoginPage/AddServer/AddServer.jsx
Normal file
58
src/components/LoginPage/AddServer/AddServer.jsx
Normal file
@ -0,0 +1,58 @@
|
||||
import React, { useState, useContext, useEffect } from 'react';
|
||||
import './AddServer.css';
|
||||
import Switch from '@material-ui/core/Switch';
|
||||
import { SocketContext } from '../../../App';
|
||||
const AddServer = () => {
|
||||
const socket = useContext(SocketContext);
|
||||
const [isPrivate, setIsPrivate] = useState(false);
|
||||
const [serverName, setServerName] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
socket.on('room:created', () => {
|
||||
console.log('ewa');
|
||||
socket.emit('room:rooms');
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleButtonClick = e => {
|
||||
e.preventDefault();
|
||||
socket.emit('room:create', {
|
||||
name: serverName,
|
||||
private: isPrivate,
|
||||
password: password,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='lp-container'>
|
||||
<div className='title-container'>
|
||||
<h1>Host A Server</h1>
|
||||
</div>
|
||||
<div className='content-container'>
|
||||
<form>
|
||||
<input
|
||||
type='text'
|
||||
value={serverName}
|
||||
onChange={e => setServerName(e.target.value)}
|
||||
placeholder='Server Name'
|
||||
/>
|
||||
<div className='private-container'>
|
||||
<p>Private</p>
|
||||
<Switch checked={isPrivate} color='primary' onChange={() => setIsPrivate(!isPrivate)} />
|
||||
</div>
|
||||
<input
|
||||
type='text'
|
||||
value={password}
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
placeholder='password'
|
||||
disabled={!isPrivate}
|
||||
/>
|
||||
<button onClick={handleButtonClick}>Host</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddServer;
|
||||
@ -1,76 +1,53 @@
|
||||
.login-page-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
height: 50%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.lp-container {
|
||||
margin: 50px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 50vh;
|
||||
width: 400px;
|
||||
position: relative;
|
||||
width: 500px;
|
||||
padding: 20px;
|
||||
border-radius: 5%;
|
||||
border: 5px solid white;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
h1 {
|
||||
margin-right: 10px;
|
||||
align-self: flex-start;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
color: white;
|
||||
}
|
||||
.rooms {
|
||||
width: 98%;
|
||||
height: 80%;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.room {
|
||||
cursor: pointer;
|
||||
justify-content: space-between;
|
||||
|
||||
.title-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: white;
|
||||
width: 90%;
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.room-selected {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
border: 1px solid white;
|
||||
border-radius: 2px;
|
||||
transform: scaleX(1.02);
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
||||
padding-left: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
.room-selected,
|
||||
.room:hover {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
|
||||
.title-container > h1 {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.number-of-players {
|
||||
|
||||
.content-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
.number-of-players > img {
|
||||
margin-right: 5px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
/* Firefox */
|
||||
* {
|
||||
scrollbar-width: auto;
|
||||
scrollbar-color: #ffffff rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Chrome, Edge, and Safari */
|
||||
*::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background-color: #ffffff;
|
||||
border-radius: 10px;
|
||||
border: 3px none #ffffff;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
||||
border-left: 1px solid black;
|
||||
border-right: 1px solid black;
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
|
||||
@ -1,54 +1,16 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import NameInput from './NameInput/NameInput';
|
||||
import { SocketContext } from '../../App';
|
||||
import './LoginPage.css';
|
||||
import userImage from '../../images/login-page/user.png';
|
||||
import AddServer from './AddServer/AddServer';
|
||||
import ServerList from './ServerList/ServerList';
|
||||
import NameInput from './NameInput/NameInput';
|
||||
const LoginPage = () => {
|
||||
const socket = useContext(SocketContext);
|
||||
const [rooms, setRooms] = useState([]);
|
||||
const [selectedRoom, setSelectedRoom] = useState(null);
|
||||
|
||||
useEffect(async () => {
|
||||
socket.emit('room:rooms');
|
||||
socket.on('room:rooms', data => {
|
||||
data = JSON.parse(data);
|
||||
console.log(data);
|
||||
setRooms(data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='login-page-container'>
|
||||
<h1>Select room:</h1>
|
||||
<div className='rooms'>
|
||||
{rooms.map(room => {
|
||||
return (
|
||||
<div
|
||||
className={selectedRoom && selectedRoom == room._id ? 'room-selected room' : 'room'}
|
||||
onClick={() => {
|
||||
if (selectedRoom && selectedRoom == room._id) {
|
||||
setSelectedRoom(null);
|
||||
} else {
|
||||
setSelectedRoom(room._id);
|
||||
}
|
||||
}}
|
||||
key={room.id}
|
||||
>
|
||||
<div>
|
||||
<p>{room.name}</p>
|
||||
{room.players.map(player => player.name + ' ')}
|
||||
</div>
|
||||
|
||||
<div className='number-of-players'>
|
||||
<img src={userImage} alt='' />
|
||||
<span> {room.players.length}/4 </span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<NameInput />
|
||||
<ServerList />
|
||||
<AddServer />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginPage;
|
||||
|
||||
@ -1,11 +1,34 @@
|
||||
.name-input-container {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
flex-direction: row;
|
||||
width: 80%;
|
||||
flex-direction: column;
|
||||
padding: 10px 20px 60px 20px;
|
||||
width: 300px;
|
||||
background: radial-gradient(circle, rgba(0, 138, 255, 1) 5%, rgba(9, 9, 121, 1) 81%);
|
||||
border: 1px solid white;
|
||||
border-radius: 8px;
|
||||
margin: 20px;
|
||||
}
|
||||
.name-input-container > button {
|
||||
margin-top: 5px;
|
||||
text-align: center;
|
||||
width: 100px;
|
||||
align-self: center;
|
||||
}
|
||||
.name-input-container > input {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.name-overlay {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1;
|
||||
}
|
||||
input,
|
||||
button {
|
||||
padding: 0;
|
||||
@ -21,7 +44,7 @@ input {
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
border: 1px solid #ccc;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
transition: border-color 0.3s ease-in-out, background-color 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
@ -37,7 +60,7 @@ button {
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
color: #fff;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
@ -1,20 +1,45 @@
|
||||
import React, { useState, useContext } from 'react';
|
||||
import React, { useState, useContext, useEffect } from 'react';
|
||||
import { SocketContext } from '../../../App';
|
||||
import './NameInput.css';
|
||||
const NameInput = () => {
|
||||
const NameInput = ({ isRoomPrivate, roomId }) => {
|
||||
const socket = useContext(SocketContext);
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const handleInputChange = e => {
|
||||
setInputValue(e.target.value);
|
||||
};
|
||||
const [nickname, setNickname] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [isPasswordWrong, setIsPasswordWrong] = useState(false);
|
||||
const handleButtonClick = () => {
|
||||
socket.emit('player:login', { name: inputValue });
|
||||
socket.emit('player:login', { name: nickname, password: password, roomId: roomId });
|
||||
};
|
||||
useEffect(() => {
|
||||
socket.on('error:wrongPassword', () => {
|
||||
setIsPasswordWrong(true);
|
||||
});
|
||||
const keyDownHandler = event => {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
handleButtonClick();
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', keyDownHandler);
|
||||
return () => {
|
||||
document.removeEventListener('keydown', keyDownHandler);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="name-input-container">
|
||||
<input placeholder='Enter name' type='text' onChange={handleInputChange} />
|
||||
<div className='name-overlay'>
|
||||
<div className='name-input-container' style={{ height: isRoomPrivate ? '100px' : '50px' }}>
|
||||
<input placeholder='Nickname' type='text' onChange={e => setNickname(e.target.value)} />
|
||||
{isRoomPrivate ? (
|
||||
<input
|
||||
placeholder='Room password'
|
||||
type='text'
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
style={{ backgroundColor: isPasswordWrong ? 'red' : null }}
|
||||
/>
|
||||
) : null}
|
||||
<button onClick={handleButtonClick}>JOIN</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
51
src/components/LoginPage/ServerList/ServerList.css
Normal file
51
src/components/LoginPage/ServerList/ServerList.css
Normal file
@ -0,0 +1,51 @@
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
img {
|
||||
margin-right: 5px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
th,
|
||||
td {
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
height: 50px;
|
||||
}
|
||||
tr {
|
||||
max-height: 50px;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
.server-container {
|
||||
display: flex;
|
||||
height: 500px;
|
||||
overflow: scroll;
|
||||
}
|
||||
.room-name {
|
||||
max-width: 150px;
|
||||
overflow: hidden;
|
||||
}
|
||||
/* Firefox */
|
||||
* {
|
||||
scrollbar-width: auto;
|
||||
scrollbar-color: #ffffff rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Chrome, Edge, and Safari */
|
||||
*::-webkit-scrollbar {
|
||||
background: rgba(0, 0, 0, 0);
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background-color: #ffffff;
|
||||
border-radius: 10px;
|
||||
}
|
||||
79
src/components/LoginPage/ServerList/ServerList.jsx
Normal file
79
src/components/LoginPage/ServerList/ServerList.jsx
Normal file
@ -0,0 +1,79 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { SocketContext } from '../../../App';
|
||||
import lock from '../../../images/login-page/lock.png';
|
||||
import refresh from '../../../images/login-page/refresh.png';
|
||||
import ReactLoading from 'react-loading';
|
||||
|
||||
import './ServerList.css';
|
||||
import NameInput from '../NameInput/NameInput';
|
||||
|
||||
const ServerList = () => {
|
||||
const socket = useContext(SocketContext);
|
||||
const [rooms, setRooms] = useState([]);
|
||||
const [joining, setJoining] = useState(false);
|
||||
const [clickedRoom, setClickedRoom] = useState(null);
|
||||
useEffect(async () => {
|
||||
socket.emit('room:rooms');
|
||||
socket.on('room:rooms', data => {
|
||||
data = JSON.parse(data);
|
||||
setRooms(data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const getRooms = () => {
|
||||
setRooms(null);
|
||||
socket.emit('room:rooms');
|
||||
};
|
||||
|
||||
const handleJoinClick = room => {
|
||||
setClickedRoom(room);
|
||||
setJoining(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='lp-container'>
|
||||
<div className='title-container'>
|
||||
<h1>Server List</h1>
|
||||
<div className='refresh'>
|
||||
<img src={refresh} onClick={getRooms}></img>
|
||||
</div>
|
||||
</div>
|
||||
<div className='server-container content-container'>
|
||||
{rooms ? (
|
||||
<table className='rooms'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Server</th>
|
||||
<th>#/#</th>
|
||||
<th>Status</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rooms.map((room, index) => (
|
||||
<tr key={index}>
|
||||
<td>{room.private ? <img src={lock} /> : null}</td>
|
||||
<td className='room-name'>{room.name}</td>
|
||||
<td>{`${room.players.length}/4`}</td>
|
||||
<td>{room.isStarted ? 'started' : 'waiting'}</td>
|
||||
<td>
|
||||
<button onClick={() => handleJoinClick(room)}>Join</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
) : (
|
||||
<div style={{ alignSelf: 'center' }}>
|
||||
<ReactLoading type='spinningBubbles' color='white' height={50} width={50} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{joining ? (
|
||||
<NameInput roomId={clickedRoom._id} isRoomPrivate={clickedRoom.private} />
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default ServerList;
|
||||
@ -14,7 +14,7 @@ const AnimatedOverlay = ({ time }) => {
|
||||
in={true}
|
||||
timeout={0}
|
||||
classNames='overlay'
|
||||
style={{ 'animation-delay': `-${animationDelay}s` }}
|
||||
style={{ animationDelay: `-${animationDelay}s` }}
|
||||
unmountOnExit
|
||||
>
|
||||
<div className='overlay'></div>
|
||||
|
||||
BIN
src/images/login-page/lock.png
Normal file
BIN
src/images/login-page/lock.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
src/images/login-page/refresh.png
Normal file
BIN
src/images/login-page/refresh.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 8.9 KiB |
Loading…
Reference in New Issue
Block a user