Merge branch 'client' of gitlab.stud.idi.ntnu.no:felixalb/dcst1008-2022-group1 into client
This commit is contained in:
		
						commit
						76b8d06641
					
				| @ -3,10 +3,12 @@ import { BrowserRouter as Router, Link, Route, Routes, useParams } from "react-r | ||||
| import Appbar from "./components/AsuraBar"; | ||||
| import ErrorSnackbar from "./components/ErrorSnackbar"; | ||||
| import LoginPage from "./LoginPage"; | ||||
| import {Button, Box, TextField, Stack, InputLabel, Paper, TableContainer, Table, TableBody, TableHead, TableCell, TableRow, Typography, Select, MenuItem, FormControl} from '@mui/material'; | ||||
| import { Button, Box, TextField, Stack, InputLabel, Paper, TableContainer, Table, TableBody, TableHead, TableCell, TableRow, Typography, Select, MenuItem, FormControl } from '@mui/material'; | ||||
| import { Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from "@mui/material"; | ||||
| import AddCircleIcon from '@mui/icons-material/AddCircle'; | ||||
| import DeleteIcon from '@mui/icons-material/Delete'; | ||||
| import EditIcon from '@mui/icons-material/Edit'; | ||||
| import PropTypes from 'prop-types' | ||||
| 
 | ||||
| function AdminCreator(props){ | ||||
|     function postCreate(){ | ||||
| @ -37,17 +39,17 @@ function AdminCreator(props){ | ||||
|     } | ||||
| 
 | ||||
|     return ( | ||||
|         <Paper sx={{width: "90vw", margin: "10px auto", padding: "15px"}} component={Stack} direction="column"> | ||||
|         <Paper sx={{width: "90vw", margin: "10px auto", padding: "15px", align:'center', justifyContent:'center', flexGrow:1}} component={Stack} direction={['column']} spacing={2}> | ||||
|             <div align="center"> | ||||
|                 <form> | ||||
|                     <TextField id="adminEmailInput" sx={{ width: "70%" }} label="Admin Email" variant="outlined" type="email" /> | ||||
|                     {/* <Button variant="contained" color="primary" onClick={postCreate}>Create Team</Button> */} | ||||
|                     <Button type="submit" variant="contained" color="success" onClick={postCreate} sx={{width: "20%", marginLeft: "5px"}}> | ||||
|                         <Box sx={{padding: "10px"}}> | ||||
|                             Create Admin | ||||
|                         </Box> | ||||
|                         <AddCircleIcon /> | ||||
|                     </Button> | ||||
|                     <TextField id="adminEmailInput" label="Admin Email" variant="outlined" type="email" sx={{width:['auto','50%','60%','70%']}} /> | ||||
|                         {/* <Button variant="contained" color="primary" onClick={postCreate}>Create Team</Button> */} | ||||
|                         <Button type="submit" variant="contained" color="success" onClick={postCreate} sx={{marginLeft:['5px'],width:['fit-content','40%','30%','20%']}}> | ||||
|                             <Box sx={{padding: "10px"}}> | ||||
|                                 Create Admin | ||||
|                             </Box> | ||||
|                             <AddCircleIcon /> | ||||
|                         </Button> | ||||
|                 </form> | ||||
|             </div> | ||||
|         </Paper> | ||||
| @ -55,17 +57,20 @@ function AdminCreator(props){ | ||||
| } | ||||
| 
 | ||||
| function UserList(props){ | ||||
|     const deleteUsers = (userId) => { | ||||
|     const deleteUser = (userId) => { | ||||
|       openConfirmDialog(function() {  | ||||
|         fetch(process.env.REACT_APP_API_URL + `/users/${userId}`, {method: "DELETE"}) | ||||
|             .then(res => res.json()) | ||||
|             .then(data => { | ||||
|                 if(data.status !== "OK"){ | ||||
|                     showError(data.data); | ||||
|                     console.log("UWU") | ||||
|                     return; | ||||
|                 } | ||||
|                 props.setUsers(props.users.filter(user => user.id !== userId)); | ||||
|                 props.onUserUpdated(); | ||||
|             }) | ||||
|             .catch(error => showError(error)); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     let updateRank = (asuraId) => event => { | ||||
| @ -92,52 +97,99 @@ function UserList(props){ | ||||
|     return( | ||||
|         <Paper sx={{minHeight: "30vh", width:"90vw", margin:"10px auto"}} component={Stack} direction="column" justifycontent="center"> | ||||
|             <div align="center"> | ||||
|             {/* TODO: scroll denne menyen, eventuelt søkefelt */} | ||||
|                 <Table aria-label="simple table"> | ||||
|                     <TableHead> | ||||
|                         <TableRow> | ||||
|                             <TableCell>Name</TableCell> | ||||
|                             <TableCell>Email</TableCell> | ||||
|                             <TableCell>Rank</TableCell> | ||||
|                             <TableCell align="center">Actions</TableCell> | ||||
|               <Table aria-label="simple table"> | ||||
|                   <TableHead> | ||||
|                       <TableRow> | ||||
|                           <TableCell>Name</TableCell> | ||||
|                           <TableCell>Email</TableCell> | ||||
|                           <TableCell>Rank</TableCell> | ||||
|                           <TableCell align="center">Actions</TableCell> | ||||
|                       </TableRow> | ||||
|                   </TableHead> | ||||
|                   <TableBody> | ||||
|                       {props.users.map((user) => ( | ||||
|                           <TableRow key={user.asuraId}> | ||||
|                           <TableCell component="th" scope="row">  | ||||
|                           <b> | ||||
|                             {user.name} | ||||
|                           </b> | ||||
|                           </TableCell> | ||||
|                           <TableCell>{user.email}</TableCell> | ||||
|                           {/* TODO Drop down menu for selecting rank */} | ||||
|                           <TableCell> | ||||
|                               <FormControl variant="standard"> | ||||
|                                   <Select onChange={updateRank(user.asuraId)} value={user.isManager ? "manager" : "admin"} aria-label="rank" id="rankSelect"> | ||||
|                                       <MenuItem value={"manager"}>Manager</MenuItem> | ||||
|                                       <MenuItem value={"admin"}>Admin</MenuItem> | ||||
|                                   </Select> | ||||
|                               </FormControl> | ||||
|                           </TableCell> | ||||
|                           {/* <TableCell align="right">{team.members}</TableCell> */} | ||||
|                           <TableCell align="center"> | ||||
|                             {/* <Button variant="contained" sx={{margin: "auto 5px"}} color="primary" onClick={() => props.setSelectedTeamId(team.id)} endIcon={<EditIcon />}>Edit</Button> */} | ||||
|                             <Button variant="contained" sx={{margin: "auto 5px"}} color="error" onClick={() => {deleteUser(user.asuraId)}} endIcon={<DeleteIcon />}>Delete</Button> | ||||
|                           </TableCell> | ||||
|                         </TableRow> | ||||
|                     </TableHead> | ||||
|                     <TableBody> | ||||
|                         {props.users.map((user) => ( | ||||
|                             <TableRow key={user.asuraId}> | ||||
|                             <TableCell component="th" scope="row">  | ||||
|                             <b> | ||||
|                               {user.name} | ||||
|                             </b> | ||||
|                             </TableCell> | ||||
|                             <TableCell>{user.email}</TableCell> | ||||
|                             {/* TODO Drop down menu for selecting rank */} | ||||
|                             <TableCell> | ||||
|                                 <FormControl variant="standard"> | ||||
|                                     <Select onChange={updateRank(user.asuraId)} value={user.isManager ? "manager" : "admin"} label="rank" labelId="rankSelect" id="rankSelect"> | ||||
|                                         <MenuItem value={"manager"}>Manager</MenuItem> | ||||
|                                         <MenuItem value={"admin"}>Admin</MenuItem> | ||||
|                                     </Select> | ||||
|                                 </FormControl> | ||||
|                             </TableCell> | ||||
|                             {/* <TableCell align="right">{team.members}</TableCell> */} | ||||
|                             <TableCell align="center"> | ||||
|                               {/* <Button variant="contained" sx={{margin: "auto 5px"}} color="primary" onClick={() => props.setSelectedTeamId(team.id)} endIcon={<EditIcon />}>Edit</Button> */} | ||||
|                               <Button variant="contained" sx={{margin: "auto 5px"}} color="error" onClick={() => {deleteUsers(user.asuraId)}} endIcon={<DeleteIcon />}>Delete</Button> | ||||
|                             </TableCell> | ||||
|                           </TableRow> | ||||
|                         ))} | ||||
|                     </TableBody> | ||||
|                 </Table> | ||||
|                       ))} | ||||
|                   </TableBody> | ||||
|               </Table> | ||||
|             </div> | ||||
|         </Paper> | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| function ConfirmationDialogRaw(props) { | ||||
|   const { userId } = useParams(); | ||||
|   const { onClose, value: valueProp, open, ...other } = props; | ||||
|   const [value, setValue] = React.useState(valueProp); | ||||
| 
 | ||||
|   React.useEffect(() => { | ||||
|     if (!open) { | ||||
|       setValue(valueProp); | ||||
|     } | ||||
|   }, [valueProp, open]); | ||||
| 
 | ||||
|   const handleCancel = () => { | ||||
|     onClose(); | ||||
|   }; | ||||
|   const handleConfirm = () => { | ||||
|     onClose(); | ||||
|     props.handleconfirm(); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <Dialog | ||||
|       sx={{ '& .MuiDialog-paper': { width: '80%', maxHeight: 435 } }} | ||||
|       maxWidth="xs" | ||||
|       open={open} | ||||
|       keepMounted | ||||
|     > | ||||
|       <DialogTitle>Delete administrator?</DialogTitle> | ||||
|       <DialogContent> | ||||
|         Are you sure you want to delete the administrator? This action is not reversible! | ||||
|       </DialogContent> | ||||
|       <DialogActions> | ||||
|         <Button autoFocus onClick={handleCancel}> | ||||
|           Cancel | ||||
|         </Button> | ||||
|         <Button onClick={handleConfirm}>Confirm</Button> | ||||
|       </DialogActions> | ||||
|     </Dialog> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| ConfirmationDialogRaw.propTypes = { | ||||
|   onClose: PropTypes.func.isRequired, | ||||
|   open: PropTypes.bool.isRequired, | ||||
| }; | ||||
| 
 | ||||
| // Confirmation window for "Delete user"
 | ||||
| function openConfirmDialog(callback) {g_setDialogCallback(callback); g_setDialogOpen(true);} | ||||
| let g_setDialogOpen = () => {}; | ||||
| let g_setDialogCallback = (callback) => {}; | ||||
| 
 | ||||
| let showError = (message) => {}; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| export default function Users(props) { | ||||
| 
 | ||||
|     const [openError, setOpenError] = React.useState(false); | ||||
| @ -149,6 +201,12 @@ export default function Users(props) { | ||||
|     } | ||||
|     const [users, setUsers] = React.useState([]); | ||||
| 
 | ||||
|     const [dialogOpen, setDialogOpen] = React.useState(false); | ||||
|     const handleDialogClose = () => { setDialogOpen(false); }; | ||||
|     const [dialogOnConfirm, setDialogOnConfirm] = React.useState(() => {return function(){}}); | ||||
|     g_setDialogCallback = (callback) => { setDialogOnConfirm(()=>{ return callback })}; | ||||
|     g_setDialogOpen = (value) => { setDialogOpen(value); }; | ||||
| 
 | ||||
|     function getUsers() { | ||||
|         fetch(process.env.REACT_APP_API_URL + `/users/getUsers`) | ||||
|             .then((res) => res.json()) | ||||
| @ -186,6 +244,13 @@ export default function Users(props) { | ||||
|         </div> | ||||
| 
 | ||||
|         <ErrorSnackbar message={errorMessage} open={openError} setOpen={setOpenError} /> | ||||
|         <ConfirmationDialogRaw | ||||
|           id="confirmation-dialog" | ||||
|           keepMounted | ||||
|           open={dialogOpen} | ||||
|           onClose={handleDialogClose} | ||||
|           handleconfirm={dialogOnConfirm} | ||||
|         /> | ||||
|         </> | ||||
|     ); | ||||
| } | ||||
| @ -85,7 +85,7 @@ function TournamentListItem(props) { | ||||
|         </Box>) | ||||
|     } else { | ||||
|       return(<Box> | ||||
|         <Typography variant="body"> Starts in: </Typography> | ||||
|         <Typography variant="body"> Starts in: </Typography> <br /> | ||||
|         { remainingDays > 0 ? <Typography variant="body"> {remainingDays} days</Typography> : null } | ||||
|         { remainingHours > 0 ? <Typography variant="body"> {remainingHours} hours</Typography> : null } | ||||
|         { remainingMins > 0 ? <Typography variant="body"> {remainingMins} mins</Typography> : null } | ||||
| @ -105,26 +105,26 @@ function TournamentListItem(props) { | ||||
|               image="banner2.png" | ||||
|             /> | ||||
|             <CardContent align="left"> | ||||
|               <Typography variant="h3" component="div" align="center">{props.tournament.name} </Typography> | ||||
|               <Typography sx={{fontSize:['2rem','2.5rem','3rem']}} component="div" align="center">{props.tournament.name} </Typography> | ||||
|                | ||||
|               <Box component={Stack} direction="column"> | ||||
|                 <Typography variant="body"> Start: {props.tournament.startTime.toLocaleString()} </Typography> | ||||
|                 <Typography variant="body"> End: {props.tournament.endTime.toLocaleString()} </Typography> | ||||
|               </Box> | ||||
|                | ||||
|               <Typography variant="h5" color="text.primary" gutterBottom> Players: {props.tournament.teamCount} / {props.tournament.teamLimit} </Typography> | ||||
|               <Typography variant="h5" color="text.primary" gutterBottom> Particpants: {props.tournament.teamCount} / {props.tournament.teamLimit} </Typography> | ||||
|               <Description /> | ||||
|               <Typography variant="body" color="text.primary"><EmojiEventsIcon alt="A trohpy" color="gold"/>  Prize: {props.tournament.prize} </Typography> | ||||
|               <Countdown /> | ||||
|                | ||||
|               <Box sx={{flexGrow: 1, marginTop: "20px"}}> | ||||
|                 <Grid container spacing={4} justifyContent="center" wrap="wrap"> | ||||
|                     { props.user.isLoggedIn ? | ||||
|                 <Grid container spacing={2} justifyContent="center" wrap="wrap"> | ||||
|                     { props.user.isLoggedIn && | ||||
|                       <Grid item> | ||||
|                       <Link to={`/tournament/${props.tournament.id}/manage`}> | ||||
|                         <Button className="ManageButton" variant="contained" color="primary" endIcon={<EditIcon />}>Edit Tournament</Button> | ||||
|                       </Link> | ||||
|                     </Grid> : null | ||||
|                     </Grid> | ||||
|                     } | ||||
|                     <Grid item > | ||||
|                     <Link to={`/tournament/${props.tournament.id}`} > | ||||
| @ -182,7 +182,7 @@ function Home(props) { | ||||
|     <> | ||||
|       <Appbar user={props.user} pageTitle="Asura Tournaments" /> | ||||
|         <Container sx={{minHeight: "30vh", width: "90vw", padding: "20px 20px"}} component={Container} direction="column" align="center"> | ||||
|           <Box component={Stack} direction="row" align="center" justifyContent="space-between" alignItems="center" sx={{flexGrow: 1}}> | ||||
|         <Box component={Stack} direction={['column','row']} sx={{align:'center', justifyContent:'space-between', flexGrow:1}}> | ||||
|             <Typography sx={{fontSize:['1.5rem','2rem','2rem']}}>Tournaments</Typography> | ||||
|             { props.user.isLoggedIn ? | ||||
|               <CreateButton /> : null | ||||
|  | ||||
| @ -12,7 +12,6 @@ export default function ProfilePage(props) { | ||||
| 
 | ||||
|     return (<> | ||||
|         <Appbar user={props.user} pageTitle="Profile" /> | ||||
|         <Container sx={{minHeight: "30vh", width: "90vw", padding: "20px 20px"}} component={Container} direction="column" align="center"> | ||||
|             <Paper sx={{minHeight: "30vh", width: "90vw", margin: "10px auto"}} component={Stack} direction="column" justifyContent="center"> | ||||
|                 <div align="center"> | ||||
|                 <h2><b>Your profile</b></h2> | ||||
| @ -23,6 +22,5 @@ export default function ProfilePage(props) { | ||||
|                 </Box> | ||||
|                 </div> | ||||
|             </Paper> | ||||
|         </Container> | ||||
|     </>) | ||||
| } | ||||
| @ -113,7 +113,7 @@ function TournamentForm(props) { | ||||
|         <TextField type="text" id="prizeInput" label="Prize" placeholder="Prize" InputLabelProps={{shrink: true}}/>      | ||||
|         <Box flexGrow={1}> | ||||
|         <Grid container spacing={2} justifyContent="center"> | ||||
|           <Grid item xs={4}> | ||||
|           <Grid item xs={6}> | ||||
|           <LocalizationProvider dateAdapter={AdapterDateFns}> | ||||
|             <DateTimePicker label={"Start Time"} inputVariant="outlined" ampm={false} mask="____-__-__ __:__" format="yyyy-MM-dd HH:mm" inputFormat="yyyy-MM-dd HH:mm" value={startTime} | ||||
|               onChange={setStartTime} | ||||
| @ -121,8 +121,7 @@ function TournamentForm(props) { | ||||
|             /> | ||||
|             </LocalizationProvider> | ||||
|           </Grid> | ||||
|           <Grid item xs={4}> | ||||
|            | ||||
|           <Grid item xs={6}> | ||||
|           <LocalizationProvider dateAdapter={AdapterDateFns}> | ||||
|             <DateTimePicker label={"End Time"} inputVariant="outlined" ampm={false} mask="____-__-__ __:__" format="yyyy-MM-dd HH:mm" inputFormat="yyyy-MM-dd HH:mm" value={endTime} | ||||
|               onChange={setEndTime} | ||||
|  | ||||
| @ -54,7 +54,7 @@ function shorten(description, maxLength) { | ||||
|                   <Typography variant="body"> End: {props.tournament.endTime.toLocaleString()} </Typography> | ||||
|                 </Box> | ||||
|                  | ||||
|                 <Typography variant="h5" color="text.primary" gutterBottom> Players: {props.tournament.teamCount} / {props.tournament.teamLimit} </Typography> | ||||
|                 <Typography variant="h5" color="text.primary" gutterBottom> Participants: {props.tournament.teamCount} / {props.tournament.teamLimit} </Typography> | ||||
|                 <Description /> | ||||
|                 <Typography variant="body" color="text.primary"><EmojiEventsIcon alt="A trohpy" color="gold" align="vertical-center"/>  Prize: {props.tournament.prize} </Typography> | ||||
| 
 | ||||
| @ -150,8 +150,8 @@ export default function TournamentHistory(props) { | ||||
|       <> | ||||
|         <Appbar user={props.user} pageTitle="Tournament History" /> | ||||
|           <Container sx={{minHeight: "30vh", width: "90vw", padding: "20px 20px"}} component={Container} direction="column" align="center"> | ||||
|             <Box component={Stack} direction="row" align="center" justifyContent="space-between" alignItems="center" sx={{flexGrow: 1}}> | ||||
|               <Typography variant="h3">Past Tournaments</Typography> | ||||
|             <Box component={Stack} direction="row" align="center" justifyContent="center" alignItems="center" sx={{flexGrow: 1, margin:'2.5% 0'}}> | ||||
|               <Typography sx={{fontSize:['1.5rem','2rem','2rem']}}>Past Tournaments</Typography> | ||||
|             </Box> | ||||
|             <TournamentList /> | ||||
|           </Container> | ||||
|  | ||||
| @ -134,13 +134,13 @@ function ManageTournament(props) { | ||||
|   return ( | ||||
|     <> | ||||
|     <form> | ||||
|     <Stack sx={{minHeight: "30vh", margin: "10px auto"}} direction="column" justifyContent="center" spacing={2} align="center"> | ||||
|     <Stack sx={{minHeight: "30vh", margin: "1.5%"}} direction="column" justifyContent="center" spacing={2} align="center"> | ||||
|           <TextField type="text" id="editName" label="Edit Name:" placeholder="Edit Name" InputLabelProps={{shrink: true}}/> | ||||
|           <TextField type="text" multiline={true} id="editDesc" label="Edit Description:" placeholder="Edit Description" InputLabelProps={{shrink: true}} /> | ||||
|           <TextField type="text" id="editPrize" label="Edit Prize:" placeholder="Edit Prize" InputLabelProps={{shrink: true}}/> | ||||
|           <Box sx={{flexGrow: 1}}> | ||||
|           <Grid container spacing={2} justifyContent="center"> | ||||
|             <Grid item xs={4}> | ||||
|             <Grid item xs={6}> | ||||
|               <LocalizationProvider dateAdapter={AdapterDateFns}> | ||||
|                 <DateTimePicker label={"Start Time"} inputVariant="outlined" ampm={false} mask="____-__-__ __:__" format="yyyy-MM-dd HH:mm" inputFormat="yyyy-MM-dd HH:mm" value={startTime} | ||||
|                   onChange={setStartTime} | ||||
| @ -148,7 +148,7 @@ function ManageTournament(props) { | ||||
|                 /> | ||||
|               </LocalizationProvider> | ||||
|               </Grid> | ||||
|               <Grid item xs={4}> | ||||
|               <Grid item xs={6}> | ||||
|               <LocalizationProvider dateAdapter={AdapterDateFns}> | ||||
|                 <DateTimePicker label={"End Time"} inputVariant="outlined" ampm={false} mask="____-__-__ __:__" format="yyyy-MM-dd HH:mm:" inputFormat="yyyy-MM-dd HH:mm" value={endTime}              | ||||
|                   onChange={setEndTime} | ||||
| @ -219,8 +219,13 @@ export default function TournamentManager(props) { | ||||
|   const handleDialogClickListItem = () => { setDialogOpen(true); }; | ||||
|   const handleDialogClose = () => { setDialogOpen(false); }; | ||||
| 
 | ||||
|   showError = props.showError; | ||||
|   showSuccess = props.showSuccess; | ||||
|   const [openError, setOpenError] = React.useState(false); | ||||
|   const [errorMessage, setErrorMessage] = React.useState(""); | ||||
|   showError = (message) => { | ||||
|     setOpenError(false); | ||||
|     setErrorMessage(message); | ||||
|     setOpenError(true); | ||||
|   } | ||||
| 
 | ||||
|   if (!props.user.isLoggedIn) { return <LoginPage user={props.user} />; } | ||||
| 
 | ||||
| @ -229,7 +234,7 @@ export default function TournamentManager(props) { | ||||
|     <Appbar user={props.user} pageTitle="Edit Tournament" /> | ||||
|     <TournamentBar pageTitle="Edit Tournament"/> | ||||
|     <Paper sx={{minHeight: "30vh", width: "90vw", margin: "20px auto", padding: "20px 0"}} component={Container} direction="column" align="center"> | ||||
|       <ManageTournament tournamentId={tournamentId} showError={showError} /> | ||||
|       <ManageTournament tournamentId={tournamentId} /> | ||||
|       {/* <AnnounceButton /> */} | ||||
|       <Box sx={{width: "100%"}}> | ||||
|         <Button variant="contained" color="error" onClick={handleDialogClickListItem} sx={{margin: "auto 5px"}} endIcon={<DeleteIcon />}> | ||||
|  | ||||
| @ -1,19 +0,0 @@ | ||||
| import * as React from "react"; | ||||
| import { BrowserRouter as Router, Link, Route, Routes } from "react-router-dom"; | ||||
| import Appbar from './components/AsuraBar'; | ||||
| 
 | ||||
| function MatchHistory() { | ||||
| 
 | ||||
|   return( | ||||
|     `Hei på deg din gamle sei` | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default function TournamentMatches(props) { | ||||
|   return ( | ||||
|     <> | ||||
|       <Appbar user={props.user} /> | ||||
|       <MatchHistory /> | ||||
|     </> | ||||
|   ); | ||||
| } | ||||
| @ -16,12 +16,12 @@ function TournamentTier(props){ | ||||
|   let roundTypes = ["finals", "semifinals", "quarterfinals", "eighthfinals", "sixteenthfinals", "thirtysecondfinals"]; | ||||
|     let matches = []; | ||||
|       for (let i = 0; i < props.matches.length; i++) { | ||||
|         matches.push(<Match tournament={props.tournament} user={props.user} tier={props.tier} roundTypes={roundTypes} teams={props.teams} match={props.matches[i]} key={i} />); | ||||
|         matches.push(<Match tournament={props.tournament} user={props.user} tier={props.tier} roundTypes={roundTypes} teams={props.teams} match={props.matches[i]} key={i} onwinnerchange={props.onwinnerchange} />); | ||||
|       } | ||||
|       return( | ||||
|         <> | ||||
|         <Box className={`round ${roundTypes[props.tier]}`} sx={{width:['100px', '150px', '200px', '250px', '400px']}}> | ||||
|           <li className="spacer"> </li> | ||||
|         <Box component='ul' className={`round ${roundTypes[props.tier]}`} sx={{width:['125px','200px','250px','300px','350px']}}> | ||||
|           <Box component='li' className="spacer"> </Box> | ||||
|           {matches} | ||||
|         </Box> | ||||
|         </> | ||||
| @ -40,7 +40,6 @@ function Match(props){ | ||||
| 
 | ||||
|   let setWinner = curryTeamId => event => { | ||||
|     let teamId = curryTeamId; | ||||
|     // console.log(teamId)
 | ||||
|     if (!teamId || teamId == null) { | ||||
|       showError("No team selected"); | ||||
|       return; | ||||
| @ -56,7 +55,7 @@ function Match(props){ | ||||
|       .then(data => { | ||||
|         if (data.status === "OK") { | ||||
|           //Refresh when winner is set successfully
 | ||||
|           window.location.reload(); | ||||
|           props.onwinnerchange(); | ||||
|         } else { | ||||
|           showError(data.data) | ||||
|         } | ||||
| @ -65,11 +64,9 @@ function Match(props){ | ||||
|   }; | ||||
| 
 | ||||
|   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 | ||||
| @ -77,8 +74,9 @@ function Match(props){ | ||||
|       .then(response => response.json()) | ||||
|       .then(data => { | ||||
|         if (data.status === "OK") { | ||||
|           // console.log("wacky smacky");
 | ||||
|           window.location.reload(); | ||||
|           props.onwinnerchange() | ||||
|         } else { | ||||
|           showError(data.data); | ||||
|         } | ||||
|       }) | ||||
|       .catch(error => showError(error)); | ||||
| @ -87,51 +85,94 @@ function Match(props){ | ||||
|   return ( | ||||
|     <> | ||||
|         {/* Team 1 (Winner-status?) (Team name) */} | ||||
|         <li className={`game game-top`}> | ||||
|           <Stack direction={"row"} alignItems="center" spacing={1}> | ||||
|               <Typography noWrap className={`${props.match.winnerId !== null ? (props.match.team1Id === props.match.winnerId) ? "winner"  : "loser" : ""}`} align={'center'} sx={{ maxWidth:'70%', overflow:'hidden', wordWrap:'none', fontSize:['2vh', '1.5vh', '2vh', '3vh', '3.5vh', '4vh']}}> | ||||
|         <Box component='li' className={`game game-top`}> | ||||
|           <Stack direction={"row"} alignItems="center" spacing={1} sx={{justifyContent:['start','space-between']}}> | ||||
|               <Typography noWrap className={`${props.match.winnerId !== null ? (props.match.team1Id === props.match.winnerId) ? "winner"  : "loser" : ""}`} align={'center'} sx={{ maxWidth:'70%', overflow:'hidden', wordWrap:'none', fontSize:['1em','1em','1.5em','1.75em']}}> | ||||
|                 {team1Name} | ||||
|               </Typography> | ||||
|               { props.match.winnerId && (props.match.team1Id === props.match.winnerId) && | ||||
|               <EmojiEventsIcon alt="A trohpy" /> | ||||
|               <EmojiEventsIcon alt="A trohpy" sx={{width:['0.75em','1em','1.25em'], height:['0.75em','1em','1.25em']}} /> | ||||
|               } | ||||
|               <Box component={Stack} direction={'row'} spacing={-1.25}> | ||||
|               { props.match.team1Id !== null && !props.tournament.hasEnded && props.match.tier !== Math.log2(props.tournament.teamLimit) - 1 && props.match.winnerId === null && props.user.isLoggedIn && | ||||
|               <IconButton color="error" aria-label="remove winner" component="span" onClick={curryUnsetContestant(props.match.team1Id)}><BackspaceIcon /></IconButton> | ||||
|                 <IconButton color="error" aria-label="remove winner" component="span" onClick={curryUnsetContestant(props.match.team1Id)}><BackspaceIcon sx={{width:['0.75em','1em','1.25em'], height:['0.75em','1em','1.25em']}} /></IconButton> | ||||
|               } | ||||
|               { props.match.team1Id !== null && props.match.winnerId === null && !props.tournament.hasEnded && props.user.isLoggedIn && | ||||
|               <IconButton onClick={setWinner(props.match.team1Id)} color="success" aria-label="select winner" component="span"><AddCircleIcon /></IconButton> | ||||
|               <IconButton onClick={setWinner(props.match.team1Id)} color="success" aria-label="select winner" component="span"><AddCircleIcon sx={{width:['0.75em','1em','1.25em'], height:['0.75em','1em','1.25em']}} /></IconButton> | ||||
|               } | ||||
|               </Box> | ||||
|           </Stack> | ||||
|         </li> | ||||
|         <li className="game game-spacer"> </li> | ||||
|         </Box> | ||||
|         <Box component='li' className="game game-spacer"> </Box> | ||||
|         {/* Team 2 (Winner-status?) (Team name) */} | ||||
|         <li className={`game game-bottom`}> | ||||
|         <Stack direction={"row"} alignItems="center"> | ||||
|               <Typography noWrap className={`${props.match.winnerId !== null ? (props.match.team2Id === props.match.winnerId) ? "winner" : "loser" : ""}`} sx={{maxWidth:'70%', overflow:'hidden', wordWrap:'none',fontSize:['2vh', '1.5vh', '2vh', '3vh', '3.5vh', '4vh']}}> | ||||
|         <Box component='li' className={`game game-bottom`}> | ||||
|         <Stack direction={"row"} alignItems="center" sx={{justifyContent:['start','space-between']}}> | ||||
|               <Typography noWrap className={`${props.match.winnerId !== null ? (props.match.team2Id === props.match.winnerId) ? "winner" : "loser" : ""}`} sx={{maxWidth:'70%', overflow:'hidden', wordWrap:'none',fontSize:['1em','1em','1.5em','1.75em']}}> | ||||
|                 {team2Name} | ||||
|               </Typography> | ||||
|               { props.match.winnerId && (props.match.team2Id === props.match.winnerId) && | ||||
|               <EmojiEventsIcon alt="A trohpy" /> | ||||
|               <EmojiEventsIcon alt="A trohpy" sx={{width:['0.75em','1em','1.25em'], height:['0.75em','1em','1.25em']}} /> | ||||
|               } | ||||
|               { props.match.team2Id !== null && !props.tournament.hasEnded && props.match.tier !== Math.log2(props.tournament.teamLimit) - 1 && props.match.winnerId === null && props.user.isLoggedIn && | ||||
|               <IconButton color="error" aria-label="remove winner" component="span" onClick={curryUnsetContestant(props.match.team2Id)}><BackspaceIcon /></IconButton> | ||||
|               <IconButton color="error" aria-label="remove winner" component="span" onClick={curryUnsetContestant(props.match.team2Id)}><BackspaceIcon sx={{width:['0.75em','1em','1.25em'], height:['0.75em','1em','1.25em']}} /></IconButton> | ||||
|               } | ||||
|               { props.match.team2Id !== null && props.match.winnerId === null && !props.tournament.hasEnded && props.user.isLoggedIn && | ||||
|               <IconButton onClick={setWinner(props.match.team2Id)} color="success" aria-label="select winner" component="span"><AddCircleIcon /></IconButton> | ||||
|               <IconButton onClick={setWinner(props.match.team2Id)} color="success" aria-label="select winner" component="span" ><AddCircleIcon sx={{width:['0.75em','1em','1.25em'], height:['0.75em','1em','1.25em']}} /></IconButton> | ||||
|               } | ||||
|             </Stack> | ||||
|         </li> | ||||
|         <li className="spacer"> </li> | ||||
|         </Box> | ||||
|         <Box component='li' className="spacer"> </Box> | ||||
|     </> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function WinnerDisplay(props) { | ||||
|   let unsetWinner = event => { | ||||
|     let formData = new FormData(); | ||||
|     formData.append("winnerId","null"); | ||||
|     let body = new URLSearchParams(formData); | ||||
|     fetch(process.env.REACT_APP_API_URL + `/match/${props.finalMatch.id}/setWinner`, { | ||||
|       method: "POST", | ||||
|       body: body | ||||
|     }) | ||||
|       .then(response => response.json()) | ||||
|       .then(data => { | ||||
|         if (data.status !== "OK") { showError(data.data); return;} | ||||
|         props.onwinnerchange(); | ||||
|       }) | ||||
|       .catch(error => showError(error)); | ||||
|   }; | ||||
|            | ||||
| 
 | ||||
| 
 | ||||
|   if (!props.team) { | ||||
|     // Winner is not yet chosen
 | ||||
|     return <div className="winnerDisplay"> | ||||
|       <Typography sx={{fontSize:['1em','1em','1.5em','2em']}}> | ||||
|         Winner is not chosen.<br /> Will it be you? | ||||
|       </Typography> | ||||
|     </div>; | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="winnerDisplay"> | ||||
|       <Typography align="center"> | ||||
|         {props.user.isLoggedIn && !props.tournament.hasEnded && <IconButton color="error" aria-label="remove winner" component="span" onClick={unsetWinner}><BackspaceIcon /></IconButton>} | ||||
|       </Typography> | ||||
|       <Typography sx={{fontSize:['1em','1em','1.5em','2em']}} className="winner"> | ||||
|         {props.team.name} | ||||
|       </Typography> | ||||
|       <EmojiEventsIcon alt="A trohpy" /> | ||||
|     </div> | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| function BracketViewer(props){ | ||||
|    | ||||
|   const [matches, setMatches] = React.useState(null); | ||||
|   const [teams, setTeams] = React.useState(null); | ||||
| 
 | ||||
|   React.useEffect(() => { | ||||
|   let getMatches = () => { | ||||
|     fetch(process.env.REACT_APP_API_URL + `/tournament/${props.tournamentId}/getMatches`) | ||||
|       .then(res => res.json()) | ||||
|       .then(data => { | ||||
| @ -140,20 +181,18 @@ function BracketViewer(props){ | ||||
|           console.error(data); | ||||
|           return; | ||||
|         } | ||||
|         let matches = data.data; | ||||
|         let allMatches = data.data; | ||||
|         // Group all matches by their round/tier
 | ||||
|         let tiers = matches.reduce((tiers, match) => { | ||||
|         let tiers = allMatches.reduce((tiers, match) => { | ||||
|           if (!tiers[match.tier]) { | ||||
|             tiers[match.tier] = []; | ||||
|           } | ||||
|           tiers[match.tier].push(match); | ||||
|           console.log(tiers) | ||||
|           return tiers; | ||||
|         }, {}); | ||||
| 
 | ||||
|         tiers = Object.values(tiers); | ||||
|         tiers = tiers.reverse(); | ||||
|          | ||||
|         setMatches(tiers); | ||||
|       }) | ||||
|       .catch(err => showError(err)); | ||||
| @ -169,19 +208,35 @@ function BracketViewer(props){ | ||||
|         setTeams(teams); | ||||
|       }) | ||||
|       .catch(err => showError(err)); | ||||
|   } | ||||
|   React.useEffect(() => { | ||||
|     getMatches(); | ||||
|   }, []); | ||||
| 
 | ||||
|   let getFinalMatch = (tierMatches) => { | ||||
|     let finalMatch = tierMatches[tierMatches.length - 1][0]; | ||||
|     return finalMatch; | ||||
|   }; | ||||
|   let getWinnerTeam = (tierMatches) => { | ||||
|     let finalMatch = getFinalMatch(tierMatches); | ||||
|     if (finalMatch.winnerId === null) { return null;} | ||||
|     let winnerTeam = teams.find(team => team.id === finalMatch.winnerId); | ||||
|     return winnerTeam; | ||||
|   }; | ||||
|    | ||||
|   return ( | ||||
|      | ||||
|       (props.tournament && matches && teams) ? | ||||
|         // <div sx={{width: "100vw", height: "80vh", overflow: "scroll"}} className="bracket">
 | ||||
|         <> | ||||
|         <div className="bracket"> | ||||
|         {matches.map(tier => { | ||||
|             let tierNum = tier[0].tier; | ||||
|             return <TournamentTier user={props.user} tournament={props.tournament} key={tierNum} tier={tierNum} matches={tier} teams={teams} /> | ||||
|         {matches.map(tierMatches => { | ||||
|             let tierNum = tierMatches[0].tier; | ||||
|             return <TournamentTier user={props.user} tournament={props.tournament} key={tierNum} tier={tierNum} matches={tierMatches} teams={teams} onwinnerchange={getMatches} /> | ||||
|           })} | ||||
|          | ||||
|         <WinnerDisplay team={getWinnerTeam(matches)} user={props.user} finalMatch={getFinalMatch(matches)} onwinnerchange={getMatches} tournament={props.tournament} /> | ||||
|         </div> | ||||
|           | ||||
|        </> | ||||
|       : <Box sx={{display:'flex', justifyContent:'center', alignItems:'center', position:'relative', marginTop:'5%'}}><CircularProgress size={"20vw"}/></Box>    | ||||
|   ); | ||||
|  | ||||
| @ -39,12 +39,12 @@ function TeamCreator(props) { | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|     <Paper sx={{width: "90vw", margin: "10px auto", padding: "15px"}} component={Stack} direction="column"> | ||||
|     <Paper sx={{width: "90vw", margin: "10px auto", padding: "15px", align:'center', justifyContent:'center', flexGrow:1}} component={Stack} direction={['column']} spacing={2}> | ||||
|       <div align="center"> | ||||
|         <form> | ||||
|         <TextField id="teamNameInput" sx={{ width: "70%" }} label="Team Name" variant="outlined" /> | ||||
|         <TextField id="teamNameInput" sx={{width:['auto','50%','60%','70%'], margin:'1% 0'}} label="Team Name" variant="outlined" /> | ||||
|         {/* <Button variant="contained" color="primary" onClick={postCreate}>Create Team</Button> */} | ||||
|         <Button type="submit" variant="contained" color="success" onClick={postCreate} sx={{width: "20%", marginLeft: "5px"}}> | ||||
|         <Button type="submit" variant="contained" color="success" onClick={postCreate} sx={{ margin:'1% 1%',width:['fit-content','40%','30%','20%']}}> | ||||
|           <Box sx={{padding: "10px"}}> | ||||
|             Create Team | ||||
|           </Box> | ||||
|  | ||||
| @ -31,10 +31,10 @@ function LoggedInMenu(props) { | ||||
|         <Menu anchorEl={anchorEl} open={open} onClose={handleClose} MenuListProps={{'aria-labelledby': 'basic-button',}} sx={{position:"absolute"}}> | ||||
|           <Link to="/profile" style={{color:"black"}}><MenuItem onClick={handleClose}><Button startIcon={<AccountCircleIcon />}>{props.user.name}</Button></MenuItem></Link> | ||||
|           <Link to="/history" style={{color:"black"}}><MenuItem onClick={handleClose}><Button startIcon={<HistoryIcon />}>History</Button></MenuItem></Link> | ||||
|           <Link to="/api/logout" style={{color:"black"}}><MenuItem onClick={logout}><Button startIcon={<LogoutIcon />} >Logout</Button></MenuItem></Link> | ||||
|           { props.user.isManager &&  | ||||
|           <Link to="/admins" style={{color:"black"}}><MenuItem onClick={handleClose}><Button startIcon={<EditIcon />} >Admins</Button></MenuItem></Link> | ||||
|           } | ||||
|            <a href={`${process.env.REACT_APP_API_URL}/users/logout`} style={{color:"black"}}><MenuItem onClick={logout}><Button startIcon={<LogoutIcon />} >Logout</Button></MenuItem></a> | ||||
|       </Menu>  | ||||
|     </>  | ||||
|   );   | ||||
| @ -67,19 +67,19 @@ export default function Appbar(props) { | ||||
|               <Grid item xs={2}> | ||||
|               <Box sx={{ width:"100%", height: "100%", justifyContent:"left", align: "center", alignItems:"center", margin: "none", padding: "none", color: "white" ,display: "flex", flexFlow: "row"}}> | ||||
|                 <Link to="/"> | ||||
|                   <img sx={{width: "10%"}} src={logo} alt="Tournament logo" className="mainIcon"></img> | ||||
|                   <Box component="img" src={logo} alt="Tournament logo" className="mainIcon" sx={{height:['55px','65px'], width:['55px','65px']}}></Box> | ||||
|                 </Link> | ||||
|                   { props.pageTitle !== "Asura Tournaments" && | ||||
|                   <Link to="/" style={{color:"white"}}> | ||||
|                     <Typography component="div" align="center"> | ||||
|                     <Typography component="div" align="center" sx={{fontSize:['1em','1em','1.5em','2em']}}> | ||||
|                           Home | ||||
|                     </Typography> | ||||
|                   </Link> | ||||
|                   } | ||||
|               </Box> | ||||
|               </Grid>     | ||||
|               <Grid item xs={2} sm={3} md={4} lg={6} xl={8}> | ||||
|                 <Typography component="div" sx={{fontSize:['0.5rem','1rem','1.5rem','2rem']}}>{props.pageTitle || ""}</Typography> | ||||
|               <Grid item xs={4} md={6} lg={8}> | ||||
|                 <Typography component="div" sx={{fontSize:['1em','1em','1.5em','2em']}}>{props.pageTitle || ""}</Typography> | ||||
|               </Grid> | ||||
|               { props.pageTitle !== "Login" ? | ||||
|                 <Grid item xs={2}> | ||||
|  | ||||
| @ -3,6 +3,11 @@ import { useParams } from "react-router-dom"; | ||||
| import { BrowserRouter as Router, Link, Route, Routes, History } from "react-router-dom"; | ||||
| import { Stack, Paper, Typography, Box, Button, Grid, Snackbar, IconButton } from "@mui/material" | ||||
| import CloseIcon from '@mui/icons-material/Close'; | ||||
| import MuiAlert from '@mui/material/Alert'; | ||||
| 
 | ||||
| const Alert = React.forwardRef(function Alert(props, ref) { | ||||
|   return <MuiAlert elevation={6} ref={ref} variant="filled" {...props} />; | ||||
| }); | ||||
| 
 | ||||
| function ClipboardButton(props) { | ||||
|   const [open, setOpen] = React.useState(false); | ||||
| @ -22,8 +27,12 @@ function ClipboardButton(props) { | ||||
|      | ||||
|   return ( | ||||
|     <> | ||||
|       <Button onClick={copyString} variant="outlined" color="primary" sx={{margin: "auto 5px"}} >Copy {props.name}</Button> | ||||
|       <Snackbar open={open} autoHideDuration={1500} onClose={handleClose} message={props.name + " copied to clipboard"} action={closeAction} /> | ||||
|       <Button onClick={copyString} variant="outlined" color="primary" sx={{margin:'1.5%', fontSize:['0.75em']}} >Copy {props.name}</Button> | ||||
|       <Snackbar open={open} autoHideDuration={1500} onClose={handleClose} action={closeAction}> | ||||
|         <Alert onClose={handleClose} severity="info" sx={{ width: '100%' }}> | ||||
|           {props.name + " copied to clipboard"} | ||||
|         </Alert> | ||||
|       </Snackbar> | ||||
|     </> | ||||
|   ); | ||||
| } | ||||
| @ -31,7 +40,7 @@ function ClipboardButton(props) { | ||||
| function ButtonLink(props) { | ||||
|   return ( | ||||
|     <Link to={`/tournament/${props.tournamentId}` + props.targetPath} > | ||||
|         <Button variant="contained" color="primary" disabled={props.activeTitle === props.title || props.viewTournament} sx={{margin: "1.5vw", fontSize: "1.2em"}} >{props.title}</Button> | ||||
|         <Button variant="contained" color="primary" disabled={props.activeTitle === props.title || props.viewTournament} sx={{fontSize:['0.7em','0.75em']}} >{props.title}</Button> | ||||
|     </Link> | ||||
|   ); | ||||
| } | ||||
| @ -39,9 +48,9 @@ function ButtonLink(props) { | ||||
| export default function TournamentBar(props) { | ||||
|     const { tournamentId } = useParams(); | ||||
|     return ( | ||||
|         <Paper sx={{width: ["90vw",], margin: "1.5% auto"}} component={Stack} direction="column" justifyContent="center" alignItems="center">  | ||||
|           <Stack direction="row" paddingTop={'0.5%'}> | ||||
|             <ButtonLink targetPath="" tournamentId={tournamentId} activeTitle={props.pageTitle} title="View Tournament" viewTournament={props.viewTournament} sx={{}}/> | ||||
|         <Paper sx={{width: ["90vw",], fontSize:['1rem','1rem','1.5rem','2rem'], margin: "1.5% auto"}} component={Stack} direction="column" justifyContent="center" alignItems="center">  | ||||
|           <Stack direction="row" paddingTop={'0.5%'} sx={{fontSize:['1rem','1rem','1.5rem','2rem'], margin:'1.5%'}} spacing={2}> | ||||
|             <ButtonLink targetPath="" tournamentId={tournamentId} activeTitle={props.pageTitle} title="View Tournament" viewTournament={props.viewTournament}/> | ||||
|             <ButtonLink targetPath="/manage" tournamentId={tournamentId} activeTitle={props.pageTitle} title="Edit Tournament" /> | ||||
|             <ButtonLink targetPath="/teams" tournamentId={tournamentId} activeTitle={props.pageTitle} title="Manage Teams" /> | ||||
|           </Stack> | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
| 	flex-direction:row; | ||||
| 	justify-content: center; | ||||
|   } | ||||
|   .round{ | ||||
| .round{ | ||||
| 	display:flex; | ||||
| 	flex-direction:column; | ||||
| 	justify-content:center; | ||||
| @ -14,13 +14,13 @@ | ||||
| 	list-style:none; | ||||
| 	padding:0; | ||||
| 	/* font-size: 1.5rem; */ | ||||
|   } | ||||
| 	.round .spacer{ flex-grow:1;} | ||||
| 	.round .spacer:first-child, | ||||
| 	.round .spacer:last-child{ flex-grow:.5; } | ||||
| 	.round .game-spacer{ | ||||
| 	  flex-grow:1; | ||||
| 	} | ||||
| } | ||||
| .round .spacer{ flex-grow:1;} | ||||
| .round .spacer:first-child, | ||||
| .round .spacer:last-child{ flex-grow:.5; } | ||||
| .round .game-spacer{ | ||||
| 	flex-grow:1; | ||||
| } | ||||
|    | ||||
|   /* | ||||
|    *  General Styles | ||||
| @ -32,26 +32,44 @@ | ||||
| 	line-height:1.4em; | ||||
|   } */ | ||||
|    | ||||
|   li.game{ | ||||
| li.game{ | ||||
| 	padding-left:20px; | ||||
|   } | ||||
| } | ||||
| 	 | ||||
| 	.winner{ | ||||
| 		color:green; | ||||
| 		font-weight: bold; | ||||
| 	} | ||||
| 	.loser{ | ||||
| 		color:grey; | ||||
| 	} | ||||
| .winner{ | ||||
| 	color:green; | ||||
| 	font-weight: bold; | ||||
| } | ||||
| .loser{ | ||||
| 	color:grey; | ||||
| } | ||||
|    | ||||
| 	li.game-top{ border-bottom:1px solid #aaa; } | ||||
| li.game-top{ border-bottom:1px solid #aaa; } | ||||
|    | ||||
| 	li.game-spacer{  | ||||
| 	  border-right:1px solid #aaa; | ||||
| 	  min-height:10vh; | ||||
| 	} | ||||
| li.game-spacer{  | ||||
| 	border-right:1px solid #aaa; | ||||
| 	min-height:10vh; | ||||
| } | ||||
|    | ||||
| 	li.game-bottom{  | ||||
| 	  border-top:1px solid #aaa; | ||||
| 	} | ||||
|    | ||||
| li.game-bottom{  | ||||
| 	border-top:1px solid #aaa; | ||||
| } | ||||
|    | ||||
| 
 | ||||
| .winnerDisplay { | ||||
| 	display:flex; | ||||
| 	flex-direction:row; | ||||
| 	align-items: center; | ||||
| 	border: 2px solid gray; | ||||
| 	border-radius: 15px; | ||||
| 	min-height: 10vh; | ||||
| 	max-height: 40vh; | ||||
| 	margin: auto 5px; | ||||
| 	padding: 10px; | ||||
| } | ||||
| .winnerDisplay > p.winner { | ||||
| 	color:green; | ||||
| } | ||||
| .winnerDisplay > div.winner { | ||||
| 	margin-right: 10px; | ||||
| } | ||||
| @ -24,8 +24,6 @@ code { | ||||
| } | ||||
| 
 | ||||
| .mainIcon{ | ||||
|   height: 65px; | ||||
|   width: 65px; | ||||
|   border-radius: 50%; | ||||
|   /* border: 5px dotted salmon; */ | ||||
|   border: 3px solid #1ab35a; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user