diff --git a/src/client/public/favicon.png b/src/client/public/favicon.png new file mode 100644 index 0000000..d48dfd8 Binary files /dev/null and b/src/client/public/favicon.png differ diff --git a/src/client/public/react.ico b/src/client/public/react.ico new file mode 100644 index 0000000..b853624 Binary files /dev/null and b/src/client/public/react.ico differ 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;