Skip to content

Commit

Permalink
refactor: use react-router for frontend navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
mrm1st3r authored and stoerti committed Sep 22, 2024
1 parent 3905ce3 commit dd1b8a1
Show file tree
Hide file tree
Showing 14 changed files with 187 additions and 111 deletions.
40 changes: 40 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
"react": "^18.3.1",
"react-countdown": "^2.3.5",
"react-dom": "^18.3.1",
"react-router": "^6.26.2",
"react-router-dom": "^6.26.2",
"react-stomp": "^5.1.0",
"sockjs": "^0.3.24",
"typescript": "^5.5.3",
Expand All @@ -40,4 +42,4 @@
"vite": "5.3.4",
"vitest": "2.0.3"
}
}
}
6 changes: 3 additions & 3 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';

import {SnackbarProvider} from 'material-ui-snackbar-provider'

import QuizmaniaMainUI from "./pages/QuizmaniaMainUI";
import {createTheme, CssBaseline, ThemeProvider} from "@mui/material";
import {RouterProvider} from "react-router";
import {router} from "./router.tsx";

const App = () => {
const theme = createTheme({
Expand Down Expand Up @@ -86,7 +86,7 @@ const App = () => {
<ThemeProvider theme={theme}>
<CssBaseline/>
<SnackbarProvider SnackbarProps={{autoHideDuration: 4000}}>
<QuizmaniaMainUI/>
<RouterProvider router={router}/>
</SnackbarProvider>
</ThemeProvider>
</div>
Expand Down
21 changes: 21 additions & 0 deletions frontend/src/hooks/useUsername.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Cookies from "js-cookie";

const username = () => {
return Cookies.get('username')
}

const setUsername = (username: string) => {
Cookies.set('username', username)
}

const removeUsername = () => {
Cookies.remove('username');
}

export const useUsername = () => {
return {
username: username(),
setUsername,
removeUsername
}
};
35 changes: 24 additions & 11 deletions frontend/src/pages/GameSelectionPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,20 @@ import {AppBar, Box, IconButton, Table, TableBody, TableCell, TableHead, TableRo
import Add from "@mui/icons-material/Add"
import Login from "@mui/icons-material/Login"
import Refresh from "@mui/icons-material/Refresh"
import React, {useEffect} from "react";
import React, {useCallback, useEffect} from "react";
import {GameCreationDialog} from "./GameCreationDialog";
import {useSnackbar} from "material-ui-snackbar-provider";
import {GameAlreadyFullException, gameCommandService, GameException, NewGameCommand, UsernameAlreadyTakenException} from "../services/GameCommandService";
import {TransferWithinAStation, Visibility} from "@mui/icons-material";
import {GameDto, gameOverviewService, GameStatus} from "../services/GameOverviewService";
import {useNavigate} from "react-router";
import { useUsername } from "../hooks/useUsername";

type GameSelectionContainerProps = {
games: GameDto[]
onButtonClickJoinGame: (gameId: string) => void
onButtonClickJoinGameAsSpectator: (gameId: string) => void
}
type GameSelectionPageProps = {
onGameSelected: (gameId: string) => void
onLogout: () => void
}


const GameSelectionContainer = (props: GameSelectionContainerProps) => {

Expand Down Expand Up @@ -74,17 +71,33 @@ const GameSelectionContainer = (props: GameSelectionContainerProps) => {
</Box>
)
}
const GameSelectionPage = (props: GameSelectionPageProps) => {
const GameSelectionPage = () => {

const navigate = useNavigate()
const {username} = useUsername();

const [newGameDialogOpen, setNewGameDialogOpen] = React.useState(false)
const [games, setGames] = React.useState<GameDto[]>([])

const snackbar = useSnackbar()

useEffect(() => {if (username === undefined) {
console.log('no username set, redirect to login');
navigate('/login');
}}, [username]);

useEffect(() => {
gameOverviewService.searchOpenGames(setGames)
}, []);

const onGameSelected = useCallback((gameId: string) => {
navigate(`/game/${gameId}`)
}, [navigate])

const onLogout = () => {
navigate('/logout');
}

const onButtonClickNewGame = () => {
setNewGameDialogOpen(true)
}
Expand All @@ -96,7 +109,7 @@ const GameSelectionPage = (props: GameSelectionPageProps) => {
const onButtonClickJoinGame = async (gameId: string) => {
try {
await gameCommandService.joinGame(gameId)
props.onGameSelected(gameId)
onGameSelected(gameId)
} catch (error) {
if (error instanceof GameAlreadyFullException) {
snackbar.showMessage("The selected game is already full")
Expand All @@ -108,7 +121,7 @@ const GameSelectionPage = (props: GameSelectionPageProps) => {
}
}
const onButtonClickJoinGameAsSpectator = async (gameId: string) => {
props.onGameSelected(gameId)
onGameSelected(gameId)
}

const onCloseNewGameDialog = () => {
Expand All @@ -118,7 +131,7 @@ const GameSelectionPage = (props: GameSelectionPageProps) => {
const onCreateNewGame = async (newGame: NewGameCommand) => {
try {
const gameId = await gameCommandService.createNewGame(newGame)
props.onGameSelected(gameId)
onGameSelected(gameId)
snackbar.showMessage(
`Created game ${newGame.name} for ${newGame.config.maxPlayers} players, ${newGame.config.numQuestions} questions and ${newGame.withModerator ? 'with' : 'without'} moderator`
)
Expand Down Expand Up @@ -148,7 +161,7 @@ const GameSelectionPage = (props: GameSelectionPageProps) => {
Games
</Typography>
<Tooltip title="Change username">
<IconButton id="changeUsername" color="inherit" onClick={props.onLogout}>
<IconButton id="changeUsername" color="inherit" onClick={onLogout}>
<TransferWithinAStation/>
</IconButton>
</Tooltip>
Expand Down
24 changes: 19 additions & 5 deletions frontend/src/pages/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
import {Box, Button, CssBaseline, Grid, Paper, TextField} from "@mui/material";
import React from "react";
import React, {useEffect} from "react";
import {useUsername} from "../hooks/useUsername.ts";
import {useNavigate} from "react-router";

const LoginPage = () => {

const {username, setUsername} = useUsername();
const navigate = useNavigate();

useEffect(() => {
if (username !== undefined) {
console.log('already logged in as', username, 'continue to overview')
navigate('/');
}
}, [username, navigate]);

const loginSuccessAction = (username: string) => {
setUsername(username);
navigate('/');
}

type LoginPageProps = {
loginSuccessAction: (username: string) => void
}
const LoginPage = ({loginSuccessAction}: LoginPageProps) => {
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
Expand Down
21 changes: 21 additions & 0 deletions frontend/src/pages/LogoutPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {useUsername} from "../hooks/useUsername.ts";
import {useNavigate} from "react-router";
import React, {useEffect} from "react";

/**
* component without UI, just to encapsulate the logout process.
*/
const LogoutPage = () => {
const {removeUsername} = useUsername();
const navigate = useNavigate();

useEffect(() => {
console.log('logging out...')
removeUsername()
navigate('/')
}, []);

return <>logging out...</>
}

export default LogoutPage;
74 changes: 0 additions & 74 deletions frontend/src/pages/QuizmaniaMainUI.tsx

This file was deleted.

7 changes: 4 additions & 3 deletions frontend/src/pages/game/GameLobby.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {gameCommandService, GameCommandService, GameException} from "../../services/GameCommandService";
import Cookies from "js-cookie";
import {gameCommandService, GameException} from "../../services/GameCommandService";
import {
AppBar,
Button,
Expand All @@ -20,13 +19,15 @@ import Person from "@mui/icons-material/Person";
import React from "react";
import {Game} from "../../domain/GameModel";
import {useSnackbar} from "material-ui-snackbar-provider";
import {useUsername} from "../../hooks/useUsername.ts";

export type GameLobbyPageProps = {
game: Game,
}

export const GameLobbyPage = (props: GameLobbyPageProps) => {
const snackbar = useSnackbar()
const {username} = useUsername()

const onClickLeaveGame = async () => {
try {
Expand All @@ -49,7 +50,7 @@ export const GameLobbyPage = (props: GameLobbyPageProps) => {
}

let startButton;
if (props.game.moderator === Cookies.get('username') || props.game.creator === Cookies.get('username')) {
if (props.game.moderator === username || props.game.creator === username) {
startButton = <div
style={{
display: "flex",
Expand Down
Loading

0 comments on commit dd1b8a1

Please sign in to comment.