From 1266dd2ecd1bc5a8867946fba70efa5116f456de Mon Sep 17 00:00:00 2001 From: Tim Slatcher Date: Thu, 18 Oct 2018 20:04:58 -0700 Subject: [PATCH] enable toggling off for players on chart --- projects/app/src/App.tsx | 2 +- projects/app/src/pages/GamePage.tsx | 2 +- projects/app/src/pages/HandPage.tsx | 2 +- projects/app/src/pages/HomePage.tsx | 2 +- projects/app/src/pages/LeaguePage.tsx | 2 +- projects/app/src/pages/SeasonHistoryPage.tsx | 38 +++++++++--- projects/app/src/pages/SeasonPage.tsx | 2 +- projects/app/src/pages/components/Card.tsx | 2 +- .../app/src/pages/components/GameResult.tsx | 2 +- .../app/src/pages/components/HandResult.tsx | 2 +- .../src/pages/components/PlayerChooser.tsx | 4 +- .../app/src/pages/components/PlayerHand.tsx | 2 +- projects/app/src/types/victory-addons.d.ts | 60 +++++++++---------- projects/server/src/index.ts | 1 + projects/shared/src/analysis/PlayerSet.ts | 40 +++++++++++++ projects/shared/src/analysis/index.ts | 1 + 16 files changed, 115 insertions(+), 49 deletions(-) create mode 100644 projects/shared/src/analysis/PlayerSet.ts diff --git a/projects/app/src/App.tsx b/projects/app/src/App.tsx index cd39036..0996b34 100644 --- a/projects/app/src/App.tsx +++ b/projects/app/src/App.tsx @@ -13,7 +13,7 @@ export interface AppProps { api: Api; } -export class App extends React.Component { +export class App extends React.PureComponent { public render() { const homePage = (props: RouteComponentProps) => ( diff --git a/projects/app/src/pages/GamePage.tsx b/projects/app/src/pages/GamePage.tsx index 719d7d5..f395af6 100644 --- a/projects/app/src/pages/GamePage.tsx +++ b/projects/app/src/pages/GamePage.tsx @@ -26,7 +26,7 @@ interface GamePageState { started: boolean; } -export class GamePage extends React.Component { +export class GamePage extends React.PureComponent { public state: GamePageState = { loading: false, game: undefined, diff --git a/projects/app/src/pages/HandPage.tsx b/projects/app/src/pages/HandPage.tsx index ec4aa71..2258f71 100644 --- a/projects/app/src/pages/HandPage.tsx +++ b/projects/app/src/pages/HandPage.tsx @@ -26,7 +26,7 @@ interface HandPageState { hand: IHand | undefined; } -export class HandPage extends React.Component { +export class HandPage extends React.PureComponent { public state: HandPageState = { loading: false, hand: undefined, diff --git a/projects/app/src/pages/HomePage.tsx b/projects/app/src/pages/HomePage.tsx index dcd2cdc..b3e6b07 100644 --- a/projects/app/src/pages/HomePage.tsx +++ b/projects/app/src/pages/HomePage.tsx @@ -16,7 +16,7 @@ interface HomePageState { newPlayer: string; } -export class HomePage extends React.Component { +export class HomePage extends React.PureComponent { public state: HomePageState = { loading: false, leagues: [], diff --git a/projects/app/src/pages/LeaguePage.tsx b/projects/app/src/pages/LeaguePage.tsx index b41acab..df9e0c5 100644 --- a/projects/app/src/pages/LeaguePage.tsx +++ b/projects/app/src/pages/LeaguePage.tsx @@ -17,7 +17,7 @@ interface LeaguePageState { playerToAdd: IPlayer | undefined; } -export class LeaguePage extends React.Component { +export class LeaguePage extends React.PureComponent { public state: LeaguePageState = { loading: false, league: undefined, diff --git a/projects/app/src/pages/SeasonHistoryPage.tsx b/projects/app/src/pages/SeasonHistoryPage.tsx index 0755a67..134430b 100644 --- a/projects/app/src/pages/SeasonHistoryPage.tsx +++ b/projects/app/src/pages/SeasonHistoryPage.tsx @@ -1,4 +1,4 @@ -import { analyzeGames, IGame } from "@turbo-hearts-scores/shared"; +import { analyzeGames, IGame, PlayerSet } from "@turbo-hearts-scores/shared"; import * as React from "react"; import { RouteComponentProps } from "react-router"; import { VictoryChart, VictoryLine, VictoryTooltip, VictoryVoronoiContainer } from "victory"; @@ -13,6 +13,7 @@ interface SeasonHistoryPageProps interface SeasonHistoryPageState { loading: boolean; seasonGames: IGame[]; + players: Set; } const COLORS = [ @@ -29,13 +30,14 @@ const COLORS = [ ]; // TODO: this should be a generic GameHistoryPage with a season loader -export class SeasonHistoryPage extends React.Component< +export class SeasonHistoryPage extends React.PureComponent< SeasonHistoryPageProps, SeasonHistoryPageState > { public state: SeasonHistoryPageState = { loading: false, seasonGames: [], + players: new Set(), }; public render() { @@ -59,10 +61,14 @@ export class SeasonHistoryPage extends React.Component<
}> {Object.keys(scoreHistory.history).map((player, playerIndex) => { + const playerName = scoreHistory.history[player].name; + if (!this.state.players.has(playerName)) { + return null; + } const data = scoreHistory.history[player].deltaHistory.map((d, i) => ({ x: i, y: d, - label: `${scoreHistory.history[player].name} ${d}`, + label: `${playerName} ${d}`, })); const style = { data: { stroke: COLORS[playerIndex % COLORS.length] }, @@ -82,10 +88,25 @@ export class SeasonHistoryPage extends React.Component<
{Object.keys(scoreHistory.history).map((player, playerIndex) => { const color = COLORS[playerIndex % COLORS.length]; + const playerName = scoreHistory.history[player].name; + const togglePlayer = () => { + if (this.state.players.has(playerName)) { + this.state.players.delete(playerName); + } else { + this.state.players.add(playerName); + } + this.forceUpdate(); + }; return ( - - - {scoreHistory.history[player].name} + + + {playerName} ); })} @@ -99,6 +120,9 @@ export class SeasonHistoryPage extends React.Component< this.setState({ loading: true }); const seasonGames = await this.props.api.fetchSeasonGames(seasonId); seasonGames.sort((g1, g2) => g1.time - g2.time); - this.setState({ loading: false, seasonGames }); + const players = new Set(); + const playerSet = analyzeGames(seasonGames, new PlayerSet()); + playerSet.players.forEach(player => players.add(player.name)); + this.setState({ loading: false, seasonGames, players }); } } diff --git a/projects/app/src/pages/SeasonPage.tsx b/projects/app/src/pages/SeasonPage.tsx index 3a6f47c..5ad159f 100644 --- a/projects/app/src/pages/SeasonPage.tsx +++ b/projects/app/src/pages/SeasonPage.tsx @@ -16,7 +16,7 @@ interface SeasonPageState { newSeason: string; } -export class SeasonPage extends React.Component { +export class SeasonPage extends React.PureComponent { public state: SeasonPageState = { loading: false, loadingGames: false, diff --git a/projects/app/src/pages/components/Card.tsx b/projects/app/src/pages/components/Card.tsx index 4058158..497a374 100644 --- a/projects/app/src/pages/components/Card.tsx +++ b/projects/app/src/pages/components/Card.tsx @@ -23,7 +23,7 @@ export interface CardProps { onClick?(): void; } -export class Card extends React.Component { +export class Card extends React.PureComponent { public render() { const suit = suitMap[this.props.suit]; return ( diff --git a/projects/app/src/pages/components/GameResult.tsx b/projects/app/src/pages/components/GameResult.tsx index be50a47..6afae5f 100644 --- a/projects/app/src/pages/components/GameResult.tsx +++ b/projects/app/src/pages/components/GameResult.tsx @@ -7,7 +7,7 @@ interface GameResultProps { game: IGame; } -export class GameResult extends React.Component { +export class GameResult extends React.PureComponent { public render() { const { leagueId, seasonId, game } = this.props; const results = getGameResult(game); diff --git a/projects/app/src/pages/components/HandResult.tsx b/projects/app/src/pages/components/HandResult.tsx index a0a2378..4f26bd5 100644 --- a/projects/app/src/pages/components/HandResult.tsx +++ b/projects/app/src/pages/components/HandResult.tsx @@ -8,7 +8,7 @@ interface HandResultProps { hand: IHand; } -export class HandResult extends React.Component { +export class HandResult extends React.PureComponent { public render() { const result = getHandResult(this.props.hand); return result.valid ? this.renderHand(result) : this.renderInvalid(); diff --git a/projects/app/src/pages/components/PlayerChooser.tsx b/projects/app/src/pages/components/PlayerChooser.tsx index da79973..6c681aa 100644 --- a/projects/app/src/pages/components/PlayerChooser.tsx +++ b/projects/app/src/pages/components/PlayerChooser.tsx @@ -1,5 +1,5 @@ +import { IPlayer } from "@turbo-hearts-scores/shared"; import * as React from "react"; -import { IPlayer } from "../../api/api"; export interface PlayerChooserProps { players: IPlayer[]; @@ -7,7 +7,7 @@ export interface PlayerChooserProps { onPlayerChanged(player: IPlayer | undefined): void; } -export class PlayerChooser extends React.Component { +export class PlayerChooser extends React.PureComponent { public render() { const selectedId = this.props.selectedPlayer ? this.props.selectedPlayer.id : ""; return ( diff --git a/projects/app/src/pages/components/PlayerHand.tsx b/projects/app/src/pages/components/PlayerHand.tsx index 4519906..03de371 100644 --- a/projects/app/src/pages/components/PlayerHand.tsx +++ b/projects/app/src/pages/components/PlayerHand.tsx @@ -12,7 +12,7 @@ interface PlayerHandProps { onChange(delta: Partial & Pick): void; } -export class PlayerHand extends React.Component { +export class PlayerHand extends React.PureComponent { public render() { return (
diff --git a/projects/app/src/types/victory-addons.d.ts b/projects/app/src/types/victory-addons.d.ts index 4405c1d..1092713 100644 --- a/projects/app/src/types/victory-addons.d.ts +++ b/projects/app/src/types/victory-addons.d.ts @@ -1,34 +1,34 @@ import * as React from "react"; declare module "victory" { - export interface VictoryTooltipProps { - active?: any - activateData?: any - angle?: any - cornerRadius?: any - data?: any - datum?: any - dx?: any - dy?: any - events?: any - flyoutStyle?: any - flyoutComponent?: any - groupComponent?: any - height?: any - horizontal?: any - index?: any - labelComponent?: any - orientation?: any - pointerLength?: any - pointerWidth?: any - renderInPortal?: any - style?: any - text?: any - width?: any - x?: any - y?: any - } + export interface VictoryTooltipProps { + active?: any; + activateData?: any; + angle?: any; + cornerRadius?: any; + data?: any; + datum?: any; + dx?: any; + dy?: any; + events?: any; + flyoutStyle?: any; + flyoutComponent?: any; + groupComponent?: any; + height?: any; + horizontal?: any; + index?: any; + labelComponent?: any; + orientation?: any; + pointerLength?: any; + pointerWidth?: any; + renderInPortal?: any; + style?: any; + text?: any; + width?: any; + x?: any; + y?: any; + } - export class VictoryTooltip extends React.Component {} - export class VictoryVoronoiContainer extends React.Component {} -} \ No newline at end of file + export class VictoryTooltip extends React.PureComponent {} + export class VictoryVoronoiContainer extends React.PureComponent {} +} diff --git a/projects/server/src/index.ts b/projects/server/src/index.ts index 4aa23e0..8691fa8 100644 --- a/projects/server/src/index.ts +++ b/projects/server/src/index.ts @@ -49,5 +49,6 @@ app.use("/", (req, res, next) => { // start our server server.listen(process.env.PORT || 7999, () => { + // tslint:disable-next-line:no-console console.log(`Server started on port ${server.address().port} :)`); }); diff --git a/projects/shared/src/analysis/PlayerSet.ts b/projects/shared/src/analysis/PlayerSet.ts new file mode 100644 index 0000000..3a44295 --- /dev/null +++ b/projects/shared/src/analysis/PlayerSet.ts @@ -0,0 +1,40 @@ +import { IGame, IPlayer } from ".."; +import { IGameAnalysis } from "./api"; +import { PlayerSetResult } from "./PlayerSet"; + +export interface PlayerSetResult { + players: Set; +} + +function emptyResult() { + return { + players: new Set(), + }; +} + +export function gameValid(game: IGame) { + if (!game.players || game.players.length === 0) { + return false; + } + if (game.players.some(p => p == null) || game.hands == null || game.hands.length === 0) { + return false; + } + return true; +} + +/** + * This requires that games be iterated on in temporal order. + */ +export class PlayerSet implements IGameAnalysis { + public initialState() { + return emptyResult(); + } + + public analyze(current: PlayerSetResult, game: IGame): PlayerSetResult { + if (!gameValid(game)) { + return current; + } + game.players!.forEach(player => current.players.add(player!)); + return current; + } +} diff --git a/projects/shared/src/analysis/index.ts b/projects/shared/src/analysis/index.ts index 727c4d6..59369f2 100644 --- a/projects/shared/src/analysis/index.ts +++ b/projects/shared/src/analysis/index.ts @@ -2,4 +2,5 @@ export * from "./api"; export * from "./HandSummary"; export * from "./HandResult"; export * from "./GameResult"; +export * from "./PlayerSet"; export * from "./Scoreboard";