Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add team name update modal #52

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import PlayerTableContainer from './PlayerTableContainer';
import RosterModal from './RosterModal';
import ScoringModal from './ScoringModal';
import Settings from './Settings';
import TeamNameModal from './TeamNameModal';
import TeamPicks from './TeamPicks';

interface IState {
Expand Down Expand Up @@ -43,6 +44,7 @@ export default class App extends React.Component<{}, IState> {

<RosterModal />
<ScoringModal />
<TeamNameModal />
</div>
);
}
Expand All @@ -60,6 +62,7 @@ export default class App extends React.Component<{}, IState> {
</div>
<RosterModal />
<ScoringModal />
<TeamNameModal />
</div>
);
}
Expand Down
20 changes: 16 additions & 4 deletions app/components/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { connect } from 'react-redux';
import { IPlayer } from '../lib/models/Player';
import { resetDraft } from '../lib/store/actions/players';
import { setScoreFormat, toggleScoringFormatting } from '../lib/store/actions/scoring';
import { setNumberOfTeams, setTrackedTeam, toggleRosterFormatting } from '../lib/store/actions/teams';
import { setNumberOfTeams, setTrackedTeam, toggleRosterFormatting, toggleTeamNameUpdates } from '../lib/store/actions/teams';
import { IStoreState } from '../lib/store/store';

