Coding session - teams, style, appbar

This commit is contained in:
Felix Albrigtsen 2022-03-28 15:20:23 +02:00
parent 8527560333
commit cfe57274dd
7 changed files with 180 additions and 103 deletions

View File

@ -28,9 +28,7 @@ function CreateButton(props) {
function TournamentListItem(props) { function TournamentListItem(props) {
return ( return (
<Container maxWidth="lg" align="start" sx={{ <Container maxWidth="lg" align="start" sx={{margin:'2.5% 0'}}>
margin:'2.5% 0'
}}>
<Paper elevation={8}> <Paper elevation={8}>
<Card> <Card>
<CardMedia <CardMedia
@ -44,7 +42,7 @@ function TournamentListItem(props) {
<Typography variant="h5" color="text.primary">{props.tournament.description}</Typography> <Typography variant="h5" color="text.primary">{props.tournament.description}</Typography>
<Typography variant="body2" color="text.secondary"> Start: {props.tournament.startTime.toLocaleString()} </Typography> <Typography variant="body2" color="text.secondary"> Start: {props.tournament.startTime.toLocaleString()} </Typography>
<Typography variant="body2" color="text.secondary"> End: {props.tournament.endTime.toLocaleString()} </Typography> <Typography variant="body2" color="text.secondary"> End: {props.tournament.endTime.toLocaleString()} </Typography>
<Typography variant="h5" color="text.primary" gutterBottom> Players todo / {props.tournament.teamLimit} </Typography> <Typography variant="h5" color="text.primary" gutterBottom> Players {props.tournament.teamCount} / {props.tournament.teamLimit} </Typography>
<Box sx={{ <Box sx={{
margin: 'auto', margin: 'auto',
@ -52,7 +50,7 @@ function TournamentListItem(props) {
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'center', justifyContent: 'center',
}} component="span"> }} component="span">
<Box sx={{margin: '0 2% 0 2'}}> <Box sx={{margin: '0 2% 0 2%'}}>
<Link to={`/tournament/${props.tournament.id}/manage`}> <Link to={`/tournament/${props.tournament.id}/manage`}>
<Button className="ManageButton" variant="contained" color="primary">Manage Tournament</Button> <Button className="ManageButton" variant="contained" color="primary">Manage Tournament</Button>
</Link> </Link>
@ -106,7 +104,7 @@ function TournamentList() {
function Home() { function Home() {
return ( return (
<React.StrictMode> <React.StrictMode>
<Appbar /> <Appbar pageTitle="Tournaments" />
<main> <main>
<Container align="center"> <Container align="center">
<CreateButton /> <CreateButton />

View File

@ -2,7 +2,7 @@ import * as React from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import Appbar from './components/appbar'; import Appbar from './components/appbar';
import { useParams } from 'react-router-dom' import { useParams } from 'react-router-dom'
import { Button } from "@mui/material"; import { Button, Paper, Stack } from "@mui/material";
import "./components/tournamentBracket.css"; import "./components/tournamentBracket.css";
function MatchPair(props) { function MatchPair(props) {
@ -64,7 +64,6 @@ function Match(props) {
let setWinner = curryTeamId => event => { let setWinner = curryTeamId => event => {
let teamId = curryTeamId; let teamId = curryTeamId;
console.log(teamId);
if (!teamId || teamId == null) { if (!teamId || teamId == null) {
showError("No team selected"); showError("No team selected");
return; return;
@ -157,7 +156,6 @@ function BracketViewer(props) {
console.error(data) console.error(data)
return; return;
} }
console.log(data);
let teams = data.data; let teams = data.data;
setTeams(teams); setTeams(teams);
}) })
@ -186,13 +184,16 @@ export default function TournamentOverview(props) {
return ( return (
<> <>
<Appbar /> <Appbar pageTitle="Tournament matches" />
<Link to={`/tournament/${tournamentId}/manage`}> <Paper sx={{width: "90vw", margin: "10px auto"}} component={Stack} direction="row" justifyContent="center">
<Button className="ManageButton" variant="contained" color="rackley">Manage Tournament</Button> <Link to={`/tournament/${tournamentId}/manage`} >
</Link> <Button className="ManageButton" variant="contained" color="rackley" sx={{margin: "15px", fontSize: "1.2em"}} >Manage Tournament</Button>
<Link to={`/tournament/${tournamentId}/teams`}> </Link>
<Button className="OverviewButton" variant="contained" color="grape">Manage Teams</Button> <Link to={`/tournament/${tournamentId}/teams`} >
</Link> <Button className="OverviewButton" variant="contained" color="secondary" sx={{margin: "15px", fontSize: "1.2em"}} >Manage Teams</Button>
</Link>
</Paper>
<BracketViewer tournamentId={tournamentId} className="bracketViewer" /> <BracketViewer tournamentId={tournamentId} className="bracketViewer" />
</> </>

View File

@ -1,15 +1,60 @@
import * as React from "react"; 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/appbar"; import Appbar from "./components/appbar";
import { Button, TextField, Stack, MenuItem, 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';
function showError(error) { function showError(error) {
alert("Something went wrong. \n" + error); alert("Something went wrong. \n" + error);
console.error(error); console.error(error);
} }
function TeamList(props) { function TeamCreator(props) {
function postCreate() {
let teamName = document.getElementById("teamNameInput").value;
if (!teamName) {
showError("Team name is required");
return;
}
let formData = new FormData();
formData.append("name", teamName);
let body = new URLSearchParams(formData)
fetch(process.env.REACT_APP_BACKEND_URL + `/api/tournament/${props.tournamentId}/createTeam`, {
method: "POST",
body: body
})
.then(res => res.json())
.then(data => {
if (data.status !== "OK") {
showError(data.data);
return;
}
document.getElementById("teamNameInput").value = "";
props.onTeamCreated();
}
)
}
return (
<Paper sx={{width: "90vw", margin: "10px auto", padding: "15px"}} component={Stack} direction="column">
<div align="center">
<TextField id="teamNameInput" sx={{ width: "70%" }} label="Team Name" variant="outlined" />
{/* <Button variant="contained" color="primary" onClick={postCreate}>Create Team</Button> */}
<Button variant="contained" color="success" onClick={postCreate} sx={{width: "20%", marginLeft: "5px"}}>
<Box sx={{padding: "10px"}}>
Create Team
</Box>
<AddCircleIcon />
</Button>
</div>
</Paper>
)
}
function TeamList(props) {
return ( return (
<Paper sx={{minHeight: "30vh", width: "90vw", margin: "10px auto"}} component={Stack} direction="column" justifyContent="center"> <Paper sx={{minHeight: "30vh", width: "90vw", margin: "10px auto"}} component={Stack} direction="column" justifyContent="center">
<div align="center" > <div align="center" >
@ -32,7 +77,7 @@ function TeamList(props) {
</b></TableCell> </b></TableCell>
<TableCell align="right">{team.members}</TableCell> <TableCell align="right">{team.members}</TableCell>
<TableCell align="center"> <TableCell align="center">
<Button variant="contained" sx={{margin: "auto 5px"}} color="primary" onClick={() => props.setselectedTeamId(team.id)}>Edit</Button> <Button variant="contained" sx={{margin: "auto 5px"}} color="primary" onClick={() => props.setSelectedTeamId(team.id)}>Edit</Button>
<Button variant="contained" sx={{margin: "auto 5px"}} color="error" onClick={() => {props.onDelete(team.id); }}>Delete</Button> <Button variant="contained" sx={{margin: "auto 5px"}} color="error" onClick={() => {props.onDelete(team.id); }}>Delete</Button>
</TableCell> </TableCell>
</TableRow> </TableRow>
@ -75,7 +120,7 @@ function TeamEditor(props) {
formData.append("name", document.getElementById("teamNameInput").value); formData.append("name", document.getElementById("teamNameInput").value);
} }
if (props.selectedTeamId == -1 || !team) { if (props.selectedTeamId === -1 || !team) {
return ( return (
<Paper sx={{minHeight: "30vh", width: "90vw", margin: "10px auto"}} component={Stack} direction="column" justifyContent="center"> <Paper sx={{minHeight: "30vh", width: "90vw", margin: "10px auto"}} component={Stack} direction="column" justifyContent="center">
<div align="center" > <div align="center" >
@ -86,7 +131,31 @@ function TeamEditor(props) {
} }
function nameInputChanged(event) { function nameInputChanged(event) {
setTeam({...team, name: event.target.value}); let newTeam = {...team};
newTeam.name = event.target.value;
setTeam(newTeam);
}
function saveTeam() {
let formData = new FormData();
formData.append("name", team.name);
console.log(team);
let body = new URLSearchParams(formData)
fetch(process.env.REACT_APP_BACKEND_URL + `/api/team/${team.id}/edit`, {
method: "POST",
body: body
})
.then(res => res.json())
.then(data => {
if (data.status !== "OK") {
showError(data.data);
return;
}
setTeam(data.data);
props.setTeams(props.teams.map(listTeam => listTeam.id === team.id ? team : listTeam));
props.setSelectedTeamId(-1);
}
);
} }
return ( return (
@ -94,8 +163,9 @@ function TeamEditor(props) {
<div align="center"> <div align="center">
<h2><b>Edit Team:</b></h2> <h2><b>Edit Team:</b></h2>
<form> <form>
<TextField id="teamNameInput" label="Team Name" value={team.name || ""} onChange={nameInputChanged} /> <TextField id="teamNameInput" label="Team Name" value={team.name || ""} onChange={nameInputChanged} sx={{width: "80%"}} />
<PlayerList players={players} setPlayers={setPlayers} /> <PlayerList players={players} setPlayers={setPlayers} />
<Button variant="contained" sx={{margin: "auto 5px"}} color="primary" onClick={saveTeam}>Save</Button>
</form> </form>
</div> </div>
</Paper> </Paper>
@ -104,10 +174,10 @@ function TeamEditor(props) {
export default function TournamentTeams(props) { export default function TournamentTeams(props) {
const [teams, setTeams] = React.useState([]); const [teams, setTeams] = React.useState([]);
const [selectedTeamId, setselectedTeamId] = React.useState(-1); const [selectedTeamId, setSelectedTeamId] = React.useState(-1);
const { tournamentId } = useParams(); const { tournamentId } = useParams();
React.useEffect(() => { function getTeams() {
fetch(process.env.REACT_APP_BACKEND_URL + `/api/tournament/${tournamentId}/getTeams`) fetch(process.env.REACT_APP_BACKEND_URL + `/api/tournament/${tournamentId}/getTeams`)
.then((res) => res.json()) .then((res) => res.json())
.then((data) => { .then((data) => {
@ -118,14 +188,18 @@ export default function TournamentTeams(props) {
//setselectedTeamId(teams[0].id); //setselectedTeamId(teams[0].id);
}) })
.catch((err) => showError(err)); .catch((err) => showError(err));
}
React.useEffect(() => {
getTeams()
}, []); }, []);
return ( return (
<> <>
<Appbar /> <Appbar pageTitle="Edit teams" />
<div className="tournamentTeams"> <div className="tournamentTeams">
<TeamList teams={teams} selectedTeamId={selectedTeamId} setselectedTeamId={setselectedTeamId} /> <TeamCreator tournamentId={tournamentId} teams={teams} onTeamCreated={getTeams} />
<TeamEditor teams={teams} selectedTeamId={selectedTeamId} /> <TeamList teams={teams} selectedTeamId={selectedTeamId} setSelectedTeamId={setSelectedTeamId} />
<TeamEditor teams={teams} setTeams={setTeams} selectedTeamId={selectedTeamId} setSelectedTeamId={setSelectedTeamId} />
</div> </div>
</> </>
); );

View File

@ -1,32 +1,32 @@
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, History } from "react-router-dom";
import { AppBar, Typography, Toolbar, CssBaseline, Box, IconButton } from "@mui/material" import { AppBar, Typography, Toolbar, CssBaseline, Box, Button, IconButton } from "@mui/material"
import Menu from '@mui/icons-material/Menu' import Menu from '@mui/icons-material/Menu'
import HomeImage from "./homeimage"; import HomeImage from "./homeimage";
export default function Appbar() { export default function Appbar(props) {
return ( return (
<> <>
<CssBaseline /> <CssBaseline />
<Box sx={{ flexGrow: 1 }}> <Box sx={{ flexGrow: 1 }}>
<AppBar position="static" color="primary"> <AppBar position="static" color="primary">
<Toolbar> <Toolbar>
<HomeImage /> <HomeImage sx={{width: "10%"}} />
<Typography variant="h6" component="div" sx={{ marginLeft: '2vw', width: "20%;" }}>
<Typography variant="h6" component="div" sx={{
flexGrow: 1,
marginLeft: '2vw'
}}>
<Link to="/" style={{ textDecoration:'none', color:'white'}}> <Link to="/" style={{ textDecoration:'none', color:'white'}}>
Asura Tournaments Asura Tournaments
</Link> </Link>
</Typography> </Typography>
{/* <Button sx={{width: "5%", color: "white"}} onClick={History.goBack}>Back</Button> */}
<Typography component="div" sx={{margin: "auto auto"}}><h2>{props.pageTitle || ""}</h2></Typography>
<IconButton <IconButton
size="large" size="large"
edge="start" edge="start"
color="inherit" color="inherit"
aria-label="menu" aria-label="menu"
sx={{ mr: 2 }} sx={{ marginRight: 2, width: "5%", marginLeft: "30%" }}
> >
<Menu /> <Menu />
</IconButton> </IconButton>

View File

@ -2,7 +2,8 @@ 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 Appbar from "./components/appbar"; import Appbar from "./components/appbar";
import { Button, TextField, MenuItem, InputLabel, Select, Container, Slider } from '@mui/material' import { Button, TextField, Stack, InputLabel, Select, Container, Slider, Paper, Box, Grid } from '@mui/material'
import FileUploadIcon from '@mui/icons-material/FileUpload';
function submitTournament(event) { function submitTournament(event) {
event.preventDefault(); event.preventDefault();
@ -82,29 +83,33 @@ function TournamentForm(props) {
return ( return (
<> <>
<form> <form>
<Container maxWidth="md"> <Stack sx={{minHeight: "30vh", margin: "10px auto"}} direction="column" justifyContent="center" spacing={4} align="center">
<InputLabel htmlFor="nameInput">Tournament Name: </InputLabel> {/* <InputLabel htmlFor="nameInput">Tournament Name: </InputLabel> */}
<TextField type="text" id="nameInput" variant="filled" label="Tournament Name" /> <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" id="descriptionInput" variant="filled" label="Description"/> <TextField type="text" id="descriptionInput" label="Description" placeholder="Descrption" InputLabelProps={{shrink: true}}/>
<InputLabel htmlFor="editImage"> <Box sx={{ flexGrow: 1 }}>
Tournament Image: <Grid container spacing={-20} justifyContent="center">
<br /> <Grid item xs={2}>
<Button variant="outlined" component="span" color="primary"> <Container>Edit Image:</Container>
Upload </Grid>
</Button> <Grid item xs={2}>
</InputLabel> <Container>
<input <label htmlFor="editImage">
type="file" <Button variant="contained" component="span" endIcon={<FileUploadIcon />}>
id="editImage" Upload
accept="image/png, image/jpeg, image/jpg, image/gif, image/svg" </Button>
style={{ display: 'none' }} <input accept="image/*" id="editImage" multiple type="file" style={{ display: 'none' }} />
/> </label>
<InputLabel htmlFor="startDatePicker">Start Time:</InputLabel> </Container>
<TextField type="datetime-local" id="startDatePicker" /> </Grid>
</Grid>
</Box>
{/* <InputLabel htmlFor="startDatePicker">Start Time:</InputLabel> */}
<TextField type="datetime-local" id="startDatePicker" label="Start Time" InputLabelProps={{shrink: true}}/>
<InputLabel htmlFor="endDatePicker">End Time:</InputLabel> {/* <InputLabel htmlFor="endDatePicker">End Time:</InputLabel> */}
<TextField type="datetime-local" id="endDatePicker" /> <TextField type="datetime-local" id="endDatePicker" label="End Time" InputLabelProps={{shrink: true}}/>
<InputLabel id="max-teams-label">Maximum number of teams</InputLabel> <InputLabel id="max-teams-label">Maximum number of teams</InputLabel>
{/* <Select {/* <Select
@ -133,14 +138,14 @@ function TournamentForm(props) {
<option value={64}>64</option> <option value={64}>64</option>
<option value={128}>128</option> <option value={128}>128</option>
</select> </select>
<Slider aria-label="Teams" defaultValue={1} valueLabelDisplay="auto" step={1} marks min={1} max={7} id="max-teams-slider" > <Slider aria-label="Teams" defaultValue={1} valueLabelDisplay="auto" step={1} marks min={1} max={7} id="max-teams-slider" name="max-teams-slider" >
</Slider> </Slider>
{/* go brrrr */} {/* go brrrr */}
<br /><br /> <br /><br />
<Button type="submit" variant="contained" onClick={submitTournament} color="primary">Create Tournament!</Button> <Button type="submit" variant="contained" onClick={submitTournament} color="primary">Create Tournament!</Button>
</Container> </Stack>
</form> </form>
</> </>
); );
@ -149,8 +154,10 @@ function TournamentForm(props) {
export default function CreateTournament(props) { export default function CreateTournament(props) {
return ( return (
<> <>
<Appbar /> <Appbar pageTitle="New tournament" />
<Paper sx={{minHeight: "30vh", width: "90vw", margin: "20px auto", padding: "20px 0"}} component={Container} direction="column" align="center">
<TournamentForm /> <TournamentForm />
</Paper>
</> </>
); );
} }

View File

@ -3,7 +3,8 @@ 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/appbar"; import Appbar from "./components/appbar";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { Button, TextField, MenuItem, InputLabel, Select, Container, Slider} from "@mui/material"; import { Button, TextField, Grid, Box, Container, Paper, Stack} from "@mui/material";
import FileUploadIcon from '@mui/icons-material/FileUpload';
let submitChanges = curryTournamentId => event => { let submitChanges = curryTournamentId => event => {
event.preventDefault(); event.preventDefault();
@ -71,7 +72,6 @@ function ManageTournament(props) {
let [tournamentInfo, setTournamentInfo] = React.useState([]); let [tournamentInfo, setTournamentInfo] = React.useState([]);
React.useEffect(() => { React.useEffect(() => {
console.log(props.tournamentId);
fetch( fetch(
process.env.REACT_APP_BACKEND_URL + process.env.REACT_APP_BACKEND_URL +
`/api/tournament/${props.tournamentId}` `/api/tournament/${props.tournamentId}`
@ -93,40 +93,40 @@ function ManageTournament(props) {
return ( return (
<> <>
<form> <form>
<Container> <Stack sx={{minHeight: "30vh", margin: "10px auto"}} direction="column" justifyContent="center" spacing={2} align="center">
<InputLabel htmlFor="editName">Edit name: </InputLabel> {/* <InputLabel htmlFor="editName">Edit name: </InputLabel> */}
<TextField type="text" id="editName" /> <TextField type="text" id="editName" label="Edit Name:" InputLabelProps={{shrink: true}}/>
<InputLabel htmlFor="editDesc">Edit description: </InputLabel> {/* <InputLabel htmlFor="editDesc">Edit description: </InputLabel> */}
<TextField type="text" id="editDesc" /> <TextField type="text" id="editDesc" label="Edit Description:" InputLabelProps={{shrink: true}} />
<InputLabel htmlFor="editImage">
Edit image:
<br />
<Button variant="outlined" component="span" color="primary">
Upload
</Button>
</InputLabel>
<input
type="file"
id="editImage"
accept="image/png, image/jpeg, image/jpg, image/gif, image/svg"
style={{ display: "none" }}
/>
<InputLabel htmlFor="editStartDate">Edit Start Time:</InputLabel>
<TextField type="datetime-local" id="editStartDate" />
<InputLabel htmlFor="editEndDate">Edit End Time:</InputLabel> <Box sx={{ flexGrow: 1 }}>
<TextField type="datetime-local" id="editEndDate" /> <Grid container spacing={-20} justifyContent="center">
<Button <Grid item xs={2}>
type="submit" <Container>Edit Image:</Container>
variant="contained" </Grid>
onClick={submitChanges(props.tournamentId)} <Grid item xs={2}>
color="primary" <Container>
> <label htmlFor="editImage">
<Button variant="contained" component="span" endIcon={<FileUploadIcon />}>
Upload
</Button>
<input accept="image/*" id="editImage" multiple type="file" style={{ display: 'none' }} />
</label>
</Container>
</Grid>
</Grid>
</Box>
{/* <InputLabel htmlFor="editStartDate">Edit Start Time:</InputLabel> */}
<TextField type="datetime-local" id="editStartDate" label="Edit Start Time" InputLabelProps={{shrink: true,}}/>
{/* <InputLabel htmlFor="editEndDate">Edit End Time:</InputLabel> */}
<TextField type="datetime-local" id="editEndDate" label="Edit End Time" InputLabelProps={{shrink: true}}/>
<Button type="submit" variant="contained" onClick={submitChanges(props.tournamentId)} color="primary" >
Save Tournament Details Save Tournament Details
</Button> </Button>
</Container>
</form> </Stack>
</form>
</> </>
); );
} }
@ -172,11 +172,13 @@ export default function TournamentManager(props) {
const { tournamentId } = useParams(); const { tournamentId } = useParams();
return ( return (
<> <>
<Appbar /> <Appbar pageTitle="Edit Tournament" />
<Paper sx={{minHeight: "30vh", width: "90vw", margin: "20px auto", padding: "20px 0"}} component={Container} direction="column" align="center">
<ManageTournament tournamentId={tournamentId} /> <ManageTournament tournamentId={tournamentId} />
<AnnounceButton /> <AnnounceButton />
<InviteButton /> <InviteButton />
<AlertContainer floatingTime={5000} /> <AlertContainer floatingTime={5000} />
</Paper>
</> </>
); );
} }

View File

@ -1,5 +0,0 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';