Universal login and appbar improvements

This commit is contained in:
Felix Albrigtsen 2022-04-24 13:01:19 +02:00
parent cef7cfd1a7
commit 2c06a8adb2
10 changed files with 89 additions and 70 deletions

View File

@ -199,48 +199,18 @@ function Home(props) {
} }
// class LoginManager {
// checkLogin() {
// fetch(process.env.REACT_APP_API_URL + `/users/getSavedUser`)
// .then(res => res.json())
// .then(data => {
// if (data.status !== "OK") {
// console.error(data.data);
// return;
// }
// console.log(data);
// setUser(data.data);
// return user;
// })
// .catch((err) => console.log(err.message));
// }
// isLoggedIn() {
// let loggedIn = user.googleId !== "" && user.asuraId !== -1;
// console.log(loggedIn);
// return loggedIn;
// }
// isManager() {
// return this.isLoggedIn() && user.isManager;
// }
// }
// let login = new LoginManager();
// login.checkLogin();
let showSuccess = (message) => {}; let showSuccess = (message) => {};
let showError = (message) => {}; let showError = (message) => {};
export default function App() { export default function App() {
const [user, setUser] = React.useState({}); const [user, setUser] = React.useState({});
let checkLogin = () => { let fetchUser = () => {
fetch(process.env.REACT_APP_API_URL + `/users/getSavedUser`) fetch(process.env.REACT_APP_API_URL + `/users/getSavedUser`)
.then(res => res.json()) .then(res => res.json())
.then(data => { .then(data => {
if (data.status !== "OK") { if (data.status !== "OK") {
setUser({ isManager: false, isLoggedIn: false }); setUser({ isManager: false, isLoggedIn: false });
console.log(data.data); console.log(data.data); // "No user logged in"
return; return;
} }
let u = data.data; let u = data.data;
@ -255,7 +225,7 @@ export default function App() {
} }
React.useEffect(() => { React.useEffect(() => {
checkLogin(); fetchUser();
}, []); }, []);
const [openError, setOpenError] = React.useState(false); const [openError, setOpenError] = React.useState(false);

View File

@ -6,12 +6,20 @@ import ErrorSnackbar from "./components/ErrorSnackbar";
import {Button, Textfield, Stack, InputLabel, Paper, Typography} from '@mui/material'; import {Button, Textfield, Stack, InputLabel, Paper, Typography} from '@mui/material';
export default function LoginPage(props) { export default function LoginPage(props) {
if (props.user.isLoggedIn) {
//Redirect to the front page if the user is logged in
window.location.href = "/";
return;
}
return ( return (
<> <>
<Appbar user={props.user} pageTitle="Sign in" /> <Appbar user={props.user} pageTitle="Login" />
<Paper x={{width: "70vw", margin: "1.5% auto"}} component={Stack} direction="column" justifyContent="center" alignItems="center"> <Paper sx={{width: "70vw", margin: "1.5% auto"}} component={Stack} direction="column" justifyContent="center" alignItems="center">
<Typography variant="h4" component="h4">
You must be logged in to access administrator features.
</Typography>
<Stack direction="column" paddingTop={'0.5%'} alignItems={'center'}> <Stack direction="column" paddingTop={'0.5%'} alignItems={'center'}>
<Typography>Sign in with google</Typography>
<a href={process.env.REACT_APP_LOGIN_URL}> <a href={process.env.REACT_APP_LOGIN_URL}>
<img src="/btn_google_signing_dark.png" alt="Sign in with google" /> <img src="/btn_google_signing_dark.png" alt="Sign in with google" />
</a> </a>

View File

@ -5,6 +5,7 @@ import AddCircleIcon from '@mui/icons-material/AddCircle';
import KeyboardDoubleArrowDownIcon from '@mui/icons-material/KeyboardDoubleArrowDown'; import KeyboardDoubleArrowDownIcon from '@mui/icons-material/KeyboardDoubleArrowDown';
import KeyboardDoubleArrowUpIcon from '@mui/icons-material/KeyboardDoubleArrowUp'; import KeyboardDoubleArrowUpIcon from '@mui/icons-material/KeyboardDoubleArrowUp';
import Appbar from './components/AsuraBar'; import Appbar from './components/AsuraBar';
import LoginPage from './LoginPage';
import EmojiEventsIcon from '@mui/icons-material/EmojiEvents'; import EmojiEventsIcon from '@mui/icons-material/EmojiEvents';
@ -143,10 +144,11 @@ function shorten(description, maxLength) {
</>; </>;
} }
export default function TournamentHistory() { export default function TournamentHistory(props) {
if (!props.user.isLoggedIn) { return <LoginPage user={props.user} />; }
return ( return (
<> <>
<Appbar pageTitle="Tournament History" /> <Appbar user={props.user} pageTitle="Tournament History" />
<Container sx={{minHeight: "30vh", width: "90vw", padding: "20px 20px"}} component={Container} direction="column" align="center"> <Container sx={{minHeight: "30vh", width: "90vw", padding: "20px 20px"}} component={Container} direction="column" align="center">
<Box component={Stack} direction="row" align="center" justifyContent="space-between" alignItems="center" sx={{flexGrow: 1}}> <Box component={Stack} direction="row" align="center" justifyContent="space-between" alignItems="center" sx={{flexGrow: 1}}>
<Typography variant="h3">Past Tournaments</Typography> <Typography variant="h3">Past Tournaments</Typography>

View File

@ -3,6 +3,7 @@ import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom";
// import { AlertContainer, alert } from "react-custom-alert"; // import { AlertContainer, alert } from "react-custom-alert";
import Appbar from "./components/AsuraBar"; import Appbar from "./components/AsuraBar";
import TournamentBar from "./components/TournamentBar"; import TournamentBar from "./components/TournamentBar";
import LoginPage from "./LoginPage";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { Button, TextField, Grid, Box, Container, Paper, Stack } from "@mui/material"; import { Button, TextField, Grid, Box, Container, Paper, Stack } from "@mui/material";
import { Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from "@mui/material"; import { Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from "@mui/material";
@ -220,6 +221,11 @@ export default function TournamentManager(props) {
showError = props.showError; showError = props.showError;
showSuccess = props.showSuccess; showSuccess = props.showSuccess;
if (!props.user.isLoggedIn) {
return <LoginPage user={props.user} />;
}
return ( return (
<> <>
<Appbar user={props.user} pageTitle="Edit Tournament" /> <Appbar user={props.user} pageTitle="Edit Tournament" />

View File

@ -2,6 +2,7 @@ import * as React from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import Appbar from './components/AsuraBar'; import Appbar from './components/AsuraBar';
import TournamentBar from "./components/TournamentBar"; import TournamentBar from "./components/TournamentBar";
import ErrorSnackbar from "./components/ErrorSnackbar";
import { useParams } from 'react-router-dom' import { useParams } from 'react-router-dom'
import { Button, IconButton, Paper, Stack, CircularProgress, Box, Grid, Typography, Container } from "@mui/material"; import { Button, IconButton, Paper, Stack, CircularProgress, Box, Grid, Typography, Container } from "@mui/material";
import "./components/tournamentBracket.css"; import "./components/tournamentBracket.css";
@ -10,17 +11,11 @@ import DoDisturbIcon from '@mui/icons-material/DoDisturb';
import BackspaceIcon from '@mui/icons-material/Backspace'; import BackspaceIcon from '@mui/icons-material/Backspace';
import AddCircleIcon from '@mui/icons-material/AddCircle'; import AddCircleIcon from '@mui/icons-material/AddCircle';
function showError(error) {
alert("Something went wrong. \n" + error);
console.error(error);
}
function TournamentTier(props){ function TournamentTier(props){
let roundTypes = ["winner","finals", "semifinals", "quarterfinals", "eighthfinals", "sixteenthfinals", "thirtysecondfinals"]; let roundTypes = ["winner","finals", "semifinals", "quarterfinals", "eighthfinals", "sixteenthfinals", "thirtysecondfinals"];
let matches = []; let matches = [];
for (let i = 0; i < props.matches.length; i++) { for (let i = 0; i < props.matches.length; i++) {
matches.push(<Match tournament={props.tournament} teams={props.teams} match={props.matches[i]} key={i} />); matches.push(<Match tournament={props.tournament} user={props.user} teams={props.teams} match={props.matches[i]} key={i} />);
} }
return( return(
<ul className={`round ${roundTypes[props.tier]}`}> <ul className={`round ${roundTypes[props.tier]}`}>
@ -94,11 +89,11 @@ function Match(props){
<Typography className={`teamName`} align={'center'} sx={{fontSize:'1.5rem', maxWidth:'15vw', overflow:'hidden', wordWrap:'none'}}> <Typography className={`teamName`} align={'center'} sx={{fontSize:'1.5rem', maxWidth:'15vw', overflow:'hidden', wordWrap:'none'}}>
{team1Name} {team1Name}
</Typography> </Typography>
{ props.match.team1Id !== null && !props.tournament.hasEnded && props.match.tier !== Math.log2(props.tournament.teamLimit) - 1 && props.match.winnerId === null ? { props.match.team1Id !== null && !props.tournament.hasEnded && props.match.tier !== Math.log2(props.tournament.teamLimit) - 1 && props.match.winnerId === null && props.user.isLoggedIn &&
<IconButton color="error" aria-label="remmove winner" component="span" onClick={curryUnsetContestant(props.match.team1Id)}><BackspaceIcon /></IconButton> : null <IconButton color="error" aria-label="remmove winner" component="span" onClick={curryUnsetContestant(props.match.team1Id)}><BackspaceIcon /></IconButton>
} }
{ props.match.team1Id !== null && props.match.winnerId === null && !props.tournament.hasEnded ? { props.match.team1Id !== null && props.match.winnerId === null && !props.tournament.hasEnded && props.user.isLoggedIn &&
<IconButton onClick={setWinner(props.match.team1Id)} color="success" aria-label="select winner" component="span"><AddCircleIcon /></IconButton> : null <IconButton onClick={setWinner(props.match.team1Id)} color="success" aria-label="select winner" component="span"><AddCircleIcon /></IconButton>
} }
{/* { props.match.winnerId && (props.match.team1Id === props.match.winnerId) && {/* { props.match.winnerId && (props.match.team1Id === props.match.winnerId) &&
<EmojiEventsIcon alt="A trohpy" color="gold" /> <EmojiEventsIcon alt="A trohpy" color="gold" />
@ -112,11 +107,11 @@ function Match(props){
<Typography className={`teamName`} sx={{fontSize:'1.5rem', maxWidth:'15vw', overflow:'hidden', wordWrap:'none'}}> <Typography className={`teamName`} sx={{fontSize:'1.5rem', maxWidth:'15vw', overflow:'hidden', wordWrap:'none'}}>
{team2Name} {team2Name}
</Typography> </Typography>
{ props.match.team2Id !== null && !props.tournament.hasEnded && props.match.tier !== Math.log2(props.tournament.teamLimit) - 1 && props.match.winnerId === null ? { props.match.team2Id !== null && !props.tournament.hasEnded && props.match.tier !== Math.log2(props.tournament.teamLimit) - 1 && props.match.winnerId === null && props.user.isLoggedIn &&
<IconButton color="error" aria-label="remmove winner" component="span" onClick={curryUnsetContestant(props.match.team2Id)}><BackspaceIcon /></IconButton> : null <IconButton color="error" aria-label="remmove winner" component="span" onClick={curryUnsetContestant(props.match.team2Id)}><BackspaceIcon /></IconButton>
} }
{ props.match.team2Id !== null && props.match.winnerId === null && !props.tournament.hasEnded ? { props.match.team2Id !== null && props.match.winnerId === null && !props.tournament.hasEnded && props.user.isLoggedIn &&
<IconButton onClick={setWinner(props.match.team2Id)} color="success" aria-label="select winner" component="span"><AddCircleIcon /></IconButton> : null <IconButton onClick={setWinner(props.match.team2Id)} color="success" aria-label="select winner" component="span"><AddCircleIcon /></IconButton>
} }
{/* { props.match.winnerId && (props.match.team2Id === props.match.winnerId) && {/* { props.match.winnerId && (props.match.team2Id === props.match.winnerId) &&
<EmojiEventsIcon alt="A trohpy" color="gold" /> <EmojiEventsIcon alt="A trohpy" color="gold" />
@ -177,17 +172,26 @@ function BracketViewer(props){
<div className="bracket"> <div className="bracket">
{matches.map(tier => { {matches.map(tier => {
let tierNum = tier[0].tier; let tierNum = tier[0].tier;
return <TournamentTier tournament={props.tournament} key={tierNum} tier={tierNum} matches={tier} teams={teams} /> return <TournamentTier user={props.user} tournament={props.tournament} key={tierNum} tier={tierNum} matches={tier} teams={teams} />
})} })}
</div> </div>
: <Box sx={{display:'flex', justifyContent:'center', alignItems:'center', position:'relative', marginTop:'5%'}}><CircularProgress size={"20vw"}/></Box> : <Box sx={{display:'flex', justifyContent:'center', alignItems:'center', position:'relative', marginTop:'5%'}}><CircularProgress size={"20vw"}/></Box>
); );
} }
let showError = (message) => {};
export default function TournamentOverview(props) { export default function TournamentOverview(props) {
const { tournamentId } = useParams(); const { tournamentId } = useParams();
const [tournament, setTournament] = React.useState(false); const [tournament, setTournament] = React.useState(false);
const [openError, setOpenError] = React.useState(false);
const [errorMessage, setErrorMessage] = React.useState("");
showError = (message) => {
setOpenError(false);
setErrorMessage(message);
setOpenError(true);
}
React.useEffect(() => { React.useEffect(() => {
fetch(process.env.REACT_APP_API_URL + `/tournament/${tournamentId}`) fetch(process.env.REACT_APP_API_URL + `/tournament/${tournamentId}`)
.then(res => res.json()) .then(res => res.json())
@ -208,10 +212,10 @@ export default function TournamentOverview(props) {
return ( return (
<> <>
<Appbar user={props.user} pageTitle={tournament.name} /> <Appbar user={props.user} pageTitle={tournament.name} />
{ props.user.isLoggedIn && !tournament.hasEnded ? { props.user.isLoggedIn && !tournament.hasEnded &&
<TournamentBar tournamentId={tournamentId} viewTournament={true} /> : null <TournamentBar tournamentId={tournamentId} viewTournament={true} />
} }
<BracketViewer tournament={tournament} tournamentId={tournamentId} className="bracketViewer" /> <BracketViewer tournament={tournament} user={props.user} tournamentId={tournamentId} className="bracketViewer" />
</> </>
); );
} }

View File

@ -2,6 +2,7 @@ import * as React from "react";
import { BrowserRouter as Router, Link, Route, Routes, useParams } from "react-router-dom"; import { BrowserRouter as Router, Link, Route, Routes, useParams } from "react-router-dom";
import Appbar from "./components/AsuraBar"; import Appbar from "./components/AsuraBar";
import TournamentBar from "./components/TournamentBar"; import TournamentBar from "./components/TournamentBar";
import LoginPage from "./LoginPage";
import { Button, TextField, Stack, MenuItem, Box, InputLabel, Select, Container, TableContainer, Table, TableBody, TableHead, TableCell, TableRow, Paper, Typography} from "@mui/material"; import { Button, TextField, Stack, MenuItem, Box, InputLabel, Select, Container, TableContainer, Table, TableBody, TableHead, TableCell, TableRow, Paper, Typography} from "@mui/material";
import AddCircleIcon from '@mui/icons-material/AddCircle'; import AddCircleIcon from '@mui/icons-material/AddCircle';
import DeleteIcon from '@mui/icons-material/Delete'; import DeleteIcon from '@mui/icons-material/Delete';
@ -203,6 +204,8 @@ export default function TournamentTeams(props) {
getTeams() getTeams()
}, []); }, []);
if (!props.user.isLoggedIn) { return <LoginPage user={props.user} />; }
return ( return (
<> <>
<Appbar user={props.user} pageTitle="Edit teams" /> <Appbar user={props.user} pageTitle="Edit teams" />

View File

@ -55,6 +55,8 @@ function NotLoggedInButton() {
} }
export default function Appbar(props) { export default function Appbar(props) {
console.log("Appbar-user:")
console.log(props.user);
return ( return (
<> <>
<CssBaseline /> <CssBaseline />
@ -79,7 +81,7 @@ export default function Appbar(props) {
<Grid item xs={8}> <Grid item xs={8}>
<Typography component="div"><h2>{props.pageTitle || ""}</h2></Typography> <Typography component="div"><h2>{props.pageTitle || ""}</h2></Typography>
</Grid> </Grid>
{ props.pageTitle !== "Sign in" ? { props.pageTitle !== "Login" ?
<Grid item xs={2}> <Grid item xs={2}>
{ props.user.isLogggedIn ? <LoggedInMenu /> : <NotLoggedInButton /> } { props.user.isLogggedIn ? <LoggedInMenu /> : <NotLoggedInButton /> }
</Grid> : </Grid> :

View File

@ -0,0 +1,19 @@
import * as React from "react";
import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom";
import { Typography } from '@mui/material'
export default function NoSuchPage() {
return(
<>
<Typography type="h3">
You are not logged in
</Typography>
<Typography type="h4">
You dont have access to this page, you can log in here: <Link to="/login">Login</Link>
</Typography>
<Link to="/">
Return to the home page
</Link>
</>
)
}

View File

@ -0,0 +1,5 @@
export default function NoUserPage(props) {
return ("Skjerp deg")
}