interface IProps {
Expand All @@ -16,8 +16,10 @@ interface IProps {
setNumberOfTeams: (count: number) => void;
setScoring: (scoring: IScoring) => void;
setTrackedTeam: (team: number) => void;
teamNames: string[];
toggleRosterFormatting: () => void;
toggleScoringFormatting: () => void;
toggleTeamNameUpdates: () => void;
trackedTeam: number;
undraftedPlayers: IPlayer[];
}
Expand All @@ -40,7 +42,7 @@ class Settings extends React.Component<IProps, IState> {
};

public render() {
const { numberOfTeams } = this.props;
const { numberOfTeams, teamNames } = this.props;
const { open } = this.state;

// an array with the allowable number of teams: [6, 16]
Expand All @@ -60,7 +62,7 @@ class Settings extends React.Component<IProps, IState> {
Your team
<Select className="Settings-Select" onChange={this.props.setTrackedTeam} value={this.props.trackedTeam}>
{new Array(numberOfTeams).fill(0).map((_, i) => (
<Select.Option key={`Pick-Selection-${i}`} value={i}>{`Team ${i + 1}`}</Select.Option>
<Select.Option key={`Pick-Selection-${i}`} value={i}>{teamNames[i]}</Select.Option>
))}
</Select>
</label>
Expand Down Expand Up @@ -106,6 +108,14 @@ class Settings extends React.Component<IProps, IState> {
</Button>
</Tooltip>
</label>

<label>
<Tooltip title="Change Team Names">
<Button className="options-left" onClick={this.props.toggleTeamNameUpdates}>
Team Names
</Button>
</Tooltip>
</label>

<label>
<Tooltip title="Download stats CSV">
Expand Down Expand Up @@ -145,9 +155,10 @@ class Settings extends React.Component<IProps, IState> {
};
}

const mapStateToProps = ({ numberOfTeams, scoring, trackedTeam, undraftedPlayers }: IStoreState) => ({
const mapStateToProps = ({ numberOfTeams, scoring, teams, trackedTeam, undraftedPlayers, }: IStoreState) => ({
numberOfTeams,
scoring,
teamNames: teams.map(team => team.name),
trackedTeam,
undraftedPlayers,
});
Expand All @@ -159,6 +170,7 @@ const mapDispathToProps = (dispatch: any) => ({
setTrackedTeam: (index: number) => dispatch(setTrackedTeam(index)),
toggleRosterFormatting: () => dispatch(toggleRosterFormatting()),
toggleScoringFormatting: () => dispatch(toggleScoringFormatting()),
toggleTeamNameUpdates: () => dispatch(toggleTeamNameUpdates()),
});

export default connect(mapStateToProps, mapDispathToProps)(Settings);
64 changes: 64 additions & 0 deletions app/components/TeamNameModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Button, Input, Modal } from 'antd';
import { setTeamName, toggleTeamNameUpdates } from 'lib/store/actions/teams';
import * as React from 'react';
import { connect } from 'react-redux';
import { IStoreState } from '../lib/store/store';

interface IProps {
teamNames: string[];
updatingTeamNames: boolean;
dispatchSetTeamName: (teamIndex: number, name: string) => void;
toggleTeamNameUpdates: () => void;
}

/**
* Modal for updating team names
*/
class TeamNameModal extends React.Component<IProps> {

public render() {
const { teamNames, updatingTeamNames, toggleTeamNameUpdates, dispatchSetTeamName } = this.props;

return (
// @ts-ignore
<Modal
title="Change team names"
open={updatingTeamNames}
closeIcon={false}
onCancel={toggleTeamNameUpdates}
footer={
<Button key="submit" size="large" type="primary" onClick={toggleTeamNameUpdates}>
Ok
</Button>
}>
<div className="team-name-modal-container">
{
teamNames.map((teamName, index) => (
<div className="team-name-container">
<label>{index + 1}</label>
<Input
key={`team-name-input-${index}`}
className="team-name-input"
defaultValue={teamName}
onBlur={(e) => dispatchSetTeamName(index, e.currentTarget.value.trim() || `Team ${index}`)}
/>
</div>
))
}
</div>
</Modal>
);
}
}

const mapStateToProps = ({ teams, updatingTeamNames }: IStoreState) => ({
teamNames: teams.map(team => team.name),
updatingTeamNames
});

const mapDispathToProps = (dispatch: any) => ({
dispatchSetTeamName: (teamIndex: number, name: string) => dispatch(setTeamName(teamIndex, name)),
toggleTeamNameUpdates: () => dispatch(toggleTeamNameUpdates()),
});

export default connect(mapStateToProps, mapDispathToProps)(TeamNameModal);
2 changes: 1 addition & 1 deletion app/components/TeamPicks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class TeamPicks extends React.Component<IProps, State> {
<div className="Pick-Section">
<header>
<h3>Starters</h3>
<p>{`Team ${trackedTeam + 1}`}</p>
<p>{teams[trackedTeam].name}</p>
</header>

<div className="Pick-Column">
Expand Down
1 change: 1 addition & 0 deletions app/lib/models/Team.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface IRoster {
* A team comprised of players
*/
export interface ITeam {
name: string;
QB: NullablePlayer[];
RB: NullablePlayer[];
WR: NullablePlayer[];
Expand Down
2 changes: 2 additions & 0 deletions app/lib/store/actions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ export const ACTION_TYPES = {
SET_ACTIVE_TEAM: 'SET_ACTIVE_TEAM',
SET_NUMBER_OF_TEAMS: 'SET_NUMBER_OF_TEAMS',
SET_PICK: 'SET_PICK',
SET_TEAM_NAME: 'SET_TEAM_NAME',
INIT_STORE: 'SET_PLAYERS',
SET_ROSTER_FORMAT: 'SET_ROSTER_FORMAT',
SET_SCORE_FORMAT: 'SET_SCORE_FORMAT',
SET_TRACKED_TEAM: 'SET_TRACKED_TEAM',
SKIP_PICK: 'SKIP_PICK',
TOGGLE_ROSTER_FORMATTING: 'TOGGLE_ROSTER_FORMATTING',
TOGGLE_SCORE_FORMATTING: 'TOGGLE_SCORE_FORMATTING',
TOGGLE_TEAM_NAME_UPDATES: 'TOGGLE_TEAM_NAME_UPDATES',
UNDO_LAST: 'UNDO_LAST',
UNDO_PICK: 'UNDO_PICK',
};
18 changes: 18 additions & 0 deletions app/lib/store/actions/teams.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,27 @@ export const setActiveTeam = (activeTeam: number) => ({
type: ACTION_TYPES.SET_ACTIVE_TEAM,
});

/**
* Update a specific team's name
* @param teamIndex index of the team you want to update
* @param name new team name
*/
export const setTeamName = (teamIndex: number, name: string) => ({
teamIndex,
name,
type: ACTION_TYPES.SET_TEAM_NAME,
})

/**
* Toggle roster formatting. will open a modal for selecting number at each position
*/
export const toggleRosterFormatting = () => ({
type: ACTION_TYPES.TOGGLE_ROSTER_FORMATTING,
});

/**
* Toggle roster formatting. will open a modal for selecting number at each position
*/
export const toggleTeamNameUpdates = () => ({
type: ACTION_TYPES.TOGGLE_TEAM_NAME_UPDATES,
});
8 changes: 7 additions & 1 deletion app/lib/store/reducers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ACTION_TYPES } from '../actions';
import { initialState, IStoreState } from '../store';
import { removePlayer, initStore, setRosterFormat, undoLast, undoPick } from './players';
import { setScoreFormat } from './scoring';
import { incrementDraft, pickPlayer, resetDraft, setNumberOfTeams, setPick, setTrackedTeam, skipPick } from './teams';
import { incrementDraft, pickPlayer, resetDraft, setNumberOfTeams, setPick, setTeamName, setTrackedTeam, skipPick } from './teams';

export default (state = initialState, action: any): IStoreState => {
switch (action.type) {
Expand Down Expand Up @@ -39,6 +39,9 @@ export default (state = initialState, action: any): IStoreState => {
case ACTION_TYPES.SET_SCORE_FORMAT: {
return setScoreFormat(state, action.scoring);
}
case ACTION_TYPES.SET_TEAM_NAME: {
return setTeamName(state, action.teamIndex, action.name);
}
case ACTION_TYPES.SET_TRACKED_TEAM: {
return setTrackedTeam(state, action.trackedTeam);
}
Expand All @@ -51,6 +54,9 @@ export default (state = initialState, action: any): IStoreState => {
case ACTION_TYPES.TOGGLE_SCORE_FORMATTING: {
return { ...state, formattingScoring: !state.formattingScoring };
}
case ACTION_TYPES.TOGGLE_TEAM_NAME_UPDATES: {
return { ...state, updatingTeamNames: !state.updatingTeamNames };
}
case ACTION_TYPES.UNDO_LAST: {
return undoLast(state);
}
Expand Down
4 changes: 2 additions & 2 deletions app/lib/store/reducers/players.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const initStore = (state: IStoreState, players: IPlayer[]) =>
lastSyncPlayers: players,
players: players,
picks: [],
teams: new Array(state.numberOfTeams).fill(0).map(() => createTeam(state.rosterFormat)),
teams: new Array(state.numberOfTeams).fill(0).map((value, index) => createTeam(state.rosterFormat, `Team ${index + 1}`)),
undraftedPlayers: players,
});

Expand All @@ -40,7 +40,7 @@ export const removePlayer = (state: IStoreState, player: IPlayer): IStoreState =
*/
const removeFromRoster = (roster: ITeam, player: IPlayer): ITeam => {
// @ts-ignore
return Object.keys(roster).reduce(
return Object.keys(roster).filter(value => value !== 'name').reduce( // kinda janky with the filter
(acc: ITeam, pos) => ({
...acc,
// @ts-ignore
Expand Down
20 changes: 17 additions & 3 deletions app/lib/store/reducers/teams.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,22 +138,36 @@ export const resetDraft = (store: IStoreState) => initStore(store, store.lastSyn
* Update the tracked team on the left side of the app
*/
export const setTrackedTeam = (state: IStoreState, trackedTeam: number): IStoreState => {
const { teams } = state;
// create a toast
if (trackedTeam !== state.trackedTeam) {
toast.info(`Tracking Team ${trackedTeam + 1}`);
toast.info(`Tracking ${ teams[trackedTeam].name }`);
}

return { ...state, trackedTeam };
};

export const setTeamName = (state: IStoreState, teamIndex: number, name: string): IStoreState => {
const { teams } = state;

if(!teams[teamIndex].name) {
console.warn(`Cannot update team index ${teamIndex}`);
return state;
}

teams[teamIndex].name = name;

return { ...state, teams };
}

/**
* Update the number of teams and recalculate VOR for the players.
*/
export const setNumberOfTeams = (state: IStoreState, numberOfTeams: number): IStoreState => {
const { picks, rosterFormat, trackedTeam } = state;
const { picks, rosterFormat, trackedTeam, teams } = state;

// create new teams with empty rosters
let newTeams = new Array(numberOfTeams).fill(0).map(() => createTeam(rosterFormat));
let newTeams = new Array(numberOfTeams).fill(0).map((value, index) => createTeam(rosterFormat, teams[index]?.name || `Team ${index + 1}`));

// given the new team count, update each pick and destination team
const newPicks: IPick[] = [];
Expand Down
13 changes: 10 additions & 3 deletions app/lib/store/store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,18 @@ export interface IStoreState {
* An array of players that have yet to be drafted
*/
undraftedPlayers: IPlayer[];

/**
* Whether the app is currently in a state of updating team names
*/
updatingTeamNames: boolean;
}

/**
* Create an emptyTeam without any drafted players
*/
export const createTeam = (rosterFormat: IRoster): ITeam => ({
export const createTeam = (rosterFormat: IRoster, name: string): ITeam => ({
name: name,
BENCH: new Array(rosterFormat.BENCH).fill(null),
DST: new Array(rosterFormat.DST).fill(null),
FLEX: new Array(rosterFormat.FLEX).fill(null),
Expand Down Expand Up @@ -173,16 +179,17 @@ export const initialState = {
lastPickedPlayer: null,
lastSync: -1,
lastSyncPlayers: [],
numberOfTeams: 10,
numberOfTeams: 12,
picks: [],
players: [],
ppr: false,
rosterFormat: initialRoster,
scoring: initialScore,
selectedPlayer: null,
teams: new Array(10).fill(0).map(() => createTeam(initialRoster)), // doing 10 empty teams by default
teams: new Array(10).fill(0).map((value, index) => createTeam(initialRoster, `Team ${index + 1}`)), // doing 10 empty teams by default
trackedTeam: 0, // team to track in TeamPicks
undraftedPlayers: [],
updatingTeamNames: false,
};

const persistConfig = {
Expand Down
15 changes: 14 additions & 1 deletion app/pages/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -859,8 +859,21 @@ i.Grayed {
width: 55px;
}

/* Settings */
/* Team Name Modal */
.team-name-modal-container {
display: flex;
flex-direction: column;
}
.team-name-container {
display: flex;
align-items: flex-end;
}
.team-name-input {
margin-top: 12px;
width: 235px;
}

/* Settings */
.Settings-Select {
width: 120px;
margin-left: auto;
Expand Down