From 176c0b5ad47e2941c0c6b880c08ae62607941741 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sat, 23 Apr 2022 13:34:00 +0200 Subject: [PATCH] Dev session, graphics, prizes, login --- src/client/public/favicon.png | Bin 0 -> 12544 bytes src/client/public/react.ico | Bin 0 -> 41662 bytes src/client/src/AdminsOverview.js | 4 +- src/client/src/FrontPage.js | 47 +++++-- src/client/src/LoginPage.js | 9 +- src/client/src/TournamentCreator.js | 15 +- src/client/src/TournamentHistory.js | 5 +- src/client/src/TournamentManager.js | 54 +++----- src/client/src/TournamentOverview.js | 131 +++++++----------- src/client/src/TournamentTeams.js | 8 +- src/client/src/components/SuccessSnackbar.js | 29 ++++ src/client/src/components/TournamentBar.js | 4 +- .../src/components/tournamentBracket.css | 2 +- 13 files changed, 155 insertions(+), 153 deletions(-) create mode 100644 src/client/public/favicon.png create mode 100644 src/client/public/react.ico create mode 100644 src/client/src/components/SuccessSnackbar.js diff --git a/src/client/public/favicon.png b/src/client/public/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..d48dfd8a1d6f7b12acb8b04a905111a8753a79af GIT binary patch literal 12544 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 literal 0 HcmV?d00001 diff --git a/src/client/src/AdminsOverview.js b/src/client/src/AdminsOverview.js index f04db42..a7be8fe 100644 --- a/src/client/src/AdminsOverview.js +++ b/src/client/src/AdminsOverview.js @@ -60,7 +60,7 @@ function AdminCreator(props){ function AdminList(props){ 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(data => { if(data.status !== "OK"){ @@ -108,7 +108,7 @@ export default function Admins(props) { const { adminId } = useParams(); 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((data) =>{ if(data.status !== "OK") { diff --git a/src/client/src/FrontPage.js b/src/client/src/FrontPage.js index f27f039..062d5ea 100644 --- a/src/client/src/FrontPage.js +++ b/src/client/src/FrontPage.js @@ -1,5 +1,6 @@ import * as React from "react"; import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom"; + import TournamentCreator from "./TournamentCreator.js"; import TournamentOverview from "./TournamentOverview.js"; import TournamentManager from "./TournamentManager.js"; @@ -8,6 +9,10 @@ import TournamentTeams from "./TournamentTeams"; import LoginPage from "./LoginPage"; import ProfilePage from "./ProfilePage"; 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 AddCircleIcon from '@mui/icons-material/AddCircle'; import KeyboardDoubleArrowDownIcon from '@mui/icons-material/KeyboardDoubleArrowDown'; @@ -111,6 +116,8 @@ function TournamentListItem(props) { Players: {props.tournament.teamCount} / {props.tournament.teamLimit} + Prize: {props.tournament.prize} + @@ -131,8 +138,6 @@ function TournamentListItem(props) { - - Prize: {props.tournament.teamCount} @@ -157,7 +162,7 @@ function TournamentList() { for (let i = 0; i < tournaments.length; i++) { tournaments[i].startTime = new Date(tournaments[i].startTime); 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]) } } @@ -209,7 +214,7 @@ class LoginManager { .then(res => res.json()) .then(data => { if (data.status !== "OK") { - console.error(data); + console.error(data.data); return; } console.log(data); @@ -229,21 +234,45 @@ class LoginManager { let login = new LoginManager(); login.checkLogin(); + +let showSuccess = (message) => {}; +let showError = (message) => {}; + 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 ( - } /> - } /> + } /> + } /> } /> - } /> - } /> - } /> + } /> + } /> + } /> } /> } /> + } /> + + + ); } diff --git a/src/client/src/LoginPage.js b/src/client/src/LoginPage.js index e3d4579..63599ce 100644 --- a/src/client/src/LoginPage.js +++ b/src/client/src/LoginPage.js @@ -5,11 +5,6 @@ import ErrorSnackbar from "./components/ErrorSnackbar"; import {Button, Textfield, Stack, InputLabel, Paper, Typography} from '@mui/material'; - -function ProfileView() { - return "lol"; -} - export default function LoginPage() { return ( <> @@ -17,9 +12,9 @@ export default function LoginPage() { Sign in with google - + Sign in with google - + diff --git a/src/client/src/TournamentCreator.js b/src/client/src/TournamentCreator.js index a589981..aba7cd4 100644 --- a/src/client/src/TournamentCreator.js +++ b/src/client/src/TournamentCreator.js @@ -9,7 +9,7 @@ import AdapterDateFns from '@mui/lab/AdapterDateFns'; import LocalizationProvider from '@mui/lab/LocalizationProvider'; import { setDate } from "date-fns"; -function postTournament(showError, tournamentName, tournamentDescription, tournamentStartDate, tournamentEndDate, tournamentMaxTeams) { +function postTournament(tournamentName, tournamentDescription, tournamentStartDate, tournamentEndDate, tournamentMaxTeams, tournamentPrize) { if (!tournamentName || tournamentName === "") { showError("Tournament name cannot be empty"); return; @@ -44,10 +44,10 @@ function postTournament(showError, tournamentName, tournamentDescription, tourna 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); + formData.append("prize", tournamentPrize) let body = new URLSearchParams(formData); 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 tournamentEnd = new Date(endTime.setSeconds(0, 0, 0)).valueOf() - new Date().getTimezoneOffset() * 60*1000; postTournament( - props.showError, document.getElementById("nameInput").value, document.getElementById("descriptionInput").value, tournamentStart, tournamentEnd, - maxTeams + maxTeams, + document.getElementById("prizeInput").value ); } @@ -110,6 +110,7 @@ function TournamentForm(props) { {/* Description: + @@ -156,10 +157,12 @@ function TournamentForm(props) { ); } +let showError = (message) => {}; + export default function TournamentCreator(props) { const [openError, setOpenError] = React.useState(false); const [errorMessage, setErrorMessage] = React.useState(""); - function showError(message) { + showError = (message) => { setOpenError(false); setErrorMessage(message); setOpenError(true); @@ -169,7 +172,7 @@ export default function TournamentCreator(props) { <> - + diff --git a/src/client/src/TournamentHistory.js b/src/client/src/TournamentHistory.js index c1d4223..75cbbdc 100644 --- a/src/client/src/TournamentHistory.js +++ b/src/client/src/TournamentHistory.js @@ -5,6 +5,8 @@ import AddCircleIcon from '@mui/icons-material/AddCircle'; import KeyboardDoubleArrowDownIcon from '@mui/icons-material/KeyboardDoubleArrowDown'; import KeyboardDoubleArrowUpIcon from '@mui/icons-material/KeyboardDoubleArrowUp'; import Appbar from './components/AsuraBar'; +import EmojiEventsIcon from '@mui/icons-material/EmojiEvents'; + function shorten(description, maxLength) { if (description.length > maxLength) { @@ -65,6 +67,7 @@ function shorten(description, maxLength) { + Prize: {props.tournament.prize} @@ -90,7 +93,7 @@ function shorten(description, maxLength) { for (let i = 0; i < tournaments.length; i++) { tournaments[i].startTime = new Date(tournaments[i].startTime); 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]) } } diff --git a/src/client/src/TournamentManager.js b/src/client/src/TournamentManager.js index 5ff4e41..694e0e6 100644 --- a/src/client/src/TournamentManager.js +++ b/src/client/src/TournamentManager.js @@ -2,7 +2,6 @@ import * as React from "react"; import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom"; // import { AlertContainer, alert } from "react-custom-alert"; import AppBar from "./components/AsuraBar"; -import ErrorSnackbar from "./components/ErrorSnackbar"; import TournamentBar from "./components/TournamentBar"; import { useParams } from "react-router-dom"; 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 tournamentStartDate = document.getElementById("editStartDate").value; let tournamentEndDate = document.getElementById("editEndDate").value; + let tournamentPrize = document.getElementById("editPrize").value if (!tournamentName || tournamentName === "") { showError("Tournament name cannot be empty"); @@ -61,6 +61,7 @@ let submitChanges = curryTournamentId => event => { formData.append("startDate", tournamentStartDate); formData.append("endDate", tournamentEndDate); // formData.append("teamLimit", tournamentMaxTeams); + formData.append("prize", tournamentPrize) let body = new URLSearchParams(formData); fetch(process.env.REACT_APP_API_URL + `/tournament/${tournamentId}/edit`, { @@ -70,7 +71,7 @@ let submitChanges = curryTournamentId => event => { .then((response) => response.json()) .then((data) => { if (data.status === "OK") { - alert("Tournament Changed successfully"); + showSuccess("Tournament Changed successfully"); window.location.href = `/tournament/${tournamentId}`; } else { showError(data.data); @@ -89,8 +90,7 @@ let deleteTournament = tournamentId => event => { .then((response) => response.json()) .then((data) => { if (data.status === "OK") { - // TODO: Replace alert with Snackbar - alert("Tournament Deleted successfully"); + showSuccess("Tournament Deleted successfully"); window.location.href = "/"; } else { showError(data.data); @@ -116,6 +116,7 @@ function ManageTournament(props) { document.getElementById("editName").value = data.data.name; 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 let startDate = new Date(data.data.startTime.slice(0, 16)); let endDate = new Date(data.data.endTime.slice(0, 16)); @@ -135,6 +136,7 @@ function ManageTournament(props) { + @@ -165,16 +167,10 @@ function ManageTournament(props) { ); } -function showError(error) { - alert("Something went wrong. \n" + error); - console.error(error); -} - function ConfirmationDialogRaw(props) { const { tournamentId } = useParams(); const { onClose, value: valueProp, open, ...other } = props; const [value, setValue] = React.useState(valueProp); - const radioGroupRef = React.useRef(null); React.useEffect(() => { if (!open) { @@ -210,32 +206,21 @@ function ConfirmationDialogRaw(props) { ConfirmationDialogRaw.propTypes = { onClose: PropTypes.func.isRequired, open: PropTypes.bool.isRequired, - value: PropTypes.string.isRequired, }; +let showError = (message) => {}; +let showSuccess = (message) => {}; + export default function TournamentManager(props) { const { tournamentId } = useParams(); - const [open, setOpen] = React.useState(false); - const [value, setValue] = React.useState(""); - - 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); - } + const [dialogOpen, setDialogOpen] = React.useState(false); + const handleDialogClickListItem = () => { setDialogOpen(true); }; + const handleDialogClose = () => { setDialogOpen(false); }; + showError = props.showError; + showSuccess = props.showSuccess; return ( - <> @@ -243,20 +228,17 @@ export default function TournamentManager(props) { {/* */} - - - ); } diff --git a/src/client/src/TournamentOverview.js b/src/client/src/TournamentOverview.js index dc9551a..f7fd094 100644 --- a/src/client/src/TournamentOverview.js +++ b/src/client/src/TournamentOverview.js @@ -18,12 +18,10 @@ function showError(error) { } function TournamentTier(props){ - const { tournamentId } = useParams(); - - let roundTypes = ["finals", "semifinals", "quarterfinals", "eighthfinals", "sixteenthfinals", "thirtysecondfinals"]; + let roundTypes = ["winner","finals", "semifinals", "quarterfinals", "eighthfinals", "sixteenthfinals", "thirtysecondfinals"]; let matches = []; for (let i = 0; i < props.matches.length; i++) { - matches.push(); + matches.push(); } return(
    @@ -45,15 +43,11 @@ function Match(props){ let setWinner = curryTeamId => event => { let teamId = curryTeamId; - console.log(teamId) + // console.log(teamId) if (!teamId || teamId == null) { showError("No team selected"); return; } - // if(props.match.winnerId === teamId){ - // showError("Team already won"); - // return; - // } let formData = new FormData(); formData.append("winnerId",teamId); let body = new URLSearchParams(formData); @@ -71,43 +65,40 @@ function Match(props){ } }) .catch(error => showError(error)); - } + }; - const [endTime, setendTime] = React.useState(null); - - 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 - console.error(data); - return; - } - let endTime = data.data.endTime; - setendTime(endTime); - }) - .catch(err => showError(err)); + let curryUnsetContestant = teamId => (e) => { + console.log("wack") + let formData = new FormData(); + formData.append("teamId", teamId); + 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 }) - - console.log(props) - - let today = new Date() - let yesterday = today.setDate(today.getDate() - 1) - let isComplete = new Date(endTime) < yesterday + .then(response => response.json()) + .then(data => { + if (data.status === "OK") { + console.log("wacky smacky"); + window.location.reload(); + } + }) + .catch(error => showError(error)); + } return ( <> {/* Team 1 (Winner-status?) (Team name) */} -
  • +
  • {team1Name} - { props.match.teamId !== null && !isComplete && props.match.tier !== Math.log2(4) - 1 && props.match.winnerId === null && team1Name !== "TBA" ? - : null + { props.match.team1Id !== null && !props.tournament.hasEnded && props.match.tier !== Math.log2(props.tournament.teamLimit) - 1 && props.match.winnerId === null ? + : null } - { props.match.team1Id !== null && props.match.winnerId === null && !isComplete && team1Name !== "TBA" ? + { props.match.team1Id !== null && props.match.winnerId === null && !props.tournament.hasEnded ? : null } {/* { props.match.winnerId && (props.match.team1Id === props.match.winnerId) && @@ -117,15 +108,15 @@ function Match(props){
  •  
  • {/* Team 2 (Winner-status?) (Team name) */} -
  • +
  • {team2Name} - { props.match.teamId !== null && !isComplete && props.match.tier !== Math.log2(props.maxTeams) - 1 && props.match.winnerId === null && team2Name !== "TBA" ? - : null + { props.match.team2Id !== null && !props.tournament.hasEnded && props.match.tier !== Math.log2(props.tournament.teamLimit) - 1 && props.match.winnerId === null ? + : null } - { props.match.team1Id !== null && props.match.winnerId === null && !isComplete && team2Name !== "TBA" ? + { props.match.team2Id !== null && props.match.winnerId === null && !props.tournament.hasEnded ? : null } {/* { props.match.winnerId && (props.match.team2Id === props.match.winnerId) && @@ -139,25 +130,11 @@ function Match(props){ } function BracketViewer(props){ - const [tournament, setTournament] = React.useState(null); + const [matches, setMatches] = React.useState(null); const [teams, setTeams] = React.useState(null); 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`) .then(res => res.json()) .then(data => { @@ -196,56 +173,46 @@ function BracketViewer(props){ .catch(err => showError(err)); }, []); return ( - (matches && teams) ? + (props.tournament && matches && teams) ? //
    {matches.map(tier => { let tierNum = tier[0].tier; - return + return })}
    : ); } -function RemovableBar(props) { - const [endTime, setendTime] = React.useState(null); - +export default function TournamentOverview(props) { + const { tournamentId } = useParams(); + const [tournament, setTournament] = React.useState(false); + 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(data => { if (data.status !== "OK") { - // Do your error thing - console.error(data); + showError(data.data); return; } - let endTime = data.data.endTime; - setendTime(endTime); + let tourn = data.data; + 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)); - }) - let today = new Date() - let yesterday = today.setDate(today.getDate() - 1) - let isComplete = new Date(endTime) < yesterday - if (isComplete) { - return (null) - } else { - return () - } -} - - -export default function TournamentOverview(props) { - const { tournamentId } = useParams(); + }, [tournamentId]); return ( <> - - { isLoggedIn ? - : null + + { isLoggedIn && !tournament.hasEnded ? + : null } - + ); } diff --git a/src/client/src/TournamentTeams.js b/src/client/src/TournamentTeams.js index 3d24409..90b1487 100644 --- a/src/client/src/TournamentTeams.js +++ b/src/client/src/TournamentTeams.js @@ -36,6 +36,7 @@ function TeamCreator(props) { } document.getElementById("teamNameInput").value = ""; props.onTeamCreated(); + } ) } @@ -108,14 +109,8 @@ function TeamList(props) { ); } -function PlayerList(props) { - // Something like https://react-list-editable.netlify.app/ - return

    PlayerList coming...

    -} - function TeamEditor(props) { const [team, setTeam] = React.useState({}); - const [players, setPlayers] = React.useState([]); React.useEffect(() => { if (props.selectedTeamId === -1) { setTeam({}); @@ -180,7 +175,6 @@ function TeamEditor(props) {

    Edit Team:

    - {/* */}
    diff --git a/src/client/src/components/SuccessSnackbar.js b/src/client/src/components/SuccessSnackbar.js new file mode 100644 index 0000000..c71b4de --- /dev/null +++ b/src/client/src/components/SuccessSnackbar.js @@ -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 ; +}); + +export default function showError(props) { + const handleClose = (event, reason) => { + if (reason === 'clickaway') { + return; + } + + props.setOpen(false); + }; + + return ( + + + + {props.message} + + + + ); +} diff --git a/src/client/src/components/TournamentBar.js b/src/client/src/components/TournamentBar.js index b196488..fec2168 100644 --- a/src/client/src/components/TournamentBar.js +++ b/src/client/src/components/TournamentBar.js @@ -31,7 +31,7 @@ function ClipboardButton(props) { function ButtonLink(props) { return ( - + ); } @@ -41,7 +41,7 @@ export default function TournamentBar(props) { return ( - + diff --git a/src/client/src/components/tournamentBracket.css b/src/client/src/components/tournamentBracket.css index bf8f409..7323480 100644 --- a/src/client/src/components/tournamentBracket.css +++ b/src/client/src/components/tournamentBracket.css @@ -10,7 +10,7 @@ display:flex; flex-direction:column; justify-content:center; - width:20vw; + width:20%; list-style:none; padding:0; font-size: 1.5rem;