diff --git a/backend/handlers/roomHandler.js b/backend/handlers/roomHandler.js index bfdeef3..5630cc0 100644 --- a/backend/handlers/roomHandler.js +++ b/backend/handlers/roomHandler.js @@ -15,5 +15,25 @@ module.exports = (io, socket) => { io.to(socket.id).emit('room:data', JSON.stringify(room)); } }; + + const getRooms = async () => { + let rooms = await RoomModel.find({}); + const response = []; + rooms.forEach(room => { + if (!room.isStarted && !room.isFull()) { + response.push({ + _id: room._id, + name: room.name, + players: room.players, + isStarted: room.isStarted, + }); + } + }); + io.to(socket.id).emit('room:rooms', JSON.stringify(response)); + }; + + + socket.on('room:data', getData); + socket.on('room:rooms', getRooms); }; diff --git a/backend/schemas/room.js b/backend/schemas/room.js index e171950..90379b6 100644 --- a/backend/schemas/room.js +++ b/backend/schemas/room.js @@ -6,6 +6,7 @@ const PawnSchema = require('./pawn'); const PlayerSchema = require('./player'); const RoomSchema = new Schema({ + name: String, createDate: { type: Date, default: Date.now }, started: { type: Boolean, default: false }, full: { type: Boolean, default: false }, @@ -66,6 +67,7 @@ RoomSchema.methods.startGame = function () { this.nextMoveTime = Date.now() + 15000; this.players.forEach(player => (player.ready = true)); this.players[0].nowMoving = true; + this.timeoutID = setTimeout(makeRandomMove, 15000, this); }; RoomSchema.methods.isFull = function () { diff --git a/backend/server.js b/backend/server.js index fb85acb..21341f1 100644 --- a/backend/server.js +++ b/backend/server.js @@ -91,4 +91,4 @@ if (process.env.NODE_ENV === 'production') { }); } -module.exports = { server }; \ No newline at end of file +module.exports = { server }; diff --git a/src/App.js b/src/App.js index fa208b4..770998b 100644 --- a/src/App.js +++ b/src/App.js @@ -1,9 +1,9 @@ import React, { useEffect, useState, createContext } from 'react'; import { io } from 'socket.io-client'; import { BrowserRouter as Router, Route, Redirect, Switch } from 'react-router-dom'; - +import ReactLoading from 'react-loading'; import Gameboard from './components/Gameboard'; -import NameInput from './components/NameInput'; +import LoginPage from './components/LoginPage/LoginPage'; export const PlayerDataContext = createContext(); export const SocketContext = createContext(); @@ -32,7 +32,11 @@ function App() { LOADING... - + {playerSocket ? ( + + ) : ( + + )} {playerData ? ( diff --git a/src/components/LoginPage/LoginPage.css b/src/components/LoginPage/LoginPage.css new file mode 100644 index 0000000..62099aa --- /dev/null +++ b/src/components/LoginPage/LoginPage.css @@ -0,0 +1,76 @@ +.login-page-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 50vh; + width: 400px; + position: relative; + 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; + display: flex; + flex-direction: row; + align-items: center; + color: white; + width: 90%; + margin: 10px; + padding: 10px; + border: 1px solid black; +} +.room-selected { + border: 1px solid white; +} +.room-selected, +.room:hover { + background-color: rgba(0, 0, 0, 0.5); +} +.number-of-players { + 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; +} diff --git a/src/components/LoginPage/LoginPage.jsx b/src/components/LoginPage/LoginPage.jsx new file mode 100644 index 0000000..835787d --- /dev/null +++ b/src/components/LoginPage/LoginPage.jsx @@ -0,0 +1,54 @@ +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'; +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 ( +
+

Select room:

+
+ {rooms.map(room => { + return ( +
{ + if (selectedRoom && selectedRoom == room._id) { + setSelectedRoom(null); + } else { + setSelectedRoom(room._id); + } + }} + key={room.id} + > +
+

{room.name}

+ {room.players.map(player => player.name + ' ')} +
+ +
+ + {room.players.length}/4 +
+
+ ); + })} +
+ +
+ ); +}; +export default LoginPage; diff --git a/src/components/LoginPage/NameInput/NameInput.css b/src/components/LoginPage/NameInput/NameInput.css new file mode 100644 index 0000000..f7509fe --- /dev/null +++ b/src/components/LoginPage/NameInput/NameInput.css @@ -0,0 +1,47 @@ +.name-input-container { + display: flex; + position: absolute; + bottom: 0; + flex-direction: row; + width: 80%; + margin: 20px; +} +input, +button { + padding: 0; + border: none; + outline: none; + box-sizing: border-box; +} + +input { + width: 100%; + padding: 12px; + font-size: 16px; + border-radius: 8px; + color: white; + border: 1px solid #ccc; + background-color: rgba(0, 0, 0, 0.5); + transition: border-color 0.3s ease-in-out, background-color 0.3s ease-in-out; +} + +input:focus { + color: black; + border-color: #4a90e2; + background-color: #fff; +} + +button { + padding: 12px 20px; + font-size: 16px; + border-radius: 8px; + border: none; + color: #fff; + background-color: rgba(0, 0, 0, 0.5); + cursor: pointer; + transition: background-color 0.3s ease-in-out; +} + +button:hover { + background-color: rgba(0, 0, 0, 1); +} diff --git a/src/components/LoginPage/NameInput/NameInput.jsx b/src/components/LoginPage/NameInput/NameInput.jsx new file mode 100644 index 0000000..491c56b --- /dev/null +++ b/src/components/LoginPage/NameInput/NameInput.jsx @@ -0,0 +1,21 @@ +import React, { useState, useContext } from 'react'; +import { SocketContext } from '../../../App'; +import './NameInput.css'; +const NameInput = () => { + const socket = useContext(SocketContext); + const [inputValue, setInputValue] = useState(''); + const handleInputChange = e => { + setInputValue(e.target.value); + }; + const handleButtonClick = () => { + socket.emit('player:login', { name: inputValue }); + }; + return ( +
+ + +
+ ); +}; + +export default NameInput; diff --git a/src/components/NameInput.jsx b/src/components/NameInput.jsx deleted file mode 100644 index 9f4d1eb..0000000 --- a/src/components/NameInput.jsx +++ /dev/null @@ -1,25 +0,0 @@ -import React, { useState, useContext } from "react"; -import { SocketContext } from "../App"; - -const NameInput = () => { - const socket = useContext(SocketContext); - const [inputValue, setInputValue] = useState(""); - const handleInputChange = (e) => { - setInputValue(e.target.value); - }; - const handleButtonClick = () => { - socket.emit("player:login", { name: inputValue }); - }; - return ( -
- - -
- ); -}; - -export default NameInput; diff --git a/src/images/login-page/user.png b/src/images/login-page/user.png new file mode 100644 index 0000000..6d15e9e Binary files /dev/null and b/src/images/login-page/user.png differ