Dev session, graphics, prizes, login

This commit is contained in:
Felix Albrigtsen 2022-04-23 13:34:00 +02:00
parent d69b3a1b2c
commit 176c0b5ad4
13 changed files with 155 additions and 153 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/client/public/react.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -60,7 +60,7 @@ function AdminCreator(props){
function AdminList(props){ function AdminList(props){
const deleteAdmin = adminId => { const deleteAdmin = adminId => {
fetch(process.env.REACT_APP_API_URL + `/admins/${adminId}`, {method: "DELETE"}) fetch(process.env.REACT_APP_API_URL + `/users/${adminId}`, {method: "DELETE"})
.then(res => res.json()) .then(res => res.json())
.then(data => { .then(data => {
if(data.status !== "OK"){ if(data.status !== "OK"){
@ -108,7 +108,7 @@ export default function Admins(props) {
const { adminId } = useParams(); const { adminId } = useParams();
function getAdmins() { function getAdmins() {
fetch(process.env.REACT_APP_API_URL + `/admins/getAdmins`) fetch(process.env.REACT_APP_API_URL + `/users/getUsers`)
.then((res) => res.json()) .then((res) => res.json())
.then((data) =>{ .then((data) =>{
if(data.status !== "OK") { if(data.status !== "OK") {

View File

@ -1,5 +1,6 @@
import * as React from "react"; import * as React from "react";
import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom"; import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom";
import TournamentCreator from "./TournamentCreator.js"; import TournamentCreator from "./TournamentCreator.js";
import TournamentOverview from "./TournamentOverview.js"; import TournamentOverview from "./TournamentOverview.js";
import TournamentManager from "./TournamentManager.js"; import TournamentManager from "./TournamentManager.js";
@ -8,6 +9,10 @@ import TournamentTeams from "./TournamentTeams";
import LoginPage from "./LoginPage"; import LoginPage from "./LoginPage";
import ProfilePage from "./ProfilePage"; import ProfilePage from "./ProfilePage";
import AppBar from './components/AsuraBar'; import AppBar from './components/AsuraBar';
import SuccessSnackbar from "./components/SuccessSnackbar";
import ErrorSnackbar from "./components/ErrorSnackbar";
import AdminsOverview from "./AdminsOverview";
import { Button, Container, Typography, Box, Stack, Card, CardContent, CardMedia, Paper, Grid, Icon, TextField } from "@mui/material"; import { Button, Container, Typography, Box, Stack, Card, CardContent, CardMedia, Paper, Grid, Icon, TextField } from "@mui/material";
import AddCircleIcon from '@mui/icons-material/AddCircle'; import AddCircleIcon from '@mui/icons-material/AddCircle';
import KeyboardDoubleArrowDownIcon from '@mui/icons-material/KeyboardDoubleArrowDown'; import KeyboardDoubleArrowDownIcon from '@mui/icons-material/KeyboardDoubleArrowDown';
@ -111,6 +116,8 @@ function TournamentListItem(props) {
<Typography variant="h5" color="text.primary" gutterBottom> Players: {props.tournament.teamCount} / {props.tournament.teamLimit} </Typography> <Typography variant="h5" color="text.primary" gutterBottom> Players: {props.tournament.teamCount} / {props.tournament.teamLimit} </Typography>
<Description /> <Description />
<Typography variant="body" color="text.primary"><EmojiEventsIcon alt="A trohpy" color="gold"/> Prize: {props.tournament.prize} </Typography>
<Countdown />
<Box sx={{flexGrow: 1, marginTop: "20px"}}> <Box sx={{flexGrow: 1, marginTop: "20px"}}>
<Grid container spacing={4} justifyContent="center" wrap="wrap"> <Grid container spacing={4} justifyContent="center" wrap="wrap">
@ -131,8 +138,6 @@ function TournamentListItem(props) {
</Grid> </Grid>
</Box> </Box>
<Countdown />
<Typography variant="body" color="text.primary"> <EmojiEventsIcon alt="A trohpy" color="gold" /> Prize: {props.tournament.teamCount} </Typography>
</CardContent> </CardContent>
</Card> </Card>
</Paper> </Paper>
@ -157,7 +162,7 @@ function TournamentList() {
for (let i = 0; i < tournaments.length; i++) { for (let i = 0; i < tournaments.length; i++) {
tournaments[i].startTime = new Date(tournaments[i].startTime); tournaments[i].startTime = new Date(tournaments[i].startTime);
tournaments[i].endTime = new Date(tournaments[i].endTime); tournaments[i].endTime = new Date(tournaments[i].endTime);
if(today - tournaments[i].endTime <= 24*60*60*1000) { if(today - tournaments[i].endTime <= 2*60*60*1000) {
currenttournaments.push(tournaments[i]) currenttournaments.push(tournaments[i])
} }
} }
@ -209,7 +214,7 @@ class LoginManager {
.then(res => res.json()) .then(res => res.json())
.then(data => { .then(data => {
if (data.status !== "OK") { if (data.status !== "OK") {
console.error(data); console.error(data.data);
return; return;
} }
console.log(data); console.log(data);
@ -229,21 +234,45 @@ class LoginManager {
let login = new LoginManager(); let login = new LoginManager();
login.checkLogin(); login.checkLogin();
let showSuccess = (message) => {};
let showError = (message) => {};
export default function App() { export default function App() {
const [openError, setOpenError] = React.useState(false);
const [errorMessage, setErrorMessage] = React.useState("");
showError = (message) => {
setOpenError(false);
setErrorMessage(message);
setOpenError(true);
}
const [openSuccess, setOpenSuccess] = React.useState(false);
const [successMessage, setSuccessMessage] = React.useState("");
showSuccess = (message) => {
setOpenSuccess(false);
setSuccessMessage(message);
setOpenSuccess(true);
}
return ( return (
<React.StrictMode> <React.StrictMode>
<Router> <Router>
<Routes> <Routes>
<Route path="/" element={<Home />} /> <Route path="/" element={<Home showError={showError} showSuccess={showSuccess} />} />
<Route path="/create" element={<TournamentCreator />} /> <Route path="/create" element={<TournamentCreator showError={showError} showSuccess={showSuccess} />} />
<Route path="/tournament/:tournamentId" element={<TournamentOverview />} /> <Route path="/tournament/:tournamentId" element={<TournamentOverview />} />
<Route path="/tournament/:tournamentId/manage" element={<TournamentManager />} /> <Route path="/tournament/:tournamentId/manage" element={<TournamentManager showError={showError} showSuccess={showSuccess} />} />
<Route path="/tournament/:tournamentId/teams" element={<TournamentTeams />} /> <Route path="/tournament/:tournamentId/teams" element={<TournamentTeams showError={showError} showSuccess={showSuccess} />} />
<Route path="/history" element={<TournamentHistory />} /> <Route path="/history" element={<TournamentHistory showError={showError} showSuccess={showSuccess} />} />
<Route path="/login" element={<LoginPage />} /> <Route path="/login" element={<LoginPage />} />
<Route path="/profile" element={<ProfilePage login={login} />} /> <Route path="/profile" element={<ProfilePage login={login} />} />
<Route path="/admins" element={<AdminsOverview />} />
</Routes> </Routes>
</Router> </Router>
<SuccessSnackbar message={successMessage} open={openSuccess} setOpen={setOpenSuccess} />
<ErrorSnackbar message={errorMessage} open={openError} setOpen={setOpenError} />
</React.StrictMode> </React.StrictMode>
); );
} }

View File

@ -5,11 +5,6 @@ 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';
function ProfileView() {
return "lol";
}
export default function LoginPage() { export default function LoginPage() {
return ( return (
<> <>
@ -17,9 +12,9 @@ export default function LoginPage() {
<Paper x={{width: "70vw", margin: "1.5% auto"}} component={Stack} direction="column" justifyContent="center" alignItems="center"> <Paper x={{width: "70vw", margin: "1.5% auto"}} component={Stack} direction="column" justifyContent="center" alignItems="center">
<Stack direction="column" paddingTop={'0.5%'} alignItems={'center'}> <Stack direction="column" paddingTop={'0.5%'} alignItems={'center'}>
<Typography>Sign in with google</Typography> <Typography>Sign in with google</Typography>
<Link to={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" />
</Link> </a>
</Stack> </Stack>
</Paper> </Paper>
</> </>

View File

@ -9,7 +9,7 @@ import AdapterDateFns from '@mui/lab/AdapterDateFns';
import LocalizationProvider from '@mui/lab/LocalizationProvider'; import LocalizationProvider from '@mui/lab/LocalizationProvider';
import { setDate } from "date-fns"; import { setDate } from "date-fns";
function postTournament(showError, tournamentName, tournamentDescription, tournamentStartDate, tournamentEndDate, tournamentMaxTeams) { function postTournament(tournamentName, tournamentDescription, tournamentStartDate, tournamentEndDate, tournamentMaxTeams, tournamentPrize) {
if (!tournamentName || tournamentName === "") { if (!tournamentName || tournamentName === "") {
showError("Tournament name cannot be empty"); showError("Tournament name cannot be empty");
return; return;
@ -44,10 +44,10 @@ function postTournament(showError, tournamentName, tournamentDescription, tourna
let formData = new FormData(); let formData = new FormData();
formData.append("name", tournamentName); formData.append("name", tournamentName);
formData.append("description", tournamentDescription); formData.append("description", tournamentDescription);
// formData.append("image", tournamentImageFile);
formData.append("startDate", tournamentStartDate); formData.append("startDate", tournamentStartDate);
formData.append("endDate", tournamentEndDate); formData.append("endDate", tournamentEndDate);
formData.append("teamLimit", tournamentMaxTeams); formData.append("teamLimit", tournamentMaxTeams);
formData.append("prize", tournamentPrize)
let body = new URLSearchParams(formData); let body = new URLSearchParams(formData);
fetch(process.env.REACT_APP_API_URL + `/tournament/create`, { fetch(process.env.REACT_APP_API_URL + `/tournament/create`, {
@ -85,12 +85,12 @@ function TournamentForm(props) {
let tournamentStart = new Date(startTime.setSeconds(0, 0, 0)).valueOf() - new Date().getTimezoneOffset() * 60*1000; let tournamentStart = new Date(startTime.setSeconds(0, 0, 0)).valueOf() - new Date().getTimezoneOffset() * 60*1000;
let tournamentEnd = new Date(endTime.setSeconds(0, 0, 0)).valueOf() - new Date().getTimezoneOffset() * 60*1000; let tournamentEnd = new Date(endTime.setSeconds(0, 0, 0)).valueOf() - new Date().getTimezoneOffset() * 60*1000;
postTournament( postTournament(
props.showError,
document.getElementById("nameInput").value, document.getElementById("nameInput").value,
document.getElementById("descriptionInput").value, document.getElementById("descriptionInput").value,
tournamentStart, tournamentStart,
tournamentEnd, tournamentEnd,
maxTeams maxTeams,
document.getElementById("prizeInput").value
); );
} }
@ -110,6 +110,7 @@ function TournamentForm(props) {
<TextField type="text" id="nameInput" label="Tournament Name" placeholder="Tournament Name" InputLabelProps={{shrink: true}}/> <TextField type="text" id="nameInput" label="Tournament Name" placeholder="Tournament Name" InputLabelProps={{shrink: true}}/>
{/* <InputLabel htmlFor="descriptionInput">Description: </InputLabel */} {/* <InputLabel htmlFor="descriptionInput">Description: </InputLabel */}
<TextField type="text" multiline={true} id="descriptionInput" label="Description" placeholder="Description" InputLabelProps={{shrink: true}}/> <TextField type="text" multiline={true} id="descriptionInput" label="Description" placeholder="Description" InputLabelProps={{shrink: true}}/>
<TextField type="text" id="prizeInput" label="Prize" placeholder="Prize" InputLabelProps={{shrink: true}}/>
<Box flexGrow={1}> <Box flexGrow={1}>
<Grid container spacing={2} justifyContent="center"> <Grid container spacing={2} justifyContent="center">
<Grid item xs={4}> <Grid item xs={4}>
@ -156,10 +157,12 @@ function TournamentForm(props) {
); );
} }
let showError = (message) => {};
export default function TournamentCreator(props) { export default function TournamentCreator(props) {
const [openError, setOpenError] = React.useState(false); const [openError, setOpenError] = React.useState(false);
const [errorMessage, setErrorMessage] = React.useState(""); const [errorMessage, setErrorMessage] = React.useState("");
function showError(message) { showError = (message) => {
setOpenError(false); setOpenError(false);
setErrorMessage(message); setErrorMessage(message);
setOpenError(true); setOpenError(true);
@ -169,7 +172,7 @@ export default function TournamentCreator(props) {
<> <>
<AppBar pageTitle="New tournament" /> <AppBar pageTitle="New tournament" />
<Paper sx={{minHeight: "30vh", width: "90vw", margin: "20px auto", padding: "20px 20px"}} component={Container} direction="column" align="center"> <Paper sx={{minHeight: "30vh", width: "90vw", margin: "20px auto", padding: "20px 20px"}} component={Container} direction="column" align="center">
<TournamentForm showError={showError} /> <TournamentForm />
</Paper> </Paper>
<ErrorSnackbar message={errorMessage} open={openError} setOpen={setOpenError} /> <ErrorSnackbar message={errorMessage} open={openError} setOpen={setOpenError} />

View File

@ -5,6 +5,8 @@ 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 EmojiEventsIcon from '@mui/icons-material/EmojiEvents';
function shorten(description, maxLength) { function shorten(description, maxLength) {
if (description.length > maxLength) { if (description.length > maxLength) {
@ -65,6 +67,7 @@ function shorten(description, maxLength) {
</Grid> </Grid>
</Grid> </Grid>
</Box> </Box>
<Typography variant="body" color="text.primary"><EmojiEventsIcon alt="A trohpy" color="gold" align="vertical-center"/> Prize: {props.tournament.prize} </Typography>
</CardContent> </CardContent>
</Card> </Card>
</Paper> </Paper>
@ -90,7 +93,7 @@ function shorten(description, maxLength) {
for (let i = 0; i < tournaments.length; i++) { for (let i = 0; i < tournaments.length; i++) {
tournaments[i].startTime = new Date(tournaments[i].startTime); tournaments[i].startTime = new Date(tournaments[i].startTime);
tournaments[i].endTime = new Date(tournaments[i].endTime); tournaments[i].endTime = new Date(tournaments[i].endTime);
if(today - tournaments[i].endTime >= 24*60*60*1000) { if(today - tournaments[i].endTime >= 2*60*60*1000) {
tournamenthistory.push(tournaments[i]) tournamenthistory.push(tournaments[i])
} }
} }

View File

@ -2,7 +2,6 @@ import * as React from "react";
import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom"; 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 ErrorSnackbar from "./components/ErrorSnackbar";
import TournamentBar from "./components/TournamentBar"; import TournamentBar from "./components/TournamentBar";
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";
@ -23,6 +22,7 @@ let submitChanges = curryTournamentId => event => {
// let tournamentImageFile = document.getElementById("editImage").files[0]; // let tournamentImageFile = document.getElementById("editImage").files[0];
let tournamentStartDate = document.getElementById("editStartDate").value; let tournamentStartDate = document.getElementById("editStartDate").value;
let tournamentEndDate = document.getElementById("editEndDate").value; let tournamentEndDate = document.getElementById("editEndDate").value;
let tournamentPrize = document.getElementById("editPrize").value
if (!tournamentName || tournamentName === "") { if (!tournamentName || tournamentName === "") {
showError("Tournament name cannot be empty"); showError("Tournament name cannot be empty");
@ -61,6 +61,7 @@ let submitChanges = curryTournamentId => event => {
formData.append("startDate", tournamentStartDate); formData.append("startDate", tournamentStartDate);
formData.append("endDate", tournamentEndDate); formData.append("endDate", tournamentEndDate);
// formData.append("teamLimit", tournamentMaxTeams); // formData.append("teamLimit", tournamentMaxTeams);
formData.append("prize", tournamentPrize)
let body = new URLSearchParams(formData); let body = new URLSearchParams(formData);
fetch(process.env.REACT_APP_API_URL + `/tournament/${tournamentId}/edit`, { fetch(process.env.REACT_APP_API_URL + `/tournament/${tournamentId}/edit`, {
@ -70,7 +71,7 @@ let submitChanges = curryTournamentId => event => {
.then((response) => response.json()) .then((response) => response.json())
.then((data) => { .then((data) => {
if (data.status === "OK") { if (data.status === "OK") {
alert("Tournament Changed successfully"); showSuccess("Tournament Changed successfully");
window.location.href = `/tournament/${tournamentId}`; window.location.href = `/tournament/${tournamentId}`;
} else { } else {
showError(data.data); showError(data.data);
@ -89,8 +90,7 @@ let deleteTournament = tournamentId => event => {
.then((response) => response.json()) .then((response) => response.json())
.then((data) => { .then((data) => {
if (data.status === "OK") { if (data.status === "OK") {
// TODO: Replace alert with Snackbar showSuccess("Tournament Deleted successfully");
alert("Tournament Deleted successfully");
window.location.href = "/"; window.location.href = "/";
} else { } else {
showError(data.data); showError(data.data);
@ -116,6 +116,7 @@ function ManageTournament(props) {
document.getElementById("editName").value = data.data.name; document.getElementById("editName").value = data.data.name;
document.getElementById("editDesc").value = data.data.description; document.getElementById("editDesc").value = data.data.description;
document.getElementById("editPrize").value = data.data.prize
// Get the time from the server, add the local timezone offset and set the input fields // Get the time from the server, add the local timezone offset and set the input fields
let startDate = new Date(data.data.startTime.slice(0, 16)); let startDate = new Date(data.data.startTime.slice(0, 16));
let endDate = new Date(data.data.endTime.slice(0, 16)); let endDate = new Date(data.data.endTime.slice(0, 16));
@ -135,6 +136,7 @@ function ManageTournament(props) {
<Stack sx={{minHeight: "30vh", margin: "10px auto"}} direction="column" justifyContent="center" spacing={2} align="center"> <Stack sx={{minHeight: "30vh", margin: "10px auto"}} direction="column" justifyContent="center" spacing={2} align="center">
<TextField type="text" id="editName" label="Edit Name:" placeholder="Edit Name" InputLabelProps={{shrink: true}}/> <TextField type="text" id="editName" label="Edit Name:" placeholder="Edit Name" InputLabelProps={{shrink: true}}/>
<TextField type="text" multiline={true} id="editDesc" label="Edit Description:" placeholder="Edit Description" InputLabelProps={{shrink: true}} /> <TextField type="text" multiline={true} id="editDesc" label="Edit Description:" placeholder="Edit Description" InputLabelProps={{shrink: true}} />
<TextField type="text" id="editPrize" label="Edit Prize:" placeholder="Edit Prize" InputLabelProps={{shrink: true}}/>
<Box sx={{flexGrow: 1}}> <Box sx={{flexGrow: 1}}>
<Grid container spacing={2} justifyContent="center"> <Grid container spacing={2} justifyContent="center">
<Grid item xs={4}> <Grid item xs={4}>
@ -165,16 +167,10 @@ function ManageTournament(props) {
); );
} }
function showError(error) {
alert("Something went wrong. \n" + error);
console.error(error);
}
function ConfirmationDialogRaw(props) { function ConfirmationDialogRaw(props) {
const { tournamentId } = useParams(); const { tournamentId } = useParams();
const { onClose, value: valueProp, open, ...other } = props; const { onClose, value: valueProp, open, ...other } = props;
const [value, setValue] = React.useState(valueProp); const [value, setValue] = React.useState(valueProp);
const radioGroupRef = React.useRef(null);
React.useEffect(() => { React.useEffect(() => {
if (!open) { if (!open) {
@ -210,32 +206,21 @@ function ConfirmationDialogRaw(props) {
ConfirmationDialogRaw.propTypes = { ConfirmationDialogRaw.propTypes = {
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
open: PropTypes.bool.isRequired, open: PropTypes.bool.isRequired,
value: PropTypes.string.isRequired,
}; };
let showError = (message) => {};
let showSuccess = (message) => {};
export default function TournamentManager(props) { export default function TournamentManager(props) {
const { tournamentId } = useParams(); const { tournamentId } = useParams();
const [open, setOpen] = React.useState(false); const [dialogOpen, setDialogOpen] = React.useState(false);
const [value, setValue] = React.useState(""); const handleDialogClickListItem = () => { setDialogOpen(true); };
const handleDialogClose = () => { setDialogOpen(false); };
const handleClickListItem = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
const [openError, setOpenError] = React.useState(false);
const [errorMessage, setErrorMessage] = React.useState("");
function showError(message) {
setOpenError(false);
setErrorMessage(message);
setOpenError(true);
}
showError = props.showError;
showSuccess = props.showSuccess;
return ( return (
<> <>
<AppBar pageTitle="Edit Tournament" /> <AppBar pageTitle="Edit Tournament" />
<TournamentBar pageTitle="Edit Tournament"/> <TournamentBar pageTitle="Edit Tournament"/>
@ -243,20 +228,17 @@ export default function TournamentManager(props) {
<ManageTournament tournamentId={tournamentId} showError={showError} /> <ManageTournament tournamentId={tournamentId} showError={showError} />
{/* <AnnounceButton /> */} {/* <AnnounceButton /> */}
<Box sx={{width: "100%"}}> <Box sx={{width: "100%"}}>
<Button variant="contained" color="error" onClick={handleClickListItem} sx={{margin: "auto 5px"}} endIcon={<DeleteIcon />}> <Button variant="contained" color="error" onClick={handleDialogClickListItem} sx={{margin: "auto 5px"}} endIcon={<DeleteIcon />}>
Delete Tournament Delete Tournament
</Button> </Button>
<ConfirmationDialogRaw <ConfirmationDialogRaw
id="ringtone-menu" id="confirmation-dialog"
keepMounted keepMounted
open={open} open={dialogOpen}
onClose={handleClose} onClose={handleDialogClose}
value={value}
/> />
</Box> </Box>
</Paper> </Paper>
<ErrorSnackbar message={errorMessage} open={openError} setOpen={setOpenError} />
</> </>
); );
} }

View File

@ -18,12 +18,10 @@ function showError(error) {
} }
function TournamentTier(props){ function TournamentTier(props){
const { tournamentId } = useParams(); let roundTypes = ["winner","finals", "semifinals", "quarterfinals", "eighthfinals", "sixteenthfinals", "thirtysecondfinals"];
let roundTypes = ["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 tournamentId={tournamentId} teams={props.teams} match={props.matches[i]} key={i} />); matches.push(<Match tournament={props.tournament} teams={props.teams} match={props.matches[i]} key={i} />);
} }
return( return(
<ul className={`round ${roundTypes[props.tier]}`}> <ul className={`round ${roundTypes[props.tier]}`}>
@ -45,15 +43,11 @@ function Match(props){
let setWinner = curryTeamId => event => { let setWinner = curryTeamId => event => {
let teamId = curryTeamId; let teamId = curryTeamId;
console.log(teamId) // console.log(teamId)
if (!teamId || teamId == null) { if (!teamId || teamId == null) {
showError("No team selected"); showError("No team selected");
return; return;
} }
// if(props.match.winnerId === teamId){
// showError("Team already won");
// return;
// }
let formData = new FormData(); let formData = new FormData();
formData.append("winnerId",teamId); formData.append("winnerId",teamId);
let body = new URLSearchParams(formData); let body = new URLSearchParams(formData);
@ -71,43 +65,40 @@ function Match(props){
} }
}) })
.catch(error => showError(error)); .catch(error => showError(error));
} };
const [endTime, setendTime] = React.useState(null); let curryUnsetContestant = teamId => (e) => {
console.log("wack")
React.useEffect(() => { let formData = new FormData();
fetch(process.env.REACT_APP_API_URL + `/tournament/${props.tournamentId}`) formData.append("teamId", teamId);
.then(res => res.json()) let body = new URLSearchParams(formData);
console.log(props.match)
fetch(process.env.REACT_APP_API_URL + `/match/${props.match.id}/unsetContestant`, {
method: "POST",
body: body
})
.then(response => response.json())
.then(data => { .then(data => {
if (data.status !== "OK") { if (data.status === "OK") {
// Do your error thing console.log("wacky smacky");
console.error(data); window.location.reload();
return;
} }
let endTime = data.data.endTime;
setendTime(endTime);
}) })
.catch(err => showError(err)); .catch(error => showError(error));
}) }
console.log(props)
let today = new Date()
let yesterday = today.setDate(today.getDate() - 1)
let isComplete = new Date(endTime) < yesterday
return ( return (
<> <>
{/* Team 1 (Winner-status?) (Team name) */} {/* Team 1 (Winner-status?) (Team name) */}
<li className={`game game-top ${props.match.winnerId && (props.match.team1Id === props.match.winnerId) ? "winner" : "loser"}`}> <li className={`game game-top ${props.match.winnerId !== null ? (props.match.team1Id === props.match.winnerId) ? "winner" : "loser" : ""}`}>
<Stack direction={"row"}> <Stack direction={"row"}>
<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.teamId !== null && !isComplete && props.match.tier !== Math.log2(4) - 1 && props.match.winnerId === null && team1Name !== "TBA" ? { props.match.team1Id !== null && !props.tournament.hasEnded && props.match.tier !== Math.log2(props.tournament.teamLimit) - 1 && props.match.winnerId === null ?
<IconButton color="error" aria-label="remmove winner" component="span"><BackspaceIcon /></IconButton> : null <IconButton color="error" aria-label="remmove winner" component="span" onClick={curryUnsetContestant(props.match.team1Id)}><BackspaceIcon /></IconButton> : null
} }
{ props.match.team1Id !== null && props.match.winnerId === null && !isComplete && team1Name !== "TBA" ? { props.match.team1Id !== null && props.match.winnerId === null && !props.tournament.hasEnded ?
<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> : null
} }
{/* { props.match.winnerId && (props.match.team1Id === props.match.winnerId) && {/* { props.match.winnerId && (props.match.team1Id === props.match.winnerId) &&
@ -117,15 +108,15 @@ function Match(props){
</li> </li>
<li className="game game-spacer">&nbsp;</li> <li className="game game-spacer">&nbsp;</li>
{/* Team 2 (Winner-status?) (Team name) */} {/* Team 2 (Winner-status?) (Team name) */}
<li className={`game game-bottom ${props.match.winnerId && (props.match.team2Id === props.match.winnerId) ? "winner" : "loser"}`}> <li className={`game game-bottom ${props.match.winnerId !== null ? (props.match.team1Id === props.match.winnerId) ? "winner" : "loser" : ""}`}>
<Stack direction={"row"} sx={{alignItems:'center'}}> <Stack direction={"row"} sx={{alignItems:'center'}}>
<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.teamId !== null && !isComplete && props.match.tier !== Math.log2(props.maxTeams) - 1 && props.match.winnerId === null && team2Name !== "TBA" ? { props.match.team2Id !== null && !props.tournament.hasEnded && props.match.tier !== Math.log2(props.tournament.teamLimit) - 1 && props.match.winnerId === null ?
<IconButton color="error" aria-label="remmove winner" component="span"><BackspaceIcon /></IconButton> : null <IconButton color="error" aria-label="remmove winner" component="span" onClick={curryUnsetContestant(props.match.team2Id)}><BackspaceIcon /></IconButton> : null
} }
{ props.match.team1Id !== null && props.match.winnerId === null && !isComplete && team2Name !== "TBA" ? { props.match.team2Id !== null && props.match.winnerId === null && !props.tournament.hasEnded ?
<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> : null
} }
{/* { props.match.winnerId && (props.match.team2Id === props.match.winnerId) && {/* { props.match.winnerId && (props.match.team2Id === props.match.winnerId) &&
@ -139,25 +130,11 @@ function Match(props){
} }
function BracketViewer(props){ function BracketViewer(props){
const [tournament, setTournament] = React.useState(null);
const [matches, setMatches] = React.useState(null); const [matches, setMatches] = React.useState(null);
const [teams, setTeams] = React.useState(null); const [teams, setTeams] = React.useState(null);
React.useEffect(() => { React.useEffect(() => {
fetch(process.env.REACT_APP_API_URL + `/tournament/${props.tournamentId}`)
.then(res => res.json())
.then(data => {
if (data.status !== "OK") {
// Do your error thing
showError(data.data);
return;
}
let tournament = data.data;
setTournament(tournament);
})
.catch(err => showError(err));
fetch(process.env.REACT_APP_API_URL + `/tournament/${props.tournamentId}/getMatches`) fetch(process.env.REACT_APP_API_URL + `/tournament/${props.tournamentId}/getMatches`)
.then(res => res.json()) .then(res => res.json())
.then(data => { .then(data => {
@ -196,56 +173,46 @@ function BracketViewer(props){
.catch(err => showError(err)); .catch(err => showError(err));
}, []); }, []);
return ( return (
(matches && teams) ? (props.tournament && matches && teams) ?
// <div sx={{width: "100vw", height: "80vh", overflow: "scroll"}} className="bracket"> // <div sx={{width: "100vw", height: "80vh", overflow: "scroll"}} className="bracket">
<div className="bracket"> <div className="bracket">
{matches.map(tier => { {matches.map(tier => {
let tierNum = tier[0].tier; let tierNum = tier[0].tier;
return <TournamentTier key={tierNum} tier={tierNum} matches={tier} teams={teams} /> return <TournamentTier 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>
); );
} }
function RemovableBar(props) { export default function TournamentOverview(props) {
const [endTime, setendTime] = React.useState(null); const { tournamentId } = useParams();
const [tournament, setTournament] = React.useState(false);
React.useEffect(() => { React.useEffect(() => {
fetch(process.env.REACT_APP_API_URL + `/tournament/${props.tournamentId}`) fetch(process.env.REACT_APP_API_URL + `/tournament/${tournamentId}`)
.then(res => res.json()) .then(res => res.json())
.then(data => { .then(data => {
if (data.status !== "OK") { if (data.status !== "OK") {
// Do your error thing showError(data.data);
console.error(data);
return; return;
} }
let endTime = data.data.endTime; let tourn = data.data;
setendTime(endTime); let now = new Date();
let endTime = new Date(tourn.endTime);
tourn.hasEnded = (now - 2*60*60*1000) > endTime; // 2 hours in the past
setTournament(tourn);
}) })
.catch(err => showError(err)); .catch(err => showError(err));
}) }, [tournamentId]);
let today = new Date()
let yesterday = today.setDate(today.getDate() - 1)
let isComplete = new Date(endTime) < yesterday
if (isComplete) {
return (null)
} else {
return (<TournamentBar pageTitle="View Tournament" />)
}
}
export default function TournamentOverview(props) {
const { tournamentId } = useParams();
return ( return (
<> <>
<Appbar pageTitle="View Tournament" /> <Appbar pageTitle={tournament.name} />
{ isLoggedIn ? { isLoggedIn && !tournament.hasEnded ?
<RemovableBar tournamentId={tournamentId} /> : null <TournamentBar tournamentId={tournamentId} viewTournament={true} /> : null
} }
<BracketViewer tournamentId={tournamentId} className="bracketViewer" /> <BracketViewer tournament={tournament} tournamentId={tournamentId} className="bracketViewer" />
</> </>
); );
} }

View File

@ -36,6 +36,7 @@ function TeamCreator(props) {
} }
document.getElementById("teamNameInput").value = ""; document.getElementById("teamNameInput").value = "";
props.onTeamCreated(); props.onTeamCreated();
} }
) )
} }
@ -108,14 +109,8 @@ function TeamList(props) {
); );
} }
function PlayerList(props) {
// Something like https://react-list-editable.netlify.app/
return <h1>PlayerList coming...</h1>
}
function TeamEditor(props) { function TeamEditor(props) {
const [team, setTeam] = React.useState({}); const [team, setTeam] = React.useState({});
const [players, setPlayers] = React.useState([]);
React.useEffect(() => { React.useEffect(() => {
if (props.selectedTeamId === -1) { if (props.selectedTeamId === -1) {
setTeam({}); setTeam({});
@ -180,7 +175,6 @@ function TeamEditor(props) {
<h2><b>Edit Team:</b></h2> <h2><b>Edit Team:</b></h2>
<form> <form>
<TextField id="newTeamNameInput" label="Team Name" value={team.name || ""} onChange={nameInputChanged} onFocus={handleFocus} sx={{width: "80%"}} /> <TextField id="newTeamNameInput" label="Team Name" value={team.name || ""} onChange={nameInputChanged} onFocus={handleFocus} sx={{width: "80%"}} />
{/* <PlayerList players={players} setPlayers={setPlayers} /> */}
<Button type="submit" variant="contained" sx={{margin: "auto 5px"}} color="primary" onClick={saveTeam}>Save</Button> <Button type="submit" variant="contained" sx={{margin: "auto 5px"}} color="primary" onClick={saveTeam}>Save</Button>
</form> </form>
</div> </div>

View File

@ -0,0 +1,29 @@
import * as React from 'react';
import Stack from '@mui/material/Stack';
import Button from '@mui/material/Button';
import Snackbar from '@mui/material/Snackbar';
import MuiAlert from '@mui/material/Alert';
const Alert = React.forwardRef(function Alert(props, ref) {
return <MuiAlert elevation={6} ref={ref} variant="filled" {...props} />;
});
export default function showError(props) {
const handleClose = (event, reason) => {
if (reason === 'clickaway') {
return;
}
props.setOpen(false);
};
return (
<Stack spacing={2} sx={{ width: '100%' }}>
<Snackbar open={props.open} autoHideDuration={6000} onClose={handleClose}>
<Alert onClose={handleClose} severity="success" sx={{ width: '100%' }}>
{props.message}
</Alert>
</Snackbar>
</Stack>
);
}

View File

@ -31,7 +31,7 @@ function ClipboardButton(props) {
function ButtonLink(props) { function ButtonLink(props) {
return ( return (
<Link to={`/tournament/${props.tournamentId}` + props.targetPath} > <Link to={`/tournament/${props.tournamentId}` + props.targetPath} >
<Button variant="contained" color="primary" disabled={props.activeTitle === props.title} sx={{margin: "15px", fontSize: "1.2em"}} >{props.title}</Button> <Button variant="contained" color="primary" disabled={props.activeTitle === props.title || props.viewTournament} sx={{margin: "15px", fontSize: "1.2em"}} >{props.title}</Button>
</Link> </Link>
); );
} }
@ -41,7 +41,7 @@ export default function TournamentBar(props) {
return ( return (
<Paper sx={{width: "90vw", margin: "1.5% auto"}} component={Stack} direction="column" justifyContent="center" alignItems="center"> <Paper sx={{width: "90vw", margin: "1.5% auto"}} component={Stack} direction="column" justifyContent="center" alignItems="center">
<Stack direction="row" paddingTop={'0.5%'}> <Stack direction="row" paddingTop={'0.5%'}>
<ButtonLink targetPath="" tournamentId={tournamentId} activeTitle={props.pageTitle} title="View Tournament" /> <ButtonLink targetPath="" tournamentId={tournamentId} activeTitle={props.pageTitle} title="View Tournament" viewTournament={props.viewTournament} />
<ButtonLink targetPath="/manage" tournamentId={tournamentId} activeTitle={props.pageTitle} title="Edit Tournament" /> <ButtonLink targetPath="/manage" tournamentId={tournamentId} activeTitle={props.pageTitle} title="Edit Tournament" />
<ButtonLink targetPath="/teams" tournamentId={tournamentId} activeTitle={props.pageTitle} title="Manage Teams" /> <ButtonLink targetPath="/teams" tournamentId={tournamentId} activeTitle={props.pageTitle} title="Manage Teams" />
</Stack> </Stack>

View File

@ -10,7 +10,7 @@
display:flex; display:flex;
flex-direction:column; flex-direction:column;
justify-content:center; justify-content:center;
width:20vw; width:20%;
list-style:none; list-style:none;
padding:0; padding:0;
font-size: 1.5rem; font-size: 1.5rem;