commit
318b0f52aa
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -357,3 +357,4 @@ Pipfile
|
||||||
env
|
env
|
||||||
/data/leagues
|
/data/leagues
|
||||||
/simmadome/build
|
/simmadome/build
|
||||||
|
/simmadome/.eslintcache
|
||||||
|
|
|
@ -167,7 +167,7 @@ class league_structure(object):
|
||||||
if division_max % 2 != 0:
|
if division_max % 2 != 0:
|
||||||
divisions.append(["OFF" for i in range(0, division_max)])
|
divisions.append(["OFF" for i in range(0, division_max)])
|
||||||
else:
|
else:
|
||||||
last_div = divisions.pop
|
last_div = divisions.pop()
|
||||||
|
|
||||||
divs_a = list(chain(divisions[int(len(divisions)/2):]))[0]
|
divs_a = list(chain(divisions[int(len(divisions)/2):]))[0]
|
||||||
if last_div is not None:
|
if last_div is not None:
|
||||||
|
|
|
@ -57,6 +57,7 @@ def create_league():
|
||||||
return jsonify({'status':'err_invalid_subleague_division_total'}), 400
|
return jsonify({'status':'err_invalid_subleague_division_total'}), 400
|
||||||
|
|
||||||
league_dic = {}
|
league_dic = {}
|
||||||
|
all_teams = set()
|
||||||
err_teams = []
|
err_teams = []
|
||||||
for subleague in config['structure']['subleagues']:
|
for subleague in config['structure']['subleagues']:
|
||||||
if subleague['name'] in league_dic:
|
if subleague['name'] in league_dic:
|
||||||
|
@ -67,10 +68,14 @@ def create_league():
|
||||||
if division['name'] in subleague_dic:
|
if division['name'] in subleague_dic:
|
||||||
return jsonify({'status':'err_duplicate_name', 'cause':f"{subleague['name']}/{division['name']}"}), 400
|
return jsonify({'status':'err_duplicate_name', 'cause':f"{subleague['name']}/{division['name']}"}), 400
|
||||||
elif len(division['teams']) > MAX_TEAMS_PER_DIVISION:
|
elif len(division['teams']) > MAX_TEAMS_PER_DIVISION:
|
||||||
return jsonify({'status':'err_too_many_teams', 'cause':f"{subleague['name']}/{division['name']}"})
|
return jsonify({'status':'err_too_many_teams', 'cause':f"{subleague['name']}/{division['name']}"}), 400
|
||||||
|
|
||||||
teams = []
|
teams = []
|
||||||
for team_name in division['teams']:
|
for team_name in division['teams']:
|
||||||
|
if team_name in all_teams:
|
||||||
|
return jsonify({'status':'err_duplicate_team', 'cause':team_name}), 400
|
||||||
|
all_teams.add(team_name)
|
||||||
|
|
||||||
team = games.get_team(team_name)
|
team = games.get_team(team_name)
|
||||||
if team is None:
|
if team is None:
|
||||||
err_teams.append(team_name)
|
err_teams.append(team_name)
|
||||||
|
@ -93,7 +98,7 @@ def create_league():
|
||||||
new_league = league_structure(config['name'])
|
new_league = league_structure(config['name'])
|
||||||
new_league.setup(
|
new_league.setup(
|
||||||
league_dic,
|
league_dic,
|
||||||
division_games=config['division_series'], # need to add a check that makes sure these values are ok
|
division_games=config['division_series'],
|
||||||
inter_division_games=config['inter_division_series'],
|
inter_division_games=config['inter_division_series'],
|
||||||
inter_league_games=config['inter_league_series'],
|
inter_league_games=config['inter_league_series'],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
[{"/Users/elijah/Documents/Projects/matteo/simmadome/src/index.tsx":"1","/Users/elijah/Documents/Projects/matteo/simmadome/src/reportWebVitals.ts":"2","/Users/elijah/Documents/Projects/matteo/simmadome/src/GamesPage.tsx":"3","/Users/elijah/Documents/Projects/matteo/simmadome/src/GamePage.tsx":"4","/Users/elijah/Documents/Projects/matteo/simmadome/src/CreateLeague.tsx":"5","/Users/elijah/Documents/Projects/matteo/simmadome/src/GamesUtil.tsx":"6","/Users/elijah/Documents/Projects/matteo/simmadome/src/util.tsx":"7","/Users/elijah/Documents/Projects/matteo/simmadome/src/Game.tsx":"8"},{"size":2368,"mtime":1610663769654,"results":"9","hashOfConfig":"10"},{"size":425,"mtime":1610566206674,"results":"11","hashOfConfig":"10"},{"size":4725,"mtime":1610664926203,"results":"12","hashOfConfig":"10"},{"size":1836,"mtime":1610677519051,"results":"13","hashOfConfig":"10"},{"size":18825,"mtime":1610778204901,"results":"14","hashOfConfig":"10"},{"size":1116,"mtime":1610677473305,"results":"15","hashOfConfig":"10"},{"size":961,"mtime":1610694553519,"results":"16","hashOfConfig":"10"},{"size":3089,"mtime":1610572714752,"results":"17","hashOfConfig":"10"},{"filePath":"18","messages":"19","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1bvn6qu",{"filePath":"20","messages":"21","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22","messages":"23","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"24","messages":"25","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"26","messages":"27","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"28","messages":"29","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"30","messages":"31","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"32","messages":"33","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/elijah/Documents/Projects/matteo/simmadome/src/index.tsx",[],"/Users/elijah/Documents/Projects/matteo/simmadome/src/reportWebVitals.ts",[],"/Users/elijah/Documents/Projects/matteo/simmadome/src/GamesPage.tsx",[],"/Users/elijah/Documents/Projects/matteo/simmadome/src/GamePage.tsx",[],"/Users/elijah/Documents/Projects/matteo/simmadome/src/CreateLeague.tsx",[],"/Users/elijah/Documents/Projects/matteo/simmadome/src/GamesUtil.tsx",[],"/Users/elijah/Documents/Projects/matteo/simmadome/src/util.tsx",[],"/Users/elijah/Documents/Projects/matteo/simmadome/src/Game.tsx",[]]
|
|
|
@ -16,15 +16,5 @@
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<!--
|
|
||||||
This HTML file is a template.
|
|
||||||
If you open it directly in the browser, you will see an empty page.
|
|
||||||
|
|
||||||
You can add webfonts, meta tags, or analytics to this file.
|
|
||||||
The build step will place the bundled scripts into the <body> tag.
|
|
||||||
|
|
||||||
To begin the development, run `npm start` or `yarn start`.
|
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
|
||||||
-->
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -255,7 +255,8 @@ input[type=number]::-webkit-outer-spin-button {
|
||||||
.cl_structure_err_team {
|
.cl_structure_err_team {
|
||||||
margin-top: -0.5rem;
|
margin-top: -0.5rem;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
width: 85%;
|
width: 95%;
|
||||||
|
padding-left: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cl_team_name_err {
|
.cl_team_name_err {
|
||||||
|
|
|
@ -183,18 +183,51 @@ function CreateLeague() {
|
||||||
let [name, setName] = useState("");
|
let [name, setName] = useState("");
|
||||||
let [showError, setShowError] = useState(false);
|
let [showError, setShowError] = useState(false);
|
||||||
let [nameExists, setNameExists] = useState(false);
|
let [nameExists, setNameExists] = useState(false);
|
||||||
let [deletedTeams, setDeletedTeams] = useState<string[]>([]);
|
let [deletedTeams, setDeletedTeams] = useState(new Set<string>());
|
||||||
let [createSuccess, setCreateSuccess] = useState(false);
|
let [createSuccess, setCreateSuccess] = useState(false);
|
||||||
let [structure, structureDispatch] = useReducer(leagueStructureReducer, initLeagueStructure);
|
let [structure, structureDispatch] = useReducer(leagueStructureReducer, initLeagueStructure);
|
||||||
let [options, optionsDispatch] = useReducer(LeagueOptionsReducer, new LeagueOptionsState());
|
let [options, optionsDispatch] = useReducer(LeagueOptionsReducer, new LeagueOptionsState());
|
||||||
|
|
||||||
let self = useRef<HTMLDivElement | null>(null)
|
let self = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (self.current) {
|
if (self.current) {
|
||||||
twemoji.parse(self.current)
|
twemoji.parse(self.current)
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
let duplicateTeams = getDuplicateTeams(structure);
|
||||||
|
|
||||||
|
let submit = () => {
|
||||||
|
if (!validRequest(name, structure, options)) {
|
||||||
|
setShowError(true);
|
||||||
|
} else {
|
||||||
|
let req = new XMLHttpRequest();
|
||||||
|
let data = makeRequest(name, structure, options);
|
||||||
|
req.open("POST", "/api/leagues", true);
|
||||||
|
req.setRequestHeader("Content-type", "application/json");
|
||||||
|
req.onreadystatechange = () => {
|
||||||
|
if(req.readyState === 4) {
|
||||||
|
if (req.status === 200) {
|
||||||
|
setCreateSuccess(true);
|
||||||
|
}
|
||||||
|
if (req.status === 400) {
|
||||||
|
let err = JSON.parse(req.response);
|
||||||
|
switch (err.status) {
|
||||||
|
case 'err_league_exists':
|
||||||
|
setNameExists(true);
|
||||||
|
break;
|
||||||
|
case 'err_no_such_team':
|
||||||
|
setDeletedTeams(new Set(err.cause));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
setShowError(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req.send(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (createSuccess) {
|
if (createSuccess) {
|
||||||
return(
|
return(
|
||||||
|
@ -217,40 +250,21 @@ function CreateLeague() {
|
||||||
nameExists && showError ? "A league by that name already exists" :
|
nameExists && showError ? "A league by that name already exists" :
|
||||||
""
|
""
|
||||||
}</div>
|
}</div>
|
||||||
<LeagueStructre state={structure} dispatch={structureDispatch} deletedTeams={deletedTeams} showError={showError}/>
|
<LeagueStructre
|
||||||
|
state={structure}
|
||||||
|
dispatch={structureDispatch}
|
||||||
|
deletedTeams={deletedTeams}
|
||||||
|
duplicateTeams={duplicateTeams}
|
||||||
|
showError={showError}
|
||||||
|
/>
|
||||||
<div className="cl_league_options">
|
<div className="cl_league_options">
|
||||||
<LeagueOptions state={options} dispatch={optionsDispatch} showError={showError}/>
|
<LeagueOptions
|
||||||
|
state={options}
|
||||||
|
dispatch={optionsDispatch}
|
||||||
|
showError={showError}
|
||||||
|
/>
|
||||||
<div className="cl_option_submit_box">
|
<div className="cl_option_submit_box">
|
||||||
<button className="cl_option_submit" onClick={e => {
|
<button className="cl_option_submit" onClick={submit}>Submit</button>
|
||||||
if (!validRequest(name, structure, options)) {
|
|
||||||
setShowError(true);
|
|
||||||
} else {
|
|
||||||
let req = new XMLHttpRequest();
|
|
||||||
let data = makeRequest(name, structure, options);
|
|
||||||
req.open("POST", "/api/leagues", true);
|
|
||||||
req.setRequestHeader("Content-type", "application/json");
|
|
||||||
req.onreadystatechange = () => {
|
|
||||||
if(req.readyState === 4) {
|
|
||||||
if (req.status === 200) {
|
|
||||||
setCreateSuccess(true);
|
|
||||||
}
|
|
||||||
if (req.status === 400) {
|
|
||||||
let err = JSON.parse(req.response);
|
|
||||||
switch (err.status) {
|
|
||||||
case 'err_league_exists':
|
|
||||||
setNameExists(true);
|
|
||||||
break;
|
|
||||||
case 'err_no_such_team':
|
|
||||||
setDeletedTeams(err.cause);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
setShowError(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
req.send(data);
|
|
||||||
}
|
|
||||||
}}>Submit</button>
|
|
||||||
<div className="cl_option_err">{
|
<div className="cl_option_err">{
|
||||||
!validRequest(name, structure, options) && showError ?
|
!validRequest(name, structure, options) && showError ?
|
||||||
"Cannot create league. Some information is missing or invalid." : ""
|
"Cannot create league. Some information is missing or invalid." : ""
|
||||||
|
@ -283,8 +297,6 @@ function makeRequest(name:string, structure: LeagueStructureState, options:Leagu
|
||||||
}
|
}
|
||||||
|
|
||||||
function validRequest(name:string, structure: LeagueStructureState, options:LeagueOptionsState) {
|
function validRequest(name:string, structure: LeagueStructureState, options:LeagueOptionsState) {
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
name !== "" &&
|
name !== "" &&
|
||||||
|
|
||||||
|
@ -296,6 +308,7 @@ function validRequest(name:string, structure: LeagueStructureState, options:Leag
|
||||||
validNumber(options.wildcards, 0) &&
|
validNumber(options.wildcards, 0) &&
|
||||||
|
|
||||||
structure.subleagues.length % 2 === 0 &&
|
structure.subleagues.length % 2 === 0 &&
|
||||||
|
getDuplicateTeams(structure).size === 0 &&
|
||||||
|
|
||||||
structure.subleagues.every((subleague, si) =>
|
structure.subleagues.every((subleague, si) =>
|
||||||
subleague.name !== "" &&
|
subleague.name !== "" &&
|
||||||
|
@ -314,9 +327,27 @@ function validNumber(value: string, min = 1) {
|
||||||
return !isNaN(Number(value)) && Number(value) >= min;
|
return !isNaN(Number(value)) && Number(value) >= min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDuplicateTeams(structure: LeagueStructureState) {
|
||||||
|
return new Set(
|
||||||
|
structure.subleagues.map(subleague =>
|
||||||
|
subleague.divisions.map(division =>
|
||||||
|
division.teams.map(team => team.name)
|
||||||
|
).reduce((prev, curr) => prev.concat(curr), [])
|
||||||
|
).reduce((prev, curr) => prev.concat(curr), [])
|
||||||
|
.filter((val, i, arr) => arr.slice(0, i).indexOf(val) >= 0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// LEAGUE STRUCUTRE
|
// LEAGUE STRUCUTRE
|
||||||
|
|
||||||
function LeagueStructre(props: {state: LeagueStructureState, dispatch: React.Dispatch<StructureReducerActions>, deletedTeams: string[], showError: boolean}) {
|
function LeagueStructre(props: {
|
||||||
|
state: LeagueStructureState,
|
||||||
|
dispatch: React.Dispatch<StructureReducerActions>,
|
||||||
|
deletedTeams: Set<string>,
|
||||||
|
duplicateTeams: Set<string>,
|
||||||
|
showError: boolean
|
||||||
|
}) {
|
||||||
|
|
||||||
let nSubleagues = props.state.subleagues.length;
|
let nSubleagues = props.state.subleagues.length;
|
||||||
let nDivisions = props.state.subleagues[0].divisions.length;
|
let nDivisions = props.state.subleagues[0].divisions.length;
|
||||||
return (
|
return (
|
||||||
|
@ -324,8 +355,18 @@ function LeagueStructre(props: {state: LeagueStructureState, dispatch: React.Dis
|
||||||
<div className="cl_league_structure_scrollbox">
|
<div className="cl_league_structure_scrollbox">
|
||||||
<div className="cl_subleague_add_align">
|
<div className="cl_subleague_add_align">
|
||||||
<div className="cl_league_structure_table">
|
<div className="cl_league_structure_table">
|
||||||
<SubleagueHeaders subleagues={props.state.subleagues} dispatch={props.dispatch} showError={props.showError}/>
|
<SubleagueHeaders
|
||||||
<Divisions subleagues={props.state.subleagues} dispatch={props.dispatch} deletedTeams={props.deletedTeams} showError={props.showError}/>
|
subleagues={props.state.subleagues}
|
||||||
|
dispatch={props.dispatch}
|
||||||
|
showError={props.showError}
|
||||||
|
/>
|
||||||
|
<Divisions
|
||||||
|
subleagues={props.state.subleagues}
|
||||||
|
dispatch={props.dispatch}
|
||||||
|
deletedTeams={props.deletedTeams}
|
||||||
|
duplicateTeams={props.duplicateTeams}
|
||||||
|
showError={props.showError}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{ (nSubleagues+1) * (nDivisions+1) < MAX_SUBLEAGUE_DIVISION_TOTAL ?
|
{ (nSubleagues+1) * (nDivisions+1) < MAX_SUBLEAGUE_DIVISION_TOTAL ?
|
||||||
<button className="cl_subleague_add" onClick={e => props.dispatch({type: 'add_subleague'})}>➕</button> :
|
<button className="cl_subleague_add" onClick={e => props.dispatch({type: 'add_subleague'})}>➕</button> :
|
||||||
|
@ -380,7 +421,14 @@ function SubleageHeader(props: {state: SubleagueState, canDelete: boolean, dispa
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Divisions(props: {subleagues: SubleagueState[], dispatch: React.Dispatch<StructureReducerActions>, deletedTeams: string[], showError: boolean}) {
|
function Divisions(props: {
|
||||||
|
subleagues: SubleagueState[],
|
||||||
|
dispatch: React.Dispatch<StructureReducerActions>,
|
||||||
|
deletedTeams: Set<string>,
|
||||||
|
duplicateTeams: Set<string>,
|
||||||
|
showError: boolean
|
||||||
|
}) {
|
||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
{props.subleagues[0].divisions.map((val, di) => (
|
{props.subleagues[0].divisions.map((val, di) => (
|
||||||
<div key={val.id} className="cl_table_row">
|
<div key={val.id} className="cl_table_row">
|
||||||
|
@ -393,11 +441,16 @@ function Divisions(props: {subleagues: SubleagueState[], dispatch: React.Dispatc
|
||||||
{props.subleagues.map((subleague, si) => (
|
{props.subleagues.map((subleague, si) => (
|
||||||
<div key={subleague.id} className="cl_division_cell">
|
<div key={subleague.id} className="cl_division_cell">
|
||||||
<div className="cl_subleague_bg">
|
<div className="cl_subleague_bg">
|
||||||
<Division state={subleague.divisions[di]} dispatch={action =>
|
<Division
|
||||||
|
state={subleague.divisions[di]}
|
||||||
|
dispatch={action =>
|
||||||
props.dispatch(Object.assign({subleague_index: si, division_index: di}, action))
|
props.dispatch(Object.assign({subleague_index: si, division_index: di}, action))
|
||||||
}
|
}
|
||||||
isDuplicate={subleague.divisions.slice(0, di).some(val => val.name === subleague.divisions[di].name)}
|
isDuplicate={subleague.divisions.slice(0, di).some(val => val.name === subleague.divisions[di].name)}
|
||||||
deletedTeams={props.deletedTeams} showError={props.showError} />
|
deletedTeams={props.deletedTeams}
|
||||||
|
duplicateTeams={props.duplicateTeams}
|
||||||
|
showError={props.showError}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
@ -410,7 +463,8 @@ function Division(props: {
|
||||||
state: DivisionState,
|
state: DivisionState,
|
||||||
dispatch: (action: DistributiveOmit<StructureReducerActions, 'subleague_index'|'division_index'>) => void,
|
dispatch: (action: DistributiveOmit<StructureReducerActions, 'subleague_index'|'division_index'>) => void,
|
||||||
isDuplicate: boolean,
|
isDuplicate: boolean,
|
||||||
deletedTeams: string[],
|
deletedTeams: Set<string>,
|
||||||
|
duplicateTeams: Set<string>,
|
||||||
showError: boolean
|
showError: boolean
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
|
@ -442,24 +496,27 @@ function Division(props: {
|
||||||
}/>
|
}/>
|
||||||
<div className="cl_structure_err cl_structure_err_div">{props.showError ? divisionErr : ""}</div>
|
<div className="cl_structure_err cl_structure_err_div">{props.showError ? divisionErr : ""}</div>
|
||||||
</div>
|
</div>
|
||||||
{props.state.teams.map((team, i) => {
|
{props.state.teams.map((team, i) => (
|
||||||
let showDeleted = props.showError && props.deletedTeams.includes(team.name)
|
<Team key={team.id}
|
||||||
return (<>
|
state={team}
|
||||||
<div className="cl_team" key={team.id}>
|
dispatch={props.dispatch}
|
||||||
<div className={"cl_team_name" + (showDeleted ? " cl_team_name_err" : "")}>{team.name}</div>
|
isDuplicate={props.duplicateTeams.has(team.name)}
|
||||||
<button className="cl_team_delete" onClick={e => props.dispatch({type:'remove_team', name: team.name})}>➖</button>
|
isDeleted={props.deletedTeams.has(team.name)}
|
||||||
</div>
|
showError={props.showError}
|
||||||
<div className="cl_structure_err cl_structure_err_team">{showDeleted ? "This team was deleted" : ""}</div>
|
/>
|
||||||
</>)
|
))}
|
||||||
})}
|
|
||||||
{props.state.teams.length < MAX_TEAMS_PER_DIVISION ? <>
|
{props.state.teams.length < MAX_TEAMS_PER_DIVISION ? <>
|
||||||
<div className="cl_team_add">
|
<div className="cl_team_add">
|
||||||
<input type="text" className="cl_newteam_name" placeholder="Add team..." value={newName} ref={newNameInput}
|
<input type="text" className="cl_newteam_name" placeholder="Add team..." value={newName} ref={newNameInput}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
|
if (e.target.value === "") {
|
||||||
|
setSearchResults([]);
|
||||||
|
} else {
|
||||||
let params = new URLSearchParams({query: e.target.value, page_len: '5', page_num: '0'});
|
let params = new URLSearchParams({query: e.target.value, page_len: '5', page_num: '0'});
|
||||||
fetch("/api/teams/search?" + params.toString())
|
fetch("/api/teams/search?" + params.toString())
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => setSearchResults(data));
|
.then(data => setSearchResults(data));
|
||||||
|
}
|
||||||
setNewName(e.target.value);
|
setNewName(e.target.value);
|
||||||
}}/>
|
}}/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -485,6 +542,30 @@ function Division(props: {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Team(props: {
|
||||||
|
state: TeamState,
|
||||||
|
dispatch: (action: DistributiveOmit<StructureReducerActions, 'subleague_index'|'division_index'>) => void,
|
||||||
|
isDuplicate: boolean,
|
||||||
|
isDeleted: boolean,
|
||||||
|
showError: boolean
|
||||||
|
}) {
|
||||||
|
|
||||||
|
let errMsg =
|
||||||
|
props.isDeleted ?
|
||||||
|
"This team was deleted" :
|
||||||
|
props.isDuplicate ?
|
||||||
|
"Each team in a league must be unique" :
|
||||||
|
"";
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<div className="cl_team">
|
||||||
|
<div className={"cl_team_name" + (errMsg && props.showError ? " cl_team_name_err" : "")}>{props.state.name}</div>
|
||||||
|
<button className="cl_team_delete" onClick={e => props.dispatch({type:'remove_team', name: props.state.name})}>➖</button>
|
||||||
|
</div>
|
||||||
|
<div className="cl_structure_err cl_structure_err_team">{props.showError ? errMsg : ""}</div>
|
||||||
|
</>);
|
||||||
|
}
|
||||||
|
|
||||||
// LEAGUE OPTIONS
|
// LEAGUE OPTIONS
|
||||||
|
|
||||||
function LeagueOptions(props: {state: LeagueOptionsState, dispatch: React.Dispatch<OptionsReducerActions>, showError: boolean}) {
|
function LeagueOptions(props: {state: LeagueOptionsState, dispatch: React.Dispatch<OptionsReducerActions>, showError: boolean}) {
|
||||||
|
|
|
@ -171,6 +171,8 @@
|
||||||
|
|
||||||
.update_text {
|
.update_text {
|
||||||
text-align: start;
|
text-align: start;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.field {
|
.field {
|
||||||
|
|
|
@ -70,10 +70,5 @@
|
||||||
|
|
||||||
@media only screen and (max-device-width: 800px) {
|
@media only screen and (max-device-width: 800px) {
|
||||||
.container {
|
.container {
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(1, minmax(700px, 90%));
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,23 +5,29 @@ import './GamesPage.css';
|
||||||
import Game from './Game';
|
import Game from './Game';
|
||||||
|
|
||||||
function GamesPage() {
|
function GamesPage() {
|
||||||
|
let gameList = useRef<(string | null)[]>([]);
|
||||||
|
|
||||||
let [search, setSearch] = useState(window.location.search);
|
let [search, setSearch] = useState(window.location.search);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSearch(window.location.search);
|
setSearch(window.location.search);
|
||||||
|
gameList.current = [];
|
||||||
//eslint-disable-next-line react-hooks/exhaustive-deps
|
//eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [window.location.search])
|
}, [window.location.search])
|
||||||
|
|
||||||
|
// get filter term
|
||||||
let searchparams = new URLSearchParams(search);
|
let searchparams = new URLSearchParams(search);
|
||||||
let filter = searchparams.get('league') ?? ""
|
let filter = searchparams.get('league') ?? ""
|
||||||
|
|
||||||
|
// set up socket listener
|
||||||
let [games, setGames] = useState<[string, GameState][]>([]);
|
let [games, setGames] = useState<[string, GameState][]>([]);
|
||||||
useListener(setGames);
|
useListener(setGames);
|
||||||
|
|
||||||
|
// build filter list
|
||||||
let filters = useRef(filter !== "" ? [filter] : []);
|
let filters = useRef(filter !== "" ? [filter] : []);
|
||||||
games.forEach((game) => { if (game[1].is_league && !filters.current.includes(game[1].leagueoruser)) { filters.current.push(game[1].leagueoruser) }});
|
games.forEach((game) => { if (game[1].is_league && !filters.current.includes(game[1].leagueoruser)) { filters.current.push(game[1].leagueoruser) }});
|
||||||
filters.current = filters.current.filter((f) => games.find((game) => game && game[1].is_league && game[1].leagueoruser === f) || f === filter);
|
filters.current = filters.current.filter((f) => games.find((game) => game && game[1].is_league && game[1].leagueoruser === f) || f === filter);
|
||||||
|
|
||||||
let gameList = useRef<(string | null)[]>([]);
|
// update game list
|
||||||
let filterGames = games.filter((game, i) => filter === "" || game[1].leagueoruser === filter);
|
let filterGames = games.filter((game, i) => filter === "" || game[1].leagueoruser === filter);
|
||||||
updateList(gameList.current, filterGames, searchparams.get('game'));
|
updateList(gameList.current, filterGames, searchparams.get('game'));
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,12 @@ h2 {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#links {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
#link_div {
|
#link_div {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -63,6 +69,12 @@ h2 {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#nav_links {
|
||||||
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
left: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.github_logo, .twitter_logo, .patreon_container {
|
.github_logo, .twitter_logo, .patreon_container {
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
|
@ -97,15 +109,18 @@ a:hover {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
#utility_links {
|
|
||||||
position: absolute;
|
|
||||||
top: 1rem;
|
|
||||||
left: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
img.emoji {
|
img.emoji {
|
||||||
height: 1em;
|
height: 1em;
|
||||||
width: 1em;
|
width: 1em;
|
||||||
margin: 0 .05em 0 .1em;
|
margin: 0 .05em 0 .1em;
|
||||||
vertical-align: -0.1em;
|
vertical-align: -0.1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px) {
|
||||||
|
#link_div, #nav_links {
|
||||||
|
position: static;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
margin-left: 2rem;
|
||||||
|
margin-right: 2rem;
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,10 @@ ReactDOM.render(
|
||||||
function Header() {
|
function Header() {
|
||||||
return (
|
return (
|
||||||
<div id="header">
|
<div id="header">
|
||||||
|
<div id="links">
|
||||||
|
<div id="nav_links">
|
||||||
|
<Link to="/create_league">Create a League</Link>
|
||||||
|
</div>
|
||||||
<div id="link_div">
|
<div id="link_div">
|
||||||
<a href="https://www.patreon.com/sixteen" className="patreon_link" target="_blank" rel="noopener noreferrer">
|
<a href="https://www.patreon.com/sixteen" className="patreon_link" target="_blank" rel="noopener noreferrer">
|
||||||
<div className="patreon_container">
|
<div className="patreon_container">
|
||||||
|
@ -42,8 +46,6 @@ function Header() {
|
||||||
<img className="twitter_logo" src={twitterLogo} alt="Twitter"/>
|
<img className="twitter_logo" src={twitterLogo} alt="Twitter"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="utility_links">
|
|
||||||
<Link to="/create_league">Create a League</Link>
|
|
||||||
</div>
|
</div>
|
||||||
<a href="/" className="page_header"><h2 className="page_header" style={{fontSize:"50px"} as React.CSSProperties}>THE SIMMADOME</h2></a>
|
<a href="/" className="page_header"><h2 className="page_header" style={{fontSize:"50px"} as React.CSSProperties}>THE SIMMADOME</h2></a>
|
||||||
<h2 className="page_header">Join SIBR on <a href="https://discord.gg/UhAajY2NCW" className="link"><img src={discordlogo} alt="" height="30"/></a> to start your own games!</h2>
|
<h2 className="page_header">Join SIBR on <a href="https://discord.gg/UhAajY2NCW" className="link"><img src={discordlogo} alt="" height="30"/></a> to start your own games!</h2>
|
||||||
|
|
|
@ -997,6 +997,7 @@ client = discord.Client()
|
||||||
gamesarray = []
|
gamesarray = []
|
||||||
active_tournaments = []
|
active_tournaments = []
|
||||||
active_leagues = []
|
active_leagues = []
|
||||||
|
active_standings = {}
|
||||||
setupmessages = {}
|
setupmessages = {}
|
||||||
|
|
||||||
thread1 = threading.Thread(target=main_controller.update_loop)
|
thread1 = threading.Thread(target=main_controller.update_loop)
|
||||||
|
@ -1028,7 +1029,7 @@ def config():
|
||||||
@client.event
|
@client.event
|
||||||
async def on_ready():
|
async def on_ready():
|
||||||
db.initialcheck()
|
db.initialcheck()
|
||||||
print(f"logged in as {client.user} with token {config()['token']}")
|
print(f"logged in as {client.user} with token {config()['token']} to {len(client.guilds)} servers")
|
||||||
watch_task = asyncio.create_task(game_watcher())
|
watch_task = asyncio.create_task(game_watcher())
|
||||||
await watch_task
|
await watch_task
|
||||||
|
|
||||||
|
@ -1827,9 +1828,11 @@ async def league_day_watcher(channel, league, games_list, filter_url, last = Fal
|
||||||
wait_seconds = (next_start - now).seconds
|
wait_seconds = (next_start - now).seconds
|
||||||
|
|
||||||
leagues.save_league(league)
|
leagues.save_league(league)
|
||||||
await channel.send(embed=league.standings_embed())
|
if league in active_standings.keys():
|
||||||
|
await active_standings[league].unpin()
|
||||||
|
active_standings[league] = await channel.send(embed=league.standings_embed())
|
||||||
|
active_standings[league].pin()
|
||||||
await channel.send(f"The day {league.day} games for the {league.name} will start in {math.ceil(wait_seconds/60)} minutes.")
|
await channel.send(f"The day {league.day} games for the {league.name} will start in {math.ceil(wait_seconds/60)} minutes.")
|
||||||
leagues.save_league(league)
|
|
||||||
await asyncio.sleep(wait_seconds)
|
await asyncio.sleep(wait_seconds)
|
||||||
await channel.send(f"A {league.name} series is continuing now at {filter_url}")
|
await channel.send(f"A {league.name} series is continuing now at {filter_url}")
|
||||||
games_list = await continue_league_series(league, queued_games, games_list, series_results, missed)
|
games_list = await continue_league_series(league, queued_games, games_list, series_results, missed)
|
||||||
|
@ -1837,7 +1840,10 @@ async def league_day_watcher(channel, league, games_list, filter_url, last = Fal
|
||||||
league.active = False
|
league.active = False
|
||||||
|
|
||||||
if league.autoplay == 0 or config()["game_freeze"]: #if number of series to autoplay has been reached
|
if league.autoplay == 0 or config()["game_freeze"]: #if number of series to autoplay has been reached
|
||||||
await channel.send(embed=league.standings_embed())
|
if league in active_standings.keys():
|
||||||
|
await active_standings[league].unpin()
|
||||||
|
active_standings[league] = await channel.send(embed=league.standings_embed())
|
||||||
|
active_standings[league].pin()
|
||||||
await channel.send(f"The {league.name} is no longer autoplaying.")
|
await channel.send(f"The {league.name} is no longer autoplaying.")
|
||||||
if config()["game_freeze"]:
|
if config()["game_freeze"]:
|
||||||
await channel.send("Patch incoming.")
|
await channel.send("Patch incoming.")
|
||||||
|
@ -1901,7 +1907,10 @@ async def league_day_watcher(channel, league, games_list, filter_url, last = Fal
|
||||||
wait_seconds = (next_start - now).seconds
|
wait_seconds = (next_start - now).seconds
|
||||||
|
|
||||||
leagues.save_league(league)
|
leagues.save_league(league)
|
||||||
await channel.send(embed=league.standings_embed())
|
if league in active_standings.keys():
|
||||||
|
await active_standings[league].unpin()
|
||||||
|
active_standings[league] = await channel.send(embed=league.standings_embed())
|
||||||
|
active_standings[league].pin()
|
||||||
await channel.send(f"""This {league.name} series is now complete! The next series will be starting in {int(wait_seconds/60)} minutes.""")
|
await channel.send(f"""This {league.name} series is now complete! The next series will be starting in {int(wait_seconds/60)} minutes.""")
|
||||||
await asyncio.sleep(wait_seconds)
|
await asyncio.sleep(wait_seconds)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue