++
- Can now join games - Can continue games using table - Can create accounts - Can create Games
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
"axios": "^1.7.9",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-router-dom": "^7.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -23,6 +23,8 @@ body {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.btn {
|
||||
background-color: #764ACB;
|
||||
color: #f0f0f5;
|
||||
|
||||
+40
-34
@@ -1,5 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import './App.css';
|
||||
import Header from './components/header';
|
||||
import Home from './pages/home';
|
||||
@@ -7,6 +8,7 @@ import Login from './pages/login';
|
||||
import Register from './pages/register';
|
||||
import JoinGame from './pages/joinGame';
|
||||
import StartGame from './pages/startGame';
|
||||
import { UserProvider } from './context/UserContext.jsx';
|
||||
|
||||
function App() {
|
||||
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||||
@@ -18,41 +20,45 @@ function App() {
|
||||
};
|
||||
|
||||
return (
|
||||
<Router>
|
||||
<div>
|
||||
{popupMessage && <div className="popup">{popupMessage}</div>}
|
||||
<UserProvider>
|
||||
<meta name="DND Master" content="WoW. A description."/>
|
||||
<Router>
|
||||
<div>
|
||||
<Helmet>
|
||||
<title>DND Master</title>
|
||||
</Helmet>
|
||||
{popupMessage && <div className="popup">{popupMessage}</div>}
|
||||
<Header isLoggedIn={isLoggedIn} />
|
||||
|
||||
{/* Header is placed at the top of the page */}
|
||||
<Header isLoggedIn={isLoggedIn} />
|
||||
|
||||
<Routes>
|
||||
<Route
|
||||
path="/"
|
||||
element={<Home isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} />}
|
||||
/>
|
||||
<Route
|
||||
path="/login"
|
||||
element={<Login setIsLoggedIn={setIsLoggedIn} />}
|
||||
/>
|
||||
<Route
|
||||
path="/register"
|
||||
element={<Register setIsLoggedIn={(status) => {
|
||||
setIsLoggedIn(status);
|
||||
showPopup('User registered successfully!');
|
||||
}} />}
|
||||
/>
|
||||
<Route
|
||||
path="joinGame"
|
||||
element={<JoinGame isLoggedIn={isLoggedIn} />}
|
||||
/>
|
||||
<Route
|
||||
path="/startGame"
|
||||
element={<StartGame isLoggedIn={isLoggedIn} />}
|
||||
/>
|
||||
</Routes>
|
||||
</div>
|
||||
</Router>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/"
|
||||
element={<Home isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} />}
|
||||
/>
|
||||
<Route
|
||||
path="/login"
|
||||
element={<Login setIsLoggedIn={setIsLoggedIn} />}
|
||||
/>
|
||||
<Route
|
||||
path="/register"
|
||||
element={<Register setIsLoggedIn={(status) => {
|
||||
setIsLoggedIn(status);
|
||||
showPopup('User registered successfully!');
|
||||
}} />}
|
||||
/>
|
||||
<Route
|
||||
path="joinGame"
|
||||
element={<JoinGame isLoggedIn={isLoggedIn} />}
|
||||
/>
|
||||
<Route
|
||||
path="/startGame"
|
||||
element={<StartGame isLoggedIn={isLoggedIn} />}
|
||||
/>
|
||||
</Routes>
|
||||
</div>
|
||||
</Router>
|
||||
</UserProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
export default App;
|
||||
@@ -0,0 +1,13 @@
|
||||
import React, { createContext, useState } from 'react';
|
||||
|
||||
export const UserContext = createContext();
|
||||
|
||||
export const UserProvider = ({ children }) => {
|
||||
const [userId, setUserId] = useState(null);
|
||||
|
||||
return (
|
||||
<UserContext.Provider value={{ userId, setUserId }}>
|
||||
{children}
|
||||
</UserContext.Provider>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
.container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
|
||||
align-self: center;
|
||||
flex-direction: row;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.button-group .btn {
|
||||
margin-bottom: 10px;
|
||||
padding: 10px 20px;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.games-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 20px;
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.games-table th, .games-table td {
|
||||
border: 1px solid #555;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.games-table th {
|
||||
background-color: #444;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.games-table tr:nth-child(even) {
|
||||
background-color: #3a3a3a;
|
||||
}
|
||||
|
||||
.games-table tr:hover {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
.game-link {
|
||||
color: #1e90ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.game-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
@@ -1,8 +1,25 @@
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { useNavigate, Link } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
import { UserContext } from '../context/UserContext';
|
||||
import './home.css';
|
||||
|
||||
function Home({ isLoggedIn, setIsLoggedIn }) {
|
||||
const navigate = useNavigate();
|
||||
const [games, setGames] = useState([]);
|
||||
const { userId } = useContext(UserContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoggedIn && userId) {
|
||||
axios.get(`http://localhost:5000/games/${userId}`)
|
||||
.then(response => {
|
||||
setGames(response.data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching games:', error);
|
||||
});
|
||||
}
|
||||
}, [isLoggedIn, userId]);
|
||||
|
||||
const handleLogout = () => {
|
||||
setIsLoggedIn(false);
|
||||
@@ -10,21 +27,48 @@ function Home({ isLoggedIn, setIsLoggedIn }) {
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<h2>Welcome to the Game</h2>
|
||||
<h2>Welcome to the Site</h2>
|
||||
{!isLoggedIn ? (
|
||||
<div className="button-group">
|
||||
<button className="btn" onClick={() => navigate('/login')}>Login</button>
|
||||
<button className="btn" onClick={() => navigate('/register')}>Register</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="button-group">
|
||||
<button className="btn" onClick={() => navigate('/startGame')}>Start Game</button>
|
||||
<button className="btn" onClick={() => navigate('/joinGame')}>Join Game</button>
|
||||
<button className="btn" onClick={handleLogout}>Logout</button>
|
||||
<div className="content">
|
||||
<div className="button-group">
|
||||
<button className="btn" onClick={() => navigate('/startGame')}>Start Game</button>
|
||||
<button className="btn" onClick={() => navigate('/joinGame')}>Join Game</button>
|
||||
<button className="btn" onClick={handleLogout}>Logout</button>
|
||||
</div>
|
||||
<div className="table-container">
|
||||
<h3>Your Games</h3>
|
||||
<table className="games-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Game ID</th>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{games.map(game => (
|
||||
<tr key={game.game_id}>
|
||||
<td>
|
||||
<Link to={`/games/${game.game_id}`} className="game-link">
|
||||
{game.game_id}
|
||||
</Link>
|
||||
</td>
|
||||
<td>{game.name}</td>
|
||||
<td>{game.description}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Home;
|
||||
export default Home;
|
||||
@@ -1,20 +1,16 @@
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useContext } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
import { UserContext } from '../context/UserContext';
|
||||
|
||||
const JoinGamePage = () => {
|
||||
const [gameCode, setGameCode] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Mock function to check if game exists (replace with your real logic)
|
||||
const checkGameExists = (code) => {
|
||||
const availableGames = ['game123', 'game456', 'game789']; // Example game codes
|
||||
return availableGames.includes(code);
|
||||
};
|
||||
const { userId } = useContext(UserContext);
|
||||
|
||||
// Handle form submission
|
||||
const handleJoinGame = (e) => {
|
||||
const handleJoinGame = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (gameCode.trim() === '') {
|
||||
@@ -22,14 +18,16 @@ const JoinGamePage = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkGameExists(gameCode)) {
|
||||
// Simulate adding user to the game (replace with your actual logic)
|
||||
setError('');
|
||||
setTimeout(() => {
|
||||
navigate('/games'); // Redirect to the games page
|
||||
}, 1000);
|
||||
} else {
|
||||
setError('Game not found!');
|
||||
try {
|
||||
const response = await axios.post(`http://localhost:5000/joinGame/${gameCode}`, { userId });
|
||||
if (response.status === 201) {
|
||||
setError('');
|
||||
navigate(`/games/${gameCode}`); // Redirect to the games page
|
||||
} else {
|
||||
setError('Failed to join the game.');
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err.response ? err.response.data.error : 'Error joining the game');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -50,4 +48,4 @@ const JoinGamePage = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default JoinGamePage;
|
||||
export default JoinGamePage;
|
||||
@@ -1,22 +1,29 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useContext } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
import { UserContext } from '../context/UserContext';
|
||||
|
||||
function Login({ setIsLoggedIn }) {
|
||||
const [username, setUsername] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [message, setMessage] = useState('');
|
||||
const navigate = useNavigate();
|
||||
const { setUserId } = useContext(UserContext);
|
||||
|
||||
const handleLogin = async (e) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
const res = await axios.post('http://localhost:5000/login', { username, password });
|
||||
setMessage(res.data.message);
|
||||
setIsLoggedIn(true);
|
||||
navigate('/');
|
||||
if (res.data.success) {
|
||||
setIsLoggedIn(true);
|
||||
setUserId(res.data.userId);
|
||||
navigate('/');
|
||||
} else {
|
||||
setMessage(res.data.message);
|
||||
}
|
||||
} catch (err) {
|
||||
setMessage(err.response.data.error);
|
||||
setMessage(err.response ? err.response.data.error : 'Error logging in');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ const startGame = () => {
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
description,
|
||||
gameMasterId: 1, // Placeholder for game master ID; replace with dynamic value if needed
|
||||
participants: [], // Default empty participants array
|
||||
gameMasterId: 1,
|
||||
participants: [],
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
+21
-1
@@ -1858,7 +1858,7 @@ prelude-ls@^1.2.1:
|
||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
||||
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
|
||||
|
||||
prop-types@^15.8.1:
|
||||
prop-types@^15.7.2, prop-types@^15.8.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
@@ -1885,6 +1885,21 @@ react-dom@^18.3.1:
|
||||
loose-envify "^1.1.0"
|
||||
scheduler "^0.23.2"
|
||||
|
||||
react-fast-compare@^3.1.1:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49"
|
||||
integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==
|
||||
|
||||
react-helmet@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726"
|
||||
integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==
|
||||
dependencies:
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.7.2"
|
||||
react-fast-compare "^3.1.1"
|
||||
react-side-effect "^2.1.0"
|
||||
|
||||
react-is@^16.13.1:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
@@ -1912,6 +1927,11 @@ react-router@7.0.2:
|
||||
set-cookie-parser "^2.6.0"
|
||||
turbo-stream "2.4.0"
|
||||
|
||||
react-side-effect@^2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.2.tgz#dc6345b9e8f9906dc2eeb68700b615e0b4fe752a"
|
||||
integrity sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==
|
||||
|
||||
react@^18.3.1:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
|
||||
|
||||
Reference in New Issue
Block a user