Massive collaborative workshop 23/03/2022

Co-authored-by: SgtPodding <SgtPodding@users.noreply.github.com>
Co-authored-by: Felix Albrigtsen <felixalbrigtsen@gmail.com>
Co-authored-by: krloer <krloer@users.noreply.github.com>
This commit is contained in:
Kristoffer Juelsenn 2022-03-23 16:19:18 +01:00
parent 9056d10117
commit 189a047bd2
12 changed files with 17060 additions and 174 deletions

File diff suppressed because it is too large Load Diff

View File

@ -31,15 +31,5 @@
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body> </body>
</html> </html>

View File

@ -1,19 +1,36 @@
import * as React from "react"; import * as React from "react";
import { AppBar, Typography, Toolbar } from "@mui/material"; import { AppBar, Typography, Toolbar, CssBaseline, Button, Box, IconButton } from "@mui/material"
import Menu from '@mui/icons-material/Menu'
import HomeImage from "./homeimage"; import HomeImage from "./homeimage";
import CssBaseline from '@mui/material/CssBaseline'
export default function Appbar() { export default function Appbar() {
return ( return (
<> <>
<CssBaseline /> <CssBaseline />
<AppBar position="relative" color="primary"> <Box sx={{ flexGrow: 1 }}>
<AppBar position="static">
<Toolbar> <Toolbar>
<HomeImage /> <HomeImage />
<Typography>This is an Appbar</Typography> <Typography variant="h6" component="div" sx={{
flexGrow: 1,
marginLeft: '2vw'
}}>
Asura Tournaments
</Typography>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="menu"
sx={{ mr: 2 }}
>
<Menu />
</IconButton>
{/* <Button color="inherit">Login</Button> */}
</Toolbar> </Toolbar>
</AppBar> </AppBar>
</> </Box>
</>
); );
} }

View File

