diff --git a/simmadome/src/CreateLeague.tsx b/simmadome/src/CreateLeague.tsx index 3a4dbe4..29d0d6c 100644 --- a/simmadome/src/CreateLeague.tsx +++ b/simmadome/src/CreateLeague.tsx @@ -1,4 +1,5 @@ import React, {useState, useRef, useLayoutEffect, useReducer} from 'react'; +import {removeIndex, replaceIndex, append, arrayOf, shallowClone, getUID, DistributiveOmit} from './util'; import './CreateLeague.css'; import twemoji from 'twemoji'; @@ -46,11 +47,6 @@ class TeamState { } } -let getUID = function() { // does NOT generate UUIDs. Meant to create list keys ONLY - let id = 0; - return function() { return id++ } -}() - // STRUCTURE REDUCER type StructureReducerActions = @@ -168,35 +164,6 @@ function LeagueOptionsReducer(state: LeagueOptionsState, action: OptionsReducerA return newState } -// UTIL - -function removeIndex(arr: any[], index: number) { - return arr.slice(0, index).concat(arr.slice(index+1)); -} - -function replaceIndex(arr: T[], index: number, val: T) { - return arr.slice(0, index).concat([val]).concat(arr.slice(index+1)); -} - -function append(arr: T[], val: T) { - return arr.concat([val]); -} - -function arrayOf(length: number, func: (i: number) => T): T[] { - var out: T[] = []; - for (var i = 0; i < length; i++) { - out.push(func(i)); - } - return out; -} - -function shallowClone(obj: T): T { - return Object.assign({}, obj); -} - -type DistributiveOmit = T extends any ? Omit : never; -type DistributivePick = T extends any ? Pick : never; - // CREATE LEAGUE let initLeagueStructure = { @@ -323,7 +290,7 @@ function validRequest(name:string, structure: LeagueStructureState, options:Leag } function validNumber(value: string, min = 1) { - return Number(value) !== NaN && Number(value) >= min + return !isNaN(Number(value)) && Number(value) >= min } // LEAGUE STRUCUTRE @@ -464,7 +431,7 @@ function LeagueOptions(props: {state: LeagueOptionsState, dispatch: React.Dispat props.dispatch({type: 'set_games_series', value: value})} showError={props.showError}/> props.dispatch({type: 'set_top_postseason', value: value})} showError={props.showError}/> - + props.dispatch({type: 'set_wildcards', value: value})} showError={props.showError}/>
@@ -479,12 +446,16 @@ function LeagueOptions(props: {state: LeagueOptionsState, dispatch: React.Dispat ); } -function NumberInput(props: {title: string, value: string, setValue: (newVal: string) => void, showError: boolean}) { +function NumberInput(props: {title: string, value: string, setValue: (newVal: string) => void, showError: boolean, minValue?:number}) { + let minValue = 1; + if (props.minValue !== undefined) { + minValue = props.minValue + } return (
{props.title}
- props.setValue(e.target.value)}/> -
{(Number(props.value) === NaN || Number(props.value) < 0) && props.showError ? "Must be a number greater than 0" : ""}
+ props.setValue(e.target.value)}/> +
{(!isNaN(Number(props.value)) || Number(props.value) < minValue) && props.showError ? "Must be a number greater than "+minValue : ""}
); } diff --git a/simmadome/src/Game.css b/simmadome/src/Game.css index fa2af13..ca73b4d 100644 --- a/simmadome/src/Game.css +++ b/simmadome/src/Game.css @@ -1,5 +1,4 @@ .game { - align-self: stretch; text-align: center; display: flex; flex-direction: column; diff --git a/simmadome/src/GamePage.css b/simmadome/src/GamePage.css index 69f0cc7..e07cd9a 100644 --- a/simmadome/src/GamePage.css +++ b/simmadome/src/GamePage.css @@ -3,5 +3,35 @@ margin-left: 1rem; margin-right: 1rem; display: flex; + flex-direction: column; + align-items: center; justify-content: space-around; +} + +.history_box { + width: 100%; + margin-top: 3rem; + padding: 1rem; + padding-top: 0.5rem; + background: var(--background-main); + border-radius: 0.25rem; + width: 100%; + min-width: 32rem; + max-width: 44rem; + box-sizing: border-box; + border: 4px solid; + border-radius: 4px; + border-color: var(--highlight); + border-top: none; + border-right: none; + border-bottom: none; +} + +.history_title { + font-size: 14pt; +} + +.history_update { + height: 4rem; + margin: 0.5rem; } \ No newline at end of file diff --git a/simmadome/src/GamePage.tsx b/simmadome/src/GamePage.tsx index 47839a3..cdf2c31 100644 --- a/simmadome/src/GamePage.tsx +++ b/simmadome/src/GamePage.tsx @@ -1,22 +1,62 @@ -import React, {useState} from 'react'; +import React, {useState, useRef, useLayoutEffect} from 'react'; +import twemoji from 'twemoji'; import ReactRouter from 'react-router'; import {GameState, useListener} from './GamesUtil'; import './GamePage.css'; import Game from './Game'; +import {getUID} from './util'; function GamePage(props: ReactRouter.RouteComponentProps<{id: string}>) { - let [games, setGames] = useState<[string, GameState][]>([]); - useListener((newGames) => setGames(newGames)); + let [game, setGame] = useState<[string, GameState]|undefined>(undefined); + let history = useRef<[number, string, string][]>([]); + + useListener((newGames) => { + let newGame = newGames.find((gamePair) => gamePair[0] === props.match.params.id); + setGame(newGame); + console.log(newGame); + if (newGame !== undefined && newGame[1].start_delay < 0 && newGame[1].end_delay > 8) { + history.current.unshift([getUID(), newGame[1].update_emoji, newGame[1].update_text]); + if (history.current.length > 8) { + history.current.pop(); + } + } + }); + + if (game === undefined) { + return
The game you're looking for either doesn't exist or has already ended.
+ } - let game = games.find((game) => game[0] === props.match.params.id) return (
- { game ? - : - "The game you're looking for either doesn't exist or has already ended." + + { history.current.length > 0 ? + : + null }
); } +function GameHistory(props: {history: [number, string, string][]}) { + let self = useRef(null); + + useLayoutEffect(() => { + if (self.current) { + twemoji.parse(self.current); + } + }) + + return ( +
+
History
+ {props.history.map((update) => ( +
+
{update[1]}
+
{update[2]}
+
+ ))} +
+ ); +} + export default GamePage; \ No newline at end of file diff --git a/simmadome/src/GamesPage.css b/simmadome/src/GamesPage.css index d99b790..8baef47 100644 --- a/simmadome/src/GamesPage.css +++ b/simmadome/src/GamesPage.css @@ -76,9 +76,4 @@ left: 50%; transform: translate(-50%, 0); } - - .emptyslot { - border: none; - min-height: 0px; - } } diff --git a/simmadome/src/GamesPage.tsx b/simmadome/src/GamesPage.tsx index 3a2ad97..4fdaacb 100644 --- a/simmadome/src/GamesPage.tsx +++ b/simmadome/src/GamesPage.tsx @@ -8,6 +8,7 @@ function GamesPage() { let [search, setSearch] = useState(window.location.search); useEffect(() => { setSearch(window.location.search); + //eslint-disable-next-line react-hooks/exhaustive-deps }, [window.location.search]) let searchparams = new URLSearchParams(search); diff --git a/simmadome/src/GamesUtil.tsx b/simmadome/src/GamesUtil.tsx index 8002c02..57f0248 100644 --- a/simmadome/src/GamesUtil.tsx +++ b/simmadome/src/GamesUtil.tsx @@ -20,6 +20,8 @@ interface GameState { update_text: string is_league: boolean leagueoruser: string + start_delay: number + end_delay: number } type GameList = ([id: string, game: GameState] | null)[]; @@ -32,6 +34,7 @@ const useListener = (onUpdate: (update: [string, GameState][]) => void, url: str socket.on('connect', () => socket.emit('recieved', {})); socket.on('states_update', onUpdate); return () => {socket.disconnect()}; + //eslint-disable-next-line react-hooks/exhaustive-deps }, [url]) } diff --git a/simmadome/src/index.tsx b/simmadome/src/index.tsx index e6a49c9..b0ec638 100644 --- a/simmadome/src/index.tsx +++ b/simmadome/src/index.tsx @@ -32,14 +32,14 @@ function Header() {