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>
<noscript>You need to enable JavaScript to run this app.</noscript>
<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>
</html>

View File

@ -1,18 +1,35 @@
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 CssBaseline from '@mui/material/CssBaseline'
export default function Appbar() {
return (
<>
<CssBaseline />
<AppBar position="relative" color="primary">
<Box sx={{ flexGrow: 1 }}>
<AppBar position="static">
<Toolbar>
<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>
</AppBar>
</Box>
</>
);
}

View File

@ -5,7 +5,7 @@ import Button from "@mui/material/Button";
export default function ManageButton(props) {
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>
</Link>
);

View File

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

View File

@ -2,52 +2,153 @@ import * as React from "react";
import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom";
import Appbar from "./components/appbar";
function CreateButton(props) {
return (
<Link to="/">
<button>Create Tournament!</button>
</Link>
);
import { Button, TextField, MenuItem, InputLabel, Select, Container, Slider } from '@mui/material'
function submitTournament(event) {
event.preventDefault();
//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) {
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) {
function TournamentForm(props) {
return (
<>
<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 />
<label for="description">Description:</label>
<input type="text" id="description" />
<br />
<label for="image">Tournament Image:</label>
<Button variant="outlined" component="span" color="primary">
Upload
</Button>
</InputLabel>
<input
type="file"
id="image"
accept="image/png, image/jpeg, image/jpg"
id="editImage"
accept="image/png, image/jpeg, image/jpg, image/gif, image/svg"
style={{ display: 'none' }}
/>
<br />
<label for="date">Start Date:</label>
<input type="date" id="date" />
<input type="time" id="time" />
<br />
<InputLabel htmlFor="startDatePicker">Start Time:</InputLabel>
<TextField type="datetime-local" id="startDatePicker" />
<InputLabel htmlFor="endDatePicker">End Time:</InputLabel>
<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>
</>
);
@ -57,9 +158,7 @@ export default function CreateTournament(props) {
return (
<>
<Appbar />
<CreateForm />
<ParticipantLimit />
<CreateButton />
<TournamentForm />
</>
);
}

View File

@ -9,18 +9,21 @@ import TournamentMatches from "./tournamentmatches";
import TeamEditor from "./teameditor";
import Appbar from './components/appbar';
import Button from "@mui/material/Button";
import Container from "@mui/material/Container";
import CssBaseline from "@mui/material/CssBaseline";
import Typography from "@mui/material/Typography";
import Grid from "@mui/material/Grid";
import Box from "@mui/material/Box";
import { Button, Container, Typography, Grid, Box } from "@mui/material";
import { Card, CardActions,CardACtionsArea, CardContent, CardHeader, CardMedia, Collapse, Paper } from "@mui/material";
import AddCircleIcon from '@mui/icons-material/AddCircle';
import { maxWidth } from "@mui/system";
function CreateButton(props) {
return (
<Link to="/create" style={{ textDecoration: "none" }}>
<Button variant="contained" color="primary">
<Button variant="contained" color="success" style={{ margin: '2.5% 0 0 0'}}>
<Box sx={{
marginRight: '2%',
}}>
Create Tournament
</Box>
<AddCircleIcon />
</Button>
</Link>
);
@ -36,38 +39,92 @@ function OverviewButton(props) {
);
}
function ListElement(props) {
function TournamentListItem(props) {
return (
<Container maxWidth="lg" align="start">
<Grid container spacing={2}>
<Grid item xs={5}>
<Typography noWrap>
{props.name}, {props.competitors} competitors, Date: {props.date}
<Container maxWidth="lg" align="start" sx={{
margin:'2.5% 0'
}}>
<Paper elevation={8}>
<Card>
<CardMedia
component="img"
alt="tournament image"
height="140"
image="https://source.unsplash.com/random"
/>
<CardContent>
<Typography variant="h3" component="div" align="center">
{props.tournament.name}
</Typography>
</Grid>
<Grid item>
<ManageButton />
</Grid>
<Grid item>
<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 />
</Grid>
</Grid>
</Box>
</Box>
</CardContent>
</Card>
</Paper>
</Container>
);
}
function TournamentList() {
let [data, setData] = React.useState(null);
let [tournamentList, setTournamentList] = React.useState([]);
React.useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((res) => res.json())
.then((data) => {
setData(data.data);
fetch("http://10.24.1.213:3000/api/tournament/getTournaments")
.then(res => res.json())
.then(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));
}, []);
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}/>
function Home() {
@ -75,10 +132,12 @@ function Home() {
<React.StrictMode>
<Appbar />
<main>
<Container>
<Box>
<Container align="center">
<CreateButton />
</Box>
<Typography variant="h2" style={{margin:'2% 0'}}>
Tournaments
</Typography>
<TournamentList />
{/* <ListElement
name="Weekend Warmup"
competitors="16"
@ -94,7 +153,7 @@ function Home() {
competitors="64"
date="01.05.2022"
/> */}
<TournamentList />
</Container>
</main>
<footer className="footer"></footer>
@ -108,8 +167,8 @@ export default function App() {
<Routes>
<Route path="/" element={<Home />} />
<Route path="/create" element={<CreateTournament />} />
<Route path="/tournament" element={<TournamentOverview />} />
<Route path="/tournament/manage" element={<TournamentManager />} />
<Route path="/tournament/" element={<TournamentOverview />} />
<Route path="/tournament/:id/manage" element={<TournamentManager />} />
<Route path="/tournament/teams" element={<TeamEditor />} />
<Route path="/tournament/matches" element={<TournamentMatches />} />
<Route

View File

@ -19,6 +19,13 @@ code {
}
.mainIcon{
height: 40px;
width: 40px;
height: 60px;
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 Appbar from './components/appbar';
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) {
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 (
<>
<form>
<label>Edit name: </label>
<input type="text" id="editName" />
<Container>
<InputLabel htmlFor="editName">Edit name: </InputLabel>
<TextField type="text" id="editName" />
<InputLabel htmlFor="editDesc">Edit description: </InputLabel>
<TextField type="text" id="editDesc" />
<InputLabel htmlFor="editImage">
Edit image:
<br />
<label>Edit description: </label>
<input type="text" id="editDesc" />
<br />
<label>Edit image: </label>
<Button variant="outlined" component="span" color="primary">
Upload
</Button>
</InputLabel>
<input
type="file"
id="editImage"
accept="image/png, image/jpeg, image/jpg"
accept="image/png, image/jpeg, image/jpg, image/gif, image/svg"
style={{ display: 'none' }}
/>
<br />
<label>Edit start time: </label>
<input type="date" id="editDate" />
<input type="time" id="editTime" />
<br />
<br />
<InputLabel htmlFor="editStartDate">Edit Start Time:</InputLabel>
<TextField type="datetime-local" id="editStartDate" />
<InputLabel htmlFor="editEndDate">Edit End Time:</InputLabel>
<TextField type="datetime-local" id="editEndDate" />
</Container>
</form>
</>
);
@ -34,7 +63,7 @@ function ManageTournament(props) {
function AnnounceButton(props) {
return (
<Link to="/tournament/manage/announcement">
<button id="sendAnnon">Send Tournament Announcement</button>
<Button id="sendAnnon" variant="outlined" color="primary">Send Tournament Announcement</Button>
</Link>
);
}
@ -50,14 +79,13 @@ function InviteButton(props) {
const alertSuccess = () =>
alert({ message: "Copied to clipboard.", type: "success" });
return (
<button id="createInvLink" onClick={event}>
<Button id="createInvLink" onClick={event} variant="outlined" color="primary">
Copy Invite Link
</button>
</Button>
);
}
//navigator.clipboard.writeText("discord.gg/asura")
export default function TournamentManager() {
export default function TournamentManager(props) {
return (
<>
<Appbar />

View File

@ -1,11 +1,37 @@
import * as React from "react";
import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom";
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() {
return (
<>
<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 Appbar from './components/appbar';
function MatchHistory() {
return(
`Hei`
);
}
export default function TournamentMatches() {
return (
<>
<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 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 (
<>
brackets = []
knownTeams = [2,4,8,16,32,64,128,256]
{new Array(groups).map((group, i) => {
return (
<div>Group {i}</div>
);
})}
</>
);
}
function ViewTournament(params) {
function OverviewButtons(params) {
return (
<>
<div id="touOverview"></div>
<Link to="/tournament/teams">
<button id="manageTeams">Manage Teams </button>
</Link>
<Link to="/tournament/matches">
<button id="touMaches">Tournament Matches</button>
</Link>
{/* <Link to="/tournament/matches">
<button id="touMatches">Tournament Matches</button>
</Link> */}
</>
);
}
export default function TournamentOverview(props) {
// Use-effect hook here
return (
<>
<Appbar />
<ManageButton />
<ViewTournament />
<RenderBrackets />
<OverviewButtons />
</>
);
}