@ -5,7 +5,7 @@ import Button from "@mui/material/Button";
export default function ManageButton(props) { export default function ManageButton(props) {
return ( return (
<Link to="/tournament/manage" style={{textDecoration:'none'}}> <Link to={`/tournament/${props.tournamentId}/manage`} style={{textDecoration:'none'}}>
<Button className="ManageButton" variant="contained" color="primary">Manage Tournament</Button> <Button className="ManageButton" variant="contained" color="primary">Manage Tournament</Button>
</Link> </Link>
); );

View File

@ -6,7 +6,7 @@ import Button from "@mui/material/Button";
export default function SaveButton(props) { export default function SaveButton(props) {
return ( return (
<Link to="/" style={{textDecoration:'none'}}> <Link to="/" style={{textDecoration:'none'}}>
<Button>Save and Exit</Button> <Button variant="outlined" color="primary">Save and Exit</Button>
</Link> </Link>
); );
} }

View File

@ -2,52 +2,153 @@ 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";
function CreateButton(props) { import { Button, TextField, MenuItem, InputLabel, Select, Container, Slider } from '@mui/material'
return (
<Link to="/"> function submitTournament(event) {
<button>Create Tournament!</button> event.preventDefault();
</Link> //TODO use refs to get values
); let tournamentName = document.getElementById("nameInput").value;
let tournamentDescription = document.getElementById("descriptionInput").value;
let tournamentImageFile = document.getElementById("editImage").files[0];
let tournamentStartDate = document.getElementById("startDatePicker").value;
let tournamentEndDate = document.getElementById("endDatePicker").value;
let tournamentMaxTeams = document.getElementById("max-teams-select").value;
if (!tournamentName || tournamentName == "") {
alert("Tournament name cannot be empty");
return;
}
if (!tournamentDescription || tournamentDescription == "") {
alert("Tournament description cannot be empty");
return;
}
if (!tournamentStartDate || tournamentStartDate == "") {
alert("Tournament start date cannot be empty");
return;
}
if (!tournamentEndDate || tournamentEndDate == "") {
alert("Tournament end date cannot be empty");
return;
}
if (!tournamentMaxTeams || isNaN(tournamentMaxTeams) || tournamentMaxTeams < 2) {
alert("Tournament max teams cannot be empty");
return;
}
if (tournamentStartDate > tournamentEndDate) {
alert("Tournament start date cannot be after end date");
return;
}
let today = new Date();
if (tournamentStartDate < today || tournamentEndDate < today) {
alert("Tournament start and end date must be after today");
return;
}
let formData = new FormData();
formData.append("name", tournamentName);
formData.append("description", tournamentDescription);
// formData.append("image", tournamentImageFile);
formData.append("startDate", tournamentStartDate);
formData.append("endDate", tournamentEndDate);
formData.append("teamLimit", tournamentMaxTeams);
let body = new URLSearchParams(formData);
fetch("http://10.24.1.213:3000/api/tournament/create", {
method: "POST",
body: body
})
.then(response => response.json())
.then(data => {
if (data.status == "OK") {
alert("Tournament created successfully");
window.location.href = "/";
} else {
showError(data.data)
}
})
.catch(error => showError(error));
}
function showError(error) {
alert("Something went wrong. \n" + error);
console.error(error);
} }
function ParticipantLimit(props) { function TournamentForm(props) {
return (
<div>
Participant Limit:
<select>
<option value="4">4</option>
<option value="8">8</option>
<option value="16">16</option>
<option value="16">32</option>
<option value="64">64</option>
<option value="128">128</option>
<option value="256">256</option>
</select>
</div>
);
}
function CreateForm(props) {
return ( return (
<> <>
<form> <form>
<label for="name">Tournament Name: <input type="text" id="name" /></label> <Container maxWidth="md">
<InputLabel htmlFor="nameInput">Tournament Name: </InputLabel>
<TextField type="text" id="nameInput" variant="filled" label="Tournament Name" />
<InputLabel htmlFor="descriptionInput">Description: </InputLabel>
<TextField type="text" id="descriptionInput" variant="filled" label="Description"/>
<InputLabel htmlFor="editImage">
Tournament Image:
<br /> <br />
<label for="description">Description:</label> <Button variant="outlined" component="span" color="primary">
<input type="text" id="description" /> Upload
<br /> </Button>
<label for="image">Tournament Image:</label> </InputLabel>
<input <input
type="file" type="file"
id="image" id="editImage"
accept="image/png, image/jpeg, image/jpg" accept="image/png, image/jpeg, image/jpg, image/gif, image/svg"
style={{ display: 'none' }}
/> />
<br /> <InputLabel htmlFor="startDatePicker">Start Time:</InputLabel>
<label for="date">Start Date:</label> <TextField type="datetime-local" id="startDatePicker" />
<input type="date" id="date" />
<input type="time" id="time" /> <InputLabel htmlFor="endDatePicker">End Time:</InputLabel>
<br /> <TextField type="datetime-local" id="endDatePicker" />
<InputLabel id="max-teams-label">Maximum number of teams</InputLabel>
{/* <Select
labelId="max-teams-label"
id="max-teams-select"
onChange={(event) => {
console.log(event.target.value);
} }
value={8}
label="Max Teams"
>
<MenuItem value={2}>2</MenuItem>
<MenuItem value={4}>4</MenuItem>
<MenuItem value={8}>8</MenuItem>
<MenuItem value={16}>16</MenuItem>
<MenuItem value={32}>32</MenuItem>
<MenuItem value={64}>64</MenuItem>
<MenuItem value={128}>128</MenuItem>
</Select> */}
<select id="max-teams-select">
<option value={2}>2</option>
<option value={4}>4</option>
<option value={8}>8</option>
<option value={16}>16</option>
<option value={32}>32</option>
<option value={64}>64</option>
<option value={128}>128</option>
</select>
<Slider
aria-label="Teams"
defaultValue={1}
// value={value}
// onChange={console.log(value)}
valueLabelDisplay="auto"
step={1}
marks
min={1}
max={7}
id="max-teams-slider"
>
</Slider>
{/* go brrrr */}
<br /><br />
<Button type="submit" variant="contained" onClick={submitTournament} color="primary">Create Tournament!</Button>
</Container>
</form> </form>
</> </>
); );
@ -57,9 +158,7 @@ export default function CreateTournament(props) {
return ( return (
<> <>
<Appbar /> <Appbar />
<CreateForm /> <TournamentForm />
<ParticipantLimit />
<CreateButton />
</> </>
); );
} }

View File

@ -9,18 +9,21 @@ import TournamentMatches from "./tournamentmatches";
import TeamEditor from "./teameditor"; import TeamEditor from "./teameditor";
import Appbar from './components/appbar'; import Appbar from './components/appbar';
import Button from "@mui/material/Button"; import { Button, Container, Typography, Grid, Box } from "@mui/material";
import Container from "@mui/material/Container"; import { Card, CardActions,CardACtionsArea, CardContent, CardHeader, CardMedia, Collapse, Paper } from "@mui/material";
import CssBaseline from "@mui/material/CssBaseline"; import AddCircleIcon from '@mui/icons-material/AddCircle';
import Typography from "@mui/material/Typography"; import { maxWidth } from "@mui/system";
import Grid from "@mui/material/Grid";
import Box from "@mui/material/Box";
function CreateButton(props) { function CreateButton(props) {
return ( return (
<Link to="/create" style={{ textDecoration: "none" }}> <Link to="/create" style={{ textDecoration: "none" }}>
<Button variant="contained" color="primary"> <Button variant="contained" color="success" style={{ margin: '2.5% 0 0 0'}}>
Create Tournament <Box sx={{
marginRight: '2%',
}}>
Create Tournament
</Box>
<AddCircleIcon />
</Button> </Button>
</Link> </Link>
); );
@ -36,38 +39,92 @@ function OverviewButton(props) {
); );
} }
function ListElement(props) { function TournamentListItem(props) {
return ( return (
<Container maxWidth="lg" align="start"> <Container maxWidth="lg" align="start" sx={{
<Grid container spacing={2}> margin:'2.5% 0'
<Grid item xs={5}> }}>
<Typography noWrap> <Paper elevation={8}>
{props.name}, {props.competitors} competitors, Date: {props.date} <Card>
</Typography> <CardMedia
</Grid> component="img"
<Grid item> alt="tournament image"
<ManageButton /> height="140"
</Grid> image="https://source.unsplash.com/random"
<Grid item> />
<OverviewButton /> <CardContent>
</Grid> <Typography variant="h3" component="div" align="center">
</Grid> {props.tournament.name}
</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">
End: {props.tournament.endTime.toLocaleString()}
</Typography>
<Typography variant="h5" color="text.primary" gutterBottom>
Players todo / {props.tournament.teamLimit}
</Typography>
<Box sx={{
margin: 'auto',
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
}} component="span">
<Box sx={{
margin: '0 2% 0 2'
}}>
<ManageButton tournamentId={props.tournament.id}/>
</Box>
<Box sx={{
margin: '0 2% 0 2%'
}}>
<OverviewButton />
</Box>
</Box>
</CardContent>
</Card>
</Paper>
</Container> </Container>
); );
} }
function TournamentList() { function TournamentList() {
let [data, setData] = React.useState(null); let [data, setData] = React.useState(null);
let [tournamentList, setTournamentList] = React.useState([]);
React.useEffect(() => { React.useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1") fetch("http://10.24.1.213:3000/api/tournament/getTournaments")
.then((res) => res.json()) .then(res => res.json())
.then((data) => { .then(data => {
setData(data.data);
if (data.status != "OK") {
// Do your error thing
console.error(data);
return;
}
let tournaments = Object.values(data.data);
for (let i = 0; i < tournaments.length; i++) {
tournaments[i].startTime = new Date(tournaments[i].startTime);
tournaments[i].endTime = new Date(tournaments[i].endTime);
}
setTournamentList(tournaments);
}) })
.catch((err) => console.log(err.message)); .catch((err) => console.log(err.message));
}, []); }, []);
return <div>{data && data.map((data, i) => <div>{i}</div>)}</div>;
return <>
{/* {tournamentList && tournamentList.map((tournamentObject, i) => <TournamentListItem key={tournamentObject.id.toString()} name={tournamentObject.name} description={tournamentObject.description} startDate={tournamentObject.startTime} endDate={tournamentObject.endTime} teamLimit={tournamentObject.teamLimit} />)} */}
{tournamentList && tournamentList.map((tournamentObject) => <TournamentListItem key={tournamentObject.id.toString()} tournament={tournamentObject} />)}
</>;
} }
//<ListElement name={data[i].name} competitors={data[i].teamLimit} date={data[i].startTime}/> //<ListElement name={data[i].name} competitors={data[i].teamLimit} date={data[i].startTime}/>
function Home() { function Home() {
@ -75,10 +132,12 @@ function Home() {
<React.StrictMode> <React.StrictMode>
<Appbar /> <Appbar />
<main> <main>
<Container> <Container align="center">
<Box>
<CreateButton /> <CreateButton />
</Box> <Typography variant="h2" style={{margin:'2% 0'}}>
Tournaments
</Typography>
<TournamentList />
{/* <ListElement {/* <ListElement
name="Weekend Warmup" name="Weekend Warmup"
competitors="16" competitors="16"
@ -94,7 +153,7 @@ function Home() {
competitors="64" competitors="64"
date="01.05.2022" date="01.05.2022"
/> */} /> */}
<TournamentList />
</Container> </Container>
</main> </main>
<footer className="footer"></footer> <footer className="footer"></footer>
@ -108,8 +167,8 @@ export default function App() {
<Routes> <Routes>
<Route path="/" element={<Home />} /> <Route path="/" element={<Home />} />
<Route path="/create" element={<CreateTournament />} /> <Route path="/create" element={<CreateTournament />} />
<Route path="/tournament" element={<TournamentOverview />} /> <Route path="/tournament/" element={<TournamentOverview />} />
<Route path="/tournament/manage" element={<TournamentManager />} /> <Route path="/tournament/:id/manage" element={<TournamentManager />} />
<Route path="/tournament/teams" element={<TeamEditor />} /> <Route path="/tournament/teams" element={<TeamEditor />} />
<Route path="/tournament/matches" element={<TournamentMatches />} /> <Route path="/tournament/matches" element={<TournamentMatches />} />
<Route <Route

View File

@ -19,6 +19,13 @@ code {
} }
.mainIcon{ .mainIcon{
height: 40px; height: 60px;
width: 40px; width: 60px;
border-radius: 50%;
/* border: 5px dotted salmon; */
border: 3px solid darkslateblue;
background-color: white;
margin: 5px;
margin-bottom: 0;
/* margin: 50% calc(2vw + 50%) 50% 50%; */
} }

View File

@ -3,29 +3,58 @@ 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 SaveButton from "./components/savebutton"; import SaveButton from "./components/savebutton";
import { useParams } from 'react-router-dom'
import { Button, TextField, MenuItem, InputLabel, Select, Container, Slider } from '@mui/material'
function ManageTournament(props) { function ManageTournament(props) {
const { id } = useParams()
let [tournamentInfo, setTournamentInfo] = React.useState([]);
React.useEffect(() => {
fetch(`http://10.24.1.213:3000/api/tournament/${id}`)
.then(res => res.json())
.then(data => {
if (data.status != "OK") {
// Do your error thing
console.error(data.data);
return;
}
setTournamentInfo(data.data);
document.getElementById("editName").value = data.data.name;
})
.catch((err) => console.log(err.message));
}, []);
return ( return (
<> <>
<form> <form>
<label>Edit name: </label> <Container>
<input type="text" id="editName" /> <InputLabel htmlFor="editName">Edit name: </InputLabel>
<br /> <TextField type="text" id="editName" />
<label>Edit description: </label> <InputLabel htmlFor="editDesc">Edit description: </InputLabel>
<input type="text" id="editDesc" /> <TextField type="text" id="editDesc" />
<br /> <InputLabel htmlFor="editImage">
<label>Edit image: </label> Edit image:
<br />
<Button variant="outlined" component="span" color="primary">
Upload
</Button>
</InputLabel>
<input <input
type="file" type="file"
id="editImage" id="editImage"
accept="image/png, image/jpeg, image/jpg" accept="image/png, image/jpeg, image/jpg, image/gif, image/svg"
style={{ display: 'none' }}
/> />
<br /> <InputLabel htmlFor="editStartDate">Edit Start Time:</InputLabel>
<label>Edit start time: </label> <TextField type="datetime-local" id="editStartDate" />
<input type="date" id="editDate" />
<input type="time" id="editTime" /> <InputLabel htmlFor="editEndDate">Edit End Time:</InputLabel>
<br /> <TextField type="datetime-local" id="editEndDate" />
<br /> </Container>
</form> </form>
</> </>
); );
@ -34,7 +63,7 @@ function ManageTournament(props) {
function AnnounceButton(props) { function AnnounceButton(props) {
return ( return (
<Link to="/tournament/manage/announcement"> <Link to="/tournament/manage/announcement">
<button id="sendAnnon">Send Tournament Announcement</button> <Button id="sendAnnon" variant="outlined" color="primary">Send Tournament Announcement</Button>
</Link> </Link>
); );
} }
@ -50,14 +79,13 @@ function InviteButton(props) {
const alertSuccess = () => const alertSuccess = () =>
alert({ message: "Copied to clipboard.", type: "success" }); alert({ message: "Copied to clipboard.", type: "success" });
return ( return (
<button id="createInvLink" onClick={event}> <Button id="createInvLink" onClick={event} variant="outlined" color="primary">
Copy Invite Link Copy Invite Link
</button> </Button>
); );
} }
//navigator.clipboard.writeText("discord.gg/asura") export default function TournamentManager(props) {
export default function TournamentManager() {
return ( return (
<> <>
<Appbar /> <Appbar />

View File

@ -1,11 +1,37 @@
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 Appbar from './components/appbar'; import Appbar from './components/appbar';
import { Button, TextField, MenuItem, InputLabel, Select, Container, Slider } from '@mui/material'
function TeamList() {
let teams = {"team 1": ["tom", "eric", "gustav"], "team 2": ["emma", "mari", "ida"],"team 3": ["ola", "ole", "ost"],"team 4": ["christine", "kristine", "kristhine"]}
return (<div>
<ul>
{Object.entries(teams).map(([team, players]) => <li key={team} ><button>{team}</button></li>)}
</ul>
</div>)
}
function TeamChanger() {
return (
<>
<form>
<InputLabel htmlFor="teamInput">Team Name: </InputLabel>
<TextField type="text" id="teamInput" variant="filled" label="Team Name:" />
<InputLabel htmlFor="membersInput">Team Members: </InputLabel>
<TextField type="text" id="membersInput" variant="filled" label="Members:"/>
</form>
</>
);
}
export default function TeamEditor() { export default function TeamEditor() {
return ( return (
<> <>
<Appbar /> <Appbar />
<TeamChanger />
<TeamList />
</> </>
); );
} }

View File

@ -2,10 +2,18 @@ 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';
function MatchHistory() {
return(
`Hei`
);
}
export default function TournamentMatches() { export default function TournamentMatches() {
return ( return (
<> <>
<Appbar /> <Appbar />
<MatchHistory />
</> </>
); );
} }

View File

@ -3,38 +3,54 @@ import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom";
import ManageButton from "./components/managebutton"; import ManageButton from "./components/managebutton";
import Appbar from './components/appbar'; import Appbar from './components/appbar';
function RenderBrackets() { // Test data
// {"status":"OK","data":
// [
// {"id":1,
// "tournamentId":1,
// "parentMatchId":null,
// "team1Id":null,
// "team2Id":null,
// "winnerId":null}
function RenderBrackets(params) {
let teams = 16;
let groups = Math.log2(teams);
// Number of matches, python equivalent: sum([2**groupNumber for groupNumber in range(groups)])
let matches = [...Array(groups).keys()].map(num => Math.pow(2, num)).reduce((a, b) => a + b);
return ( return (
<> <>
brackets = [] {new Array(groups).map((group, i) => {
knownTeams = [2,4,8,16,32,64,128,256] return (
<div>Group {i}</div>
);
})}
</> </>
); );
} }
function ViewTournament(params) { function OverviewButtons(params) {
return ( return (
<> <>
<div id="touOverview"></div> <div id="touOverview"></div>
<Link to="/tournament/teams"> <Link to="/tournament/teams">
<button id="manageTeams">Manage Teams </button> <button id="manageTeams">Manage Teams </button>
</Link> </Link>
<Link to="/tournament/matches"> {/* <Link to="/tournament/matches">
<button id="touMaches">Tournament Matches</button> <button id="touMatches">Tournament Matches</button>
</Link> </Link> */}
</> </>
); );
} }
export default function TournamentOverview(props) { export default function TournamentOverview(props) {
// Use-effect hook here
return ( return (
<> <>
<Appbar /> <Appbar />
<ManageButton /> <ManageButton />
<ViewTournament /> <RenderBrackets />
<OverviewButtons />
</> </>
); );
} }