added joining to room
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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 className='login-page-container'>
|
||||
<ServerList />
|
||||
<AddServer />
|
||||
</div>
|
||||
<NameInput />
|
||||
</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,19 +1,44 @@
|
||||
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} />
|
||||
<button onClick={handleButtonClick}>JOIN</button>
|
||||
<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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
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 |
Reference in New Issue
Block a user