From 84a12446f140fc23e7fe7cef62137e356dabd1c9 Mon Sep 17 00:00:00 2001 From: Vac1911 Date: Fri, 26 Nov 2021 15:43:13 -0500 Subject: [PATCH 01/43] Configurable Columns Prototype --- package.json | 2 +- src/common/getCols.ts | 16 ++ .../views/Roster/RosterCustomizeColumns.tsx | 159 ++++++++++++++++++ src/ui/views/Roster/index.tsx | 60 +++++-- src/worker/api/index.ts | 5 + src/worker/db/connectMeta.ts | 5 + src/worker/views/roster.ts | 47 ++++-- 7 files changed, 265 insertions(+), 29 deletions(-) create mode 100644 src/ui/views/Roster/RosterCustomizeColumns.tsx diff --git a/package.json b/package.json index ca4e8023ca..718cea4abe 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "deploy": "yarn run lint && yarn test && node tools/deploy.mjs", "deploy-all": "yarn run lint && yarn test && node tools/deploy-all.mjs", "start-watch": "concurrently --kill-others \"yarn run start\" \"yarn run watch\"", - "watch": "yarn run ajv-hack && node --openssl-legacy-provider tools/watch.js", + "watch": "yarn run ajv-hack && node tools/watch.js", "lint": "concurrently --raw \"yarn run lint-js\" \"yarn run lint-ts\"", "lint-js": "eslint \"*.{mjs,js,ts,tsx}\" \"public/*.js\" \"src/**/*.{mjs,js,ts,tsx}\" \"tools/**/*.{mjs,js,ts,tsx}\"", "lint-ts": "node tools/pre-test.mjs && yarn run tsc", diff --git a/src/common/getCols.ts b/src/common/getCols.ts index 18d5fd4492..34d28b35d5 100644 --- a/src/common/getCols.ts +++ b/src/common/getCols.ts @@ -2214,6 +2214,12 @@ const cols: { sortSequence: ["desc", "asc"], sortType: "number", }, + "rating:ovr": { + desc: "Overall Rating", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Ovr", + }, "Ovr Drop": { desc: "Decrease in Overall Rating", sortSequence: ["desc", "asc"], @@ -2273,11 +2279,21 @@ const cols: { Pos: { desc: "Position", }, + "rating:pos": { + desc: "Position", + title: "Pos", + }, Pot: { desc: "Potential Rating", sortSequence: ["desc", "asc"], sortType: "number", }, + "rating:pot": { + desc: "Potential Rating", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Pot", + }, "Pot Drop": { desc: "Decrease in Potential Rating", sortSequence: ["desc", "asc"], diff --git a/src/ui/views/Roster/RosterCustomizeColumns.tsx b/src/ui/views/Roster/RosterCustomizeColumns.tsx new file mode 100644 index 0000000000..6749358e60 --- /dev/null +++ b/src/ui/views/Roster/RosterCustomizeColumns.tsx @@ -0,0 +1,159 @@ +import { useState } from "react"; +import { arrayMoveImmutable } from "array-move"; +import { SortableContainer, SortableElement } from "react-sortable-hoc"; +import classNames from "classnames"; +import { Modal } from "react-bootstrap"; +import { toWorker } from "../../util"; + +export type Col = { + title: string; + hidden: boolean; + key: number; + type: string; +}; + +const Item = SortableElement( + ({ + col, + hidden, + onToggleHidden, + }: { + col: Col; + hidden: boolean; + onToggleHidden: () => void; + }) => { + const title = col.title; + + return ( +
+ + +
+ ); + }, +); + +const Container = SortableContainer( + ({ children, isDragged }: { children: any[]; isDragged: boolean }) => { + return ( + + ); + }, +); + +const RosterCustomizeColumns = ({ + allStats, + allRatings, + onHide, + cols, + show, + table, +}: { + allStats: string[]; + allRatings: string[]; + onHide: () => void; + cols: string[]; + show: boolean; + table: string; +}) => { + let i = 1; + const initialColumns: Col[] = [ + ...allRatings.map(col => ({ + title: col, + key: i++, + hidden: !cols.includes(col), + type: "ratings", + })), + ...allStats.map(col => ({ + title: col, + key: i++, + hidden: !cols.includes(col), + type: "stats", + })), + ]; + const [columns, setColumns] = useState(initialColumns); + const [isDragged, setIsDragged] = useState(false); + + const onSortEnd = ({ oldIndex, newIndex }) => { + const nextColumns = arrayMoveImmutable(columns, oldIndex, newIndex); + setColumns(nextColumns); + }; + + const onToggleHidden = (i: number) => () => { + const nextColumns = [...columns]; + if (nextColumns[i]) { + nextColumns[i] = { ...nextColumns[i] }; + nextColumns[i].hidden = !nextColumns[i].hidden; + setColumns(nextColumns); + } + }; + + const onReset = () => setColumns(initialColumns); + + const hide = async () => { + await toWorker("main", "updateColumns", { + columns: columns, + key: table, + }); + onHide(); + }; + + return ( + + Customize Columns + +

+ Click and drag to reorder columns, or use the checkboxes to show/hide + columns. +

+ { + setIsDragged(true); + }} + onSortEnd={args => { + setIsDragged(false); + onSortEnd(args); + }} + > + {columns.map((column, i) => { + return ( + +
+ + + + +
+ ); +}; + +export default RosterCustomizeColumns; diff --git a/src/ui/views/Roster/index.tsx b/src/ui/views/Roster/index.tsx index d720e2b52a..6b76531943 100644 --- a/src/ui/views/Roster/index.tsx +++ b/src/ui/views/Roster/index.tsx @@ -18,6 +18,7 @@ import { confirm, getCols, helpers, logEvent, toWorker } from "../../util"; import PlayingTime, { ptStyles } from "./PlayingTime"; import TopStuff from "./TopStuff"; import type { Phase, View } from "../../../common/types"; +import RosterCustomizeColumns from "./RosterCustomizeColumns"; // If a player was just drafted and the regular season hasn't started, then he can be released without paying anything const justDrafted = ( @@ -91,12 +92,18 @@ const Roster = ({ showTradeFor, showTradingBlock, stats, + ratings, + allStats, + allRatings, t, tid, userTid, + columns, }: View<"roster">) => { + console.log(columns, stats); const [sortedPids, setSortedPids] = useState(undefined); const [prevPlayers, setPrevPlayers] = useState(players); + const [showColumnsModal, setShowColumnsModal] = useState(false); useTitleBar({ title: "Roster", @@ -128,6 +135,7 @@ const Roster = ({ const profit = t.seasonAttrs !== undefined ? t.seasonAttrs.profit : 0; + const ratingCols = getCols(ratings.map(rating => `rating:${rating}`)); const statCols = getCols(stats.map(stat => `stat:${stat}`)); const showMood = season === currentSeason; @@ -163,6 +171,22 @@ const Roster = ({ tid={tid} /> + + + location.reload()} + /> + {showSpectatorWarning ? (

The AI will handle roster management in spectator mode. @@ -205,10 +229,12 @@ const Roster = ({ cols={() => ( <> Name - Pos Age - Ovr - Pot + {ratingCols.map(({ desc, title }) => ( + + {title} + + ))} {season === currentSeason ? Contract : null} YWT @@ -304,22 +330,20 @@ const Roster = ({ {p.name} - {p.ratings.pos} {p.age} - - {showRatings ? ( - - {p.ratings.ovr} - - ) : null} - - - {showRatings ? ( - - {p.ratings.pot} - - ) : null} - + {showRatings + ? ratings.map(rating => + p.ratings["d" + rating] ? ( + + + {p.ratings[rating]} + + + ) : ( + {p.ratings[rating]} + ), + ) + : null} {season === currentSeason ? ( { + await idb.meta.put("tables", data.columns, data.key); +}; + const updateOptions = async ( options: Options & { realPlayerPhotos: string; @@ -3624,6 +3628,7 @@ export default { updateLeague, updateMultiTeamMode, updateOptions, + updateColumns, updatePlayThroughInjuries, updatePlayerWatch, updatePlayingTime, diff --git a/src/worker/db/connectMeta.ts b/src/worker/db/connectMeta.ts index 2487c55bba..abbdeaa36c 100644 --- a/src/worker/db/connectMeta.ts +++ b/src/worker/db/connectMeta.ts @@ -26,6 +26,10 @@ export interface MetaDB extends DBSchema { | "realPlayerPhotos" | "realTeamInfo"; }; + tables: { + key: string; + value: object[]; + }; leagues: { value: League; key: number; @@ -34,6 +38,7 @@ export interface MetaDB extends DBSchema { } const create = (db: IDBPDatabase) => { + db.createObjectStore("tables"); db.createObjectStore("achievements", { keyPath: "aid", autoIncrement: true, diff --git a/src/worker/views/roster.ts b/src/worker/views/roster.ts index c3a496842e..4584dcfc12 100644 --- a/src/worker/views/roster.ts +++ b/src/worker/views/roster.ts @@ -1,4 +1,11 @@ -import { bySport, isSport, PHASE, POSITIONS } from "../../common"; +import { + bySport, + isSport, + PHASE, + PLAYER_STATS_TABLES, + POSITIONS, + RATINGS, +} from "../../common"; import { season, team } from "../core"; import { idb } from "../db"; import { g } from "../util"; @@ -8,6 +15,7 @@ import type { TeamSeasonAttr, } from "../../common/types"; import { addMood } from "./freeAgents"; +import { union } from "lodash-es"; const footballScore = (p: { ratings: { @@ -37,12 +45,6 @@ const updateRoster = async ( inputs.playoffs !== state.playoffs || inputs.season !== state.season ) { - const stats = bySport({ - basketball: ["gp", "min", "pts", "trb", "ast", "per"], - football: ["gp", "keyStats", "av"], - hockey: ["gp", "amin", "keyStats", "ops", "dps", "ps"], - }); - const editable = inputs.season === g.get("season") && inputs.tid === g.get("userTid") && @@ -109,8 +111,24 @@ const updateRoster = async ( "value", ]; // tid and draft are used for checking if a player can be released without paying his salary - const ratings = ["ovr", "pot", "dovr", "dpot", "skills", "pos", "ovrs"]; - const stats2 = [...stats, "yearsWithTeam", "jerseyNumber", "min", "gp"]; + const columns = await idb.meta.get("tables", "roster"); + + let ratings, stats; + if (columns) { + ratings = columns + .filter(c => !c.hidden && c.type == "ratings") + .map(c => c.title); + stats = columns + .filter(c => !c.hidden && c.type == "stats") + .map(c => c.title); + } else { + stats = bySport({ + basketball: ["gp", "min", "pts", "trb", "ast", "per"], + football: ["gp", "keyStats", "av"], + hockey: ["gp", "amin", "keyStats", "ops", "dps", "ps"], + }); + ratings = ["ovr", "pot", "dovr", "dpot", "skills", "pos", "ovrs"]; + } let players: any[]; let payroll: number | undefined; @@ -141,7 +159,7 @@ const updateRoster = async ( ratings, playoffs: inputs.playoffs === "playoffs", regularSeason: inputs.playoffs !== "playoffs", - stats: stats2, + stats: [...stats, "jerseyNumber", "yearsWithTeam"], season: inputs.season, tid: inputs.tid, showNoStats: true, @@ -215,6 +233,11 @@ const updateRoster = async ( }; t2.seasonAttrs.avgAge = t2.seasonAttrs.avgAge ?? team.avgAge(players); + const allRatings = ["ovr", "pot", "pos", ...RATINGS]; + const allStats = union( + PLAYER_STATS_TABLES.regular.stats, + PLAYER_STATS_TABLES.advanced.stats, + ); return { abbrev: inputs.abbrev, budget: g.get("budget"), @@ -247,6 +270,10 @@ const updateRoster = async ( inputs.tid === g.get("userTid") && !g.get("spectator"), stats, + ratings, + allStats, + allRatings, + columns, t: t2, tid: inputs.tid, userTid: g.get("userTid"), From 83ed7e83fa9a677e2964139c449f04f51404755a Mon Sep 17 00:00:00 2001 From: Vac1911 Date: Fri, 26 Nov 2021 16:32:00 -0500 Subject: [PATCH 02/43] get Player Column --- src/ui/util/getCols.tsx | 2677 +++++++++++++++++++++++++++++++++++ src/ui/views/FreeAgents.tsx | 14 +- 2 files changed, 2681 insertions(+), 10 deletions(-) create mode 100644 src/ui/util/getCols.tsx diff --git a/src/ui/util/getCols.tsx b/src/ui/util/getCols.tsx new file mode 100644 index 0000000000..e999fbec74 --- /dev/null +++ b/src/ui/util/getCols.tsx @@ -0,0 +1,2677 @@ +import type { Col } from "../components/DataTable"; +import bySport from "../../common/bySport"; +import isSport from "../../common/isSport"; +import { PlayerNameLabels, RatingWithChange } from "../components"; +import type { Player } from "../../common/types"; + +type ColTemp = Omit & { + title?: string; + render?: (p: Player) => JSX.Element; +}; + +const gp = isSport("hockey") ? "GP" : "G"; + +const sportSpecificCols = bySport<{ + [key: string]: ColTemp; +}>({ + basketball: { + "rating:fg": { + desc: "Mid Range", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "2Pt", + }, + "rating:tp": { + desc: "Three Pointers", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "3Pt", + }, + "rating:oiq": { + desc: "Offensive IQ", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "oIQ", + }, + "rating:dnk": { + desc: "Dunks/Layups", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Dnk", + }, + "rating:drb": { + desc: "Dribbling", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Drb", + }, + "rating:ins": { + desc: "Inside Scoring", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Ins", + }, + "rating:jmp": { + desc: "Jumping", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Jmp", + }, + "rating:ft": { + desc: "Free Throws", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FT", + }, + "rating:pss": { + desc: "Passing", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Pss", + }, + "rating:reb": { + desc: "Rebounding", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Reb", + }, + "rating:diq": { + desc: "Defensive IQ", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "dIQ", + }, + "stat:2pp": { + desc: "Two Point Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "2P%", + }, + "stat:2p": { + desc: "Two Pointers Made", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "2P", + }, + "stat:2pa": { + desc: "Two Pointers Attempted", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "2PA", + }, + "stat:pm": { + desc: "Plus/Minus", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "+/-", + }, + "stat:tpp": { + desc: "Three Point Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "3P%", + }, + "stat:tp": { + desc: "Three Pointers Made", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "3P", + }, + "stat:tpa": { + desc: "Three Pointers Attempted", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "3PA", + }, + "stat:tpar": { + desc: "Three Point Attempt Rate (3PA / FGA)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "3PAr", + }, + "stat:astp": { + desc: "Percentage of teammate field goals a player assisted while on the floor", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "AST%", + }, + "stat:ast": { + desc: "Assists", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "AST", + }, + "stat:ba": { + desc: "Blocks Against", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "BA", + }, + "stat:blk": { + desc: "Blocks", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "BLK", + }, + "stat:blkp": { + desc: "Percentage of opponent two-pointers blocked", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "BLK%", + }, + "stat:drb": { + desc: "Defensive Rebounds", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "DRB", + }, + "stat:drbp": { + desc: "Percentage of available defensive rebounds grabbed", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "DRB%", + }, + "stat:drtg": { + desc: "Defensive Rating (points allowed per 100 possessions)", + sortSequence: ["asc", "desc"], + sortType: "number", + title: "DRtg", + }, + "stat:dws": { + desc: "Defensive Win Shares", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "DWS", + }, + "stat:ewa": { + desc: "Estimated Wins Added", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "EWA", + }, + "stat:efg": { + desc: "Effective Field Goal Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "eFG%", + }, + "stat:fgp": { + desc: "Field Goal Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FG%", + }, + "stat:fg": { + desc: "Field Goals Made", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FG", + }, + "stat:fga": { + desc: "Field Goals Attempted", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FGA", + }, + "stat:ftp": { + desc: "Free Throw Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FT%", + }, + "stat:ft": { + desc: "Free Throws Made", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FT", + }, + "stat:fta": { + desc: "Free Throws Attempted", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FTA", + }, + "stat:ftpFga": { + desc: "Free Throws per Field Goal Attempted", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FTr", + }, + "stat:ftr": { + desc: "Free Throw Attempt Rate (FTA / FGA)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FT/FGA", + }, + "stat:gmsc": { + desc: "Game Score", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "GmSc", + }, + "stat:nrtg": { + desc: "Net Rating (point differential per 100 possessions)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "NRtg", + }, + "stat:orb": { + desc: "Offensive Rebounds", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ORB", + }, + "stat:orbp": { + desc: "Percentage of available offensive rebounds grabbed", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ORB%", + }, + "stat:ortg": { + desc: "Offensive Rating (points produced/scored per 100 possessions)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ORtg", + }, + "stat:ows": { + desc: "Offensive Win Shares", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OWS", + }, + "stat:pace": { + desc: "Possessions Per Game", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Pace", + }, + "stat:per": { + desc: "Player Efficiency Rating", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PER", + }, + "stat:pf": { + desc: "Personal Fouls", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PF", + }, + "stat:pl": { + desc: "Pythagorean Losses (expected losses based on points scored and allowed)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PL", + }, + "stat:pts": { + desc: "Points", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PTS", + }, + "stat:pw": { + desc: "Pythagorean Wins (expected wins based on points scored and allowed)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PW", + }, + "stat:stl": { + desc: "Steals", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "STL", + }, + "stat:stlp": { + desc: "Percentage of opponent possessions ending in steals", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "STL%", + }, + "stat:tovp": { + desc: "Turnovers per 100 plays", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TOV%", + }, + "stat:trb": { + desc: "Total Rebounds", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TRB", + }, + "stat:trbp": { + desc: "Percentage of available rebounds grabbed", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TRB%", + }, + "stat:tsp": { + desc: "True Shooting Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TS%", + }, + "stat:tov": { + desc: "Turnovers", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TOV", + }, + "stat:usgp": { + desc: "Percentage of team plays used", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "USG%", + }, + "stat:ws": { + desc: "Win Shares", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "WS", + }, + "stat:wsPerPlayer": { + desc: "Win Shares Per Player", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "WS/Player", + }, + "stat:ws48": { + desc: "Win Shares Per 48 Minutes", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "WS/48", + }, + "stat:obpm": { + desc: "Offensive Box Plus-Minus", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OBPM", + }, + "stat:dbpm": { + desc: "Defensive Box Plus-Minus", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "DBPM", + }, + "stat:bpm": { + desc: "Box Plus-Minus", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "BPM", + }, + "stat:vorp": { + desc: "Value Over Replacement Player", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "VORP", + }, + "stat:fgAtRim": { + desc: "At Rim Made", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "M", + }, + "stat:fgaAtRim": { + desc: "At Rim Attempted", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "A", + }, + "stat:fgpAtRim": { + desc: "At Rim Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "%", + }, + "stat:fgLowPost": { + desc: "Low Post Made", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "M", + }, + "stat:fgaLowPost": { + desc: "Low Post Attempted", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "A", + }, + "stat:fgpLowPost": { + desc: "Low Post Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "%", + }, + "stat:fgMidRange": { + desc: "Mid Range Made", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "M", + }, + "stat:fgaMidRange": { + desc: "Mid Range Attempted", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "A", + }, + "stat:fgpMidRange": { + desc: "Mid Range Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "%", + }, + "stat:dd": { + desc: "Double Doubles", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "DD", + }, + "stat:td": { + desc: "Triple Doubles", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TD", + }, + "stat:qd": { + desc: "Quadruple Doubles", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "QD", + }, + "stat:fxf": { + desc: "Five by Fives", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "5x5", + }, + }, + football: { + "pos:QB": { + desc: "Quarterback", + sortType: "number", + title: "QB", + }, + "pos:RB": { + desc: "Running Back", + sortType: "number", + title: "RB", + }, + "pos:WR": { + desc: "Wide Receiver", + sortType: "number", + title: "WR", + }, + "pos:TE": { + desc: "Tight End", + sortType: "number", + title: "TE", + }, + "pos:OL": { + desc: "Offensive Lineman", + sortType: "number", + title: "OL", + }, + "pos:DL": { + desc: "Defensive Lineman", + sortType: "number", + title: "DL", + }, + "pos:LB": { + desc: "Linebacker", + sortType: "number", + title: "LB", + }, + "pos:CB": { + desc: "Cornerback", + sortType: "number", + title: "CB", + }, + "pos:S": { + desc: "Safety", + sortType: "number", + title: "S", + }, + "pos:K": { + desc: "Kicker", + sortType: "number", + title: "K", + }, + "pos:P": { + desc: "Punter", + sortType: "number", + title: "P", + }, + "rating:thv": { + desc: "Throwing Vision", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ThV", + }, + "rating:thp": { + desc: "Throwing Power", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ThP", + }, + "rating:tha": { + desc: "Throwing Accuracy", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ThA", + }, + "rating:bsc": { + desc: "Ball Security", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "BSc", + }, + "rating:elu": { + desc: "Elusiveness", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Elu", + }, + "rating:rtr": { + desc: "Route Running", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "RtR", + }, + "rating:hnd": { + desc: "Hands", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Hnd", + }, + "rating:rbk": { + desc: "Run Blocking", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "RBk", + }, + "rating:pbk": { + desc: "Pass Blocking", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PBk", + }, + "rating:pcv": { + desc: "Pass Coverage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PCv", + }, + "rating:tck": { + desc: "Tackling", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Tck", + }, + "rating:prs": { + desc: "Pass Rushing", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PRs", + }, + "rating:rns": { + desc: "Run Stopping", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "RnS", + }, + "rating:kpw": { + desc: "Kicking Power", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "KPw", + }, + "rating:kac": { + desc: "Kicking Accuracy", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "KAc", + }, + "rating:ppw": { + desc: "Punting Power", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PPw", + }, + "rating:pac": { + desc: "Punting Accuracy", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PAc", + }, + "rating:ovrQB": { + desc: "Overall Rating (QB)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrQB", + }, + "rating:ovrRB": { + desc: "Overall Rating (RB)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrRB", + }, + "rating:ovrWR": { + desc: "Overall Rating (WR)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrWR", + }, + "rating:ovrTE": { + desc: "Overall Rating (TE)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrTE", + }, + "rating:ovrOL": { + desc: "Overall Rating (OL)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrOL", + }, + "rating:ovrDL": { + desc: "Overall Rating (DL)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrDL", + }, + "rating:ovrLB": { + desc: "Overall Rating (LB)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrLB", + }, + "rating:ovrCB": { + desc: "Overall Rating (CB)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrCB", + }, + "rating:ovrS": { + desc: "Overall Rating (S)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrS", + }, + "rating:ovrK": { + desc: "Overall Rating (K)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrK", + }, + "rating:ovrP": { + desc: "Overall Rating (P)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrP", + }, + "rating:ovrKR": { + desc: "Overall Rating (KR)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrKR", + }, + "rating:ovrPR": { + desc: "Overall Rating (PR)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrPR", + }, + "rating:potQB": { + desc: "Potential Rating (QB)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotQB", + }, + "rating:potRB": { + desc: "Potential Rating (RB)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotRB", + }, + "rating:potWR": { + desc: "Potential Rating (WR)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotWR", + }, + "rating:potTE": { + desc: "Potential Rating (TE)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotTE", + }, + "rating:potOL": { + desc: "Potential Rating (OL)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotOL", + }, + "rating:potDL": { + desc: "Potential Rating (DL)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotDL", + }, + "rating:potLB": { + desc: "Potential Rating (LB)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotLB", + }, + "rating:potCB": { + desc: "Potential Rating (CB)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotCB", + }, + "rating:potS": { + desc: "Potential Rating (S)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotS", + }, + "rating:potK": { + desc: "Potential Rating (K)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotK", + }, + "rating:potP": { + desc: "Potential Rating (P)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotP", + }, + "rating:potKR": { + desc: "Potential Rating (KR)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotKR", + }, + "rating:potPR": { + desc: "Potential Rating (PR)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotPR", + }, + "stat:fmb": { + desc: "Fumbles", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Fmb", + }, + "stat:fmbLost": { + desc: "Fumbles Lost", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FL", + }, + "stat:fp": { + desc: "Fantasy Points", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FP", + }, + "stat:pssCmp": { + desc: "Completions", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Cmp", + }, + "stat:pss": { + desc: "Passing Attempts", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Att", + }, + "stat:pssYds": { + desc: "Passing Yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Yds", + }, + "stat:pssTD": { + desc: "Passing Touchdowns", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TD", + }, + "stat:pssInt": { + desc: "Interceptions", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Int", + }, + "stat:pssLng": { + desc: "Longest Pass", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Lng", + }, + "stat:pssSk": { + desc: "Times Sacked", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Sk", + }, + "stat:pssSkYds": { + desc: "Yards lost due to sacks", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Yds", + }, + "stat:rus": { + desc: "Rushing Attempts", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Rush", + }, + "stat:rusYds": { + desc: "Rushing Yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Yds", + }, + "stat:rusTD": { + desc: "Rushing Touchdowns", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TD", + }, + "stat:rusLng": { + desc: "Longest Run", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Lng", + }, + "stat:tgt": { + desc: "Targets", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Tgt", + }, + "stat:rec": { + desc: "Receptions", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Rec", + }, + "stat:recYds": { + desc: "Receiving Yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Yds", + }, + "stat:recTD": { + desc: "Receiving Touchdowns", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TD", + }, + "stat:recLng": { + desc: "Longest Reception", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Lng", + }, + "stat:pr": { + desc: "Punt Returns", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PR", + }, + "stat:prYds": { + desc: "Punt Return Yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Yds", + }, + "stat:prTD": { + desc: "Punts returned for touchdowns", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TD", + }, + "stat:prLng": { + desc: "Longest Punt Return", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Lng", + }, + "stat:kr": { + desc: "Kickoff Returns", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "KR", + }, + "stat:krYds": { + desc: "Kickoff Return Yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Yds", + }, + "stat:krTD": { + desc: "Kickoffs returned for touchdowns", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TD", + }, + "stat:krLng": { + desc: "Longest Kickoff Return", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Lng", + }, + "stat:defInt": { + desc: "Interceptions", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Int", + }, + "stat:defIntYds": { + desc: "Yards interceptions were returned for", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Yds", + }, + "stat:defIntTD": { + desc: "Interceptions returned for touchdowns", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TD", + }, + "stat:defIntLng": { + desc: "Longest Interception Return", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Lng", + }, + "stat:defPssDef": { + desc: "Passes Defended", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PD", + }, + "stat:defFmbFrc": { + desc: "Forced Fumbles", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FF", + }, + "stat:defFmbRec": { + desc: "Fumbles Recovered", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FR", + }, + "stat:defFmbYds": { + desc: "Yards fumbles were returned for", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Yds", + }, + "stat:defFmbTD": { + desc: "Fumbles returned for touchdowns", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TD", + }, + "stat:defFmbLng": { + desc: "Longest Fumble Return", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Lng", + }, + "stat:defSk": { + desc: "Sacks", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Sk", + }, + "stat:defTckSolo": { + desc: "Solo Tackles", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Solo", + }, + "stat:defTckAst": { + desc: "Assists On Tackles", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Ast", + }, + "stat:defTckLoss": { + desc: "Tackes For Loss", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TFL", + }, + "stat:defSft": { + desc: "Safeties Scored", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Sfty", + }, + "stat:fg0": { + desc: "Field Goals Made, 19 yards and under", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FG10", + }, + "stat:fga0": { + desc: "Field Goals Attempted, 19 yards and under", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FGA10", + }, + "stat:fg20": { + desc: "Field Goals Made, 20-29 yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FG20", + }, + "stat:fga20": { + desc: "Field Goals Attempted, 20-29 yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FGA20", + }, + "stat:fg30": { + desc: "Field Goals Made, 30-39 yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FG30", + }, + "stat:fga30": { + desc: "Field Goals Attempted, 30-39 yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FGA30", + }, + "stat:fg40": { + desc: "Field Goals Made, 40-49 yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FG40", + }, + "stat:fga40": { + desc: "Field Goals Attempted, 40-49 yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FGA40", + }, + "stat:fg50": { + desc: "Field Goals Made, 50+ yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FG50", + }, + "stat:fga50": { + desc: "Field Goals Attempted, 50+ yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FGA50", + }, + "stat:fgLng": { + desc: "Longest Field Goal", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Lng", + }, + "stat:xp": { + desc: "Extra Points Made", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "XPM", + }, + "stat:xpa": { + desc: "Extra Points Attempted", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "XPA", + }, + "stat:pnt": { + desc: "Times Punted", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Pnt", + }, + "stat:pntYds": { + desc: "Total Punt Yardage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Yds", + }, + "stat:pntLng": { + desc: "Longest Punt", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Lng", + }, + "stat:pntBlk": { + desc: "Times Punts Blocked", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Blk", + }, + "stat:pen": { + desc: "Penalties", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Pen", + }, + "stat:penYds": { + desc: "Penalty Yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Yds", + }, + "stat:cmpPct": { + desc: "Completion Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Pct", + }, + "stat:qbRat": { + desc: "Quarterback Rating", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "QBRat", + }, + "stat:rusYdsPerAtt": { + desc: "Rushing Yards Per Attempt", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Y/A", + }, + "stat:recYdsPerAtt": { + desc: "Yards Per Catch", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Y/A", + }, + "stat:fg": { + desc: "Field Goals Made", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FGM", + }, + "stat:fga": { + desc: "Field Goals Attempted", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FGA", + }, + "stat:fgPct": { + desc: "Field Goal Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Pct", + }, + "stat:xpPct": { + desc: "Extra Point Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Pct", + }, + "stat:kickingPts": { + desc: "Kicking Points", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Pts", + }, + "stat:pntYdsPerAtt": { + desc: "Yards Per Punt", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Y/A", + }, + "stat:pntTB": { + desc: "Punt Touchbacks", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TB", + }, + "stat:pntIn20": { + desc: "Punts Inside 20", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "In20", + }, + "stat:krYdsPerAtt": { + desc: "Yards Per Kick Return", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Y/A", + }, + "stat:prYdsPerAtt": { + desc: "Yards Per Punt Return", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Y/A", + }, + "stat:defTck": { + desc: "Total Tackles", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Tck", + }, + "stat:keyStats": { + desc: "Key Stats", + sortSequence: ["desc", "asc"], + sortType: "string", + title: "Stats", + }, + "stat:pts": { + desc: "", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Pts", + }, + "stat:yds": { + desc: "Offensive Yards", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Yds", + }, + "stat:ply": { + desc: "Plays", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Ply", + }, + "stat:ydsPerPlay": { + desc: "Yards Per Play", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Y/P", + }, + "stat:tov": { + desc: "Turnovers", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TO", + }, + "stat:drives": { + desc: "Number of Drives", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "#Dr", + }, + "stat:drivesScoringPct": { + desc: "Percentage of drives ending in a score", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Sc%", + }, + "stat:drivesTurnoverPct": { + desc: "Percentage of drives ending in a turnover", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TO%", + }, + "stat:avgFieldPosition": { + desc: "Average Starting Field Position", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Start", + }, + "stat:timePerDrive": { + desc: "Time Per Drive (minutes)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Tm/D", + }, + "stat:playsPerDrive": { + desc: "Number of Plays Per Drive", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Ply/D", + }, + "stat:ydsPerDrive": { + desc: "Yards Per Drive", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Y/D", + }, + "stat:ptsPerDrive": { + desc: "Points Per Drive", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Pts/D", + }, + "stat:qbRec": { + desc: "Record as primary QB", + sortSequence: ["desc", "asc"], + sortType: "record", + title: "QBRec", + }, + "stat:qbW": { + desc: "Wins as primary QB", + sortSequence: ["desc", "asc"], + sortType: "record", + title: "QBW", + }, + "stat:qbL": { + desc: "Losses as primary QB", + sortSequence: ["desc", "asc"], + sortType: "record", + title: "QBL", + }, + "stat:qbT": { + desc: "Ties as primary QB", + sortSequence: ["desc", "asc"], + sortType: "record", + title: "QBT", + }, + "stat:qbOTL": { + desc: "Overtime losses as primary QB", + sortSequence: ["desc", "asc"], + sortType: "record", + title: "QBOTL", + }, + "stat:pssTDPct": { + desc: "Percentage of passes that result in touchdowns", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TD%", + }, + "stat:pssIntPct": { + desc: "Percentage of passes that result in interceptions", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Int%", + }, + "stat:pssYdsPerAtt": { + desc: "Pass Yards Per Attempt", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Y/A", + }, + "stat:pssAdjYdsPerAtt": { + desc: "Adjusted Pass Yards Per Attempt ((yds + 20 * TD - 45 * int) / att)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "AY/A", + }, + "stat:pssYdsPerCmp": { + desc: "Pass Yards Per Completion", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Y/C", + }, + "stat:pssYdsPerGame": { + desc: "Pass Yards Per Game", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Y/G", + }, + "stat:pssNetYdsPerAtt": { + desc: "Net Pass Yards Per Attempt (passes and sacks)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "NY/A", + }, + "stat:pssAdjNetYdsPerAtt": { + desc: "Adjusted Net Pass Yards Per Attempt ((yds + 20 * TD - 45 * int - skYds) / (att + sk))", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ANY/A", + }, + "stat:pssSkPct": { + desc: "Percentage of times sacked when attempting a pass", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Sk%", + }, + "stat:rusYdsPerGame": { + desc: "Rushing Yards Per Game", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Y/G", + }, + "stat:rusPerGame": { + desc: "Rushing Attempts Per Game", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "A/G", + }, + "stat:recYdsPerRec": { + desc: "Yards Per Reception", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Y/R", + }, + "stat:recPerGame": { + desc: "Receptions Per Game", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "R/G", + }, + "stat:recYdsPerGame": { + desc: "Receiving Yards Per Game", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Y/G", + }, + "stat:recCatchPct": { + desc: "Catch Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Ctch%", + }, + "stat:touches": { + desc: "Touches (Rushing Attempts And Receptions)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Tch", + }, + "stat:ydsPerTouch": { + desc: "Yards Per Touch", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Y/Tch", + }, + "stat:ydsFromScrimmage": { + desc: "Total Rushing and Receiving Yards From Scrimmage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "YScm", + }, + "stat:rusRecTD": { + desc: "Total Rushing and Receiving Touchdowns", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "RRTD", + }, + "stat:allPurposeYds": { + desc: "All Purpose Yards (Rushing, Receiving, and Kick/Punt/Fumble/Interception Returns)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "APY", + }, + "stat:av": { + desc: "Approximate Value", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "AV", + }, + "stat:avPerPlayer": { + desc: "Approximate Value Per Player", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "AV/Player", + }, + }, + hockey: { + "pos:C": { + desc: "Center", + sortType: "number", + title: "C", + }, + "pos:W": { + desc: "Wing", + sortType: "number", + title: "W", + }, + "pos:D": { + desc: "Defenseman", + sortType: "number", + title: "D", + }, + "pos:G": { + desc: "Goalie", + sortType: "number", + title: "G", + }, + "rating:pss": { + desc: "Passing", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Pss", + }, + "rating:wst": { + desc: "Wristshot", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Wst", + }, + "rating:sst": { + desc: "Slapshot", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Sst", + }, + "rating:stk": { + desc: "Stickhandling", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Stk", + }, + "rating:oiq": { + desc: "Offensive IQ", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "oIQ", + }, + "rating:chk": { + desc: "Checking", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Chk", + }, + "rating:blk": { + desc: "Shot Blocking", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Blk", + }, + "rating:fcf": { + desc: "Faceoffs", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Fcf", + }, + "rating:diq": { + desc: "Defensive IQ", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "dIQ", + }, + "rating:glk": { + desc: "Goalkeeping", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Glk", + }, + "rating:ovrC": { + desc: "Overall Rating (Center)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrC", + }, + "rating:ovrW": { + desc: "Overall Rating (Winger)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrW", + }, + "rating:ovrD": { + desc: "Overall Rating (Defenseman)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrD", + }, + "rating:ovrG": { + desc: "Overall Rating (Goalie)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OvrG", + }, + "rating:potC": { + desc: "Potential Rating (Center)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotC", + }, + "rating:potW": { + desc: "Potential Rating (Winger)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotW", + }, + "rating:potD": { + desc: "Potential Rating (Defenseman)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotD", + }, + "rating:potG": { + desc: "Potential Rating (Goalie)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PotG", + }, + "stat:gpGoalie": { + desc: "Games Played (Goalie)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: gp, + }, + "stat:gpSkater": { + desc: "Games Played (Skater)", + sortSequence: ["desc", "asc"], + sortType: "number", + title: gp, + }, + "stat:pm": { + desc: "Plus/Minus", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "+/-", + }, + "stat:pim": { + desc: "Penalty Minutes", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PIM", + }, + "stat:evG": { + desc: "Even Strength Goals", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "evG", + }, + "stat:ppG": { + desc: "Power Play Goals", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ppG", + }, + "stat:shG": { + desc: "Short-Handed Goals", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "shG", + }, + "stat:gwG": { + desc: "Game Winning Goals", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "gwG", + }, + "stat:evA": { + desc: "Even Strength Assists", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "evA", + }, + "stat:ppA": { + desc: "Power Play Assists", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ppA", + }, + "stat:shA": { + desc: "Short-Handed Assists", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "shA", + }, + "stat:gwA": { + desc: "Game Winning Assists", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "gwA", + }, + "stat:s": { + desc: "Shots on Goal", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "S", + }, + "stat:tsa": { + desc: "Total Shots Attempted", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TSA", + }, + "stat:fow": { + desc: "Faceoff Wins", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FOW", + }, + "stat:fol": { + desc: "Faceoff Losses", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FOL", + }, + "stat:foPct": { + desc: "Faceoff Win Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "FO%", + }, + "stat:blk": { + desc: "Blocks", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "BLK", + }, + "stat:hit": { + desc: "Hits", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "HIT", + }, + "stat:tk": { + desc: "Takeaways", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "TK", + }, + "stat:gv": { + desc: "Giveaways", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "GV", + }, + "stat:ga": { + desc: "Goals Against", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "GA", + }, + "stat:sv": { + desc: "Saves", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "SV", + }, + "stat:so": { + desc: "Shutouts", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "SO", + }, + "stat:g": { + desc: "Goals", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "G", + }, + "stat:a": { + desc: "Assists", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "A", + }, + "stat:pts": { + desc: "Points", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PTS", + }, + "stat:sPct": { + desc: "Shooting Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "S%", + }, + "stat:svPct": { + desc: "Save Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "SV%", + }, + "stat:sa": { + desc: "Shots Against", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "SA", + }, + "stat:gaa": { + desc: "Goals Against Average", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "GAA", + }, + "stat:keyStats": { + desc: "Key Stats", + sortSequence: ["desc", "asc"], + sortType: "string", + title: "Stats", + }, + "stat:ps": { + desc: "Point Shares", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PS", + }, + "stat:psPerPlayer": { + desc: "Point Shares Per Player", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PS/Player", + }, + "stat:ops": { + desc: "Offensive Point Shares", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OPS", + }, + "stat:dps": { + desc: "Defensive Point Shares", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "DPS", + }, + "stat:gps": { + desc: "Goalie Point Shares", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "GPS", + }, + "stat:gc": { + desc: "Goals Created", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "GC", + }, + "stat:amin": { + desc: "Average Time On Ice", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ATOI", + }, + "stat:ppMin": { + desc: "Power Play Time On Ice", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ppTOI", + }, + "stat:shMin": { + desc: "Short Handed Time On Ice", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "shTOI", + }, + "stat:ppo": { + desc: "Power Play Opportunities", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PPO", + }, + "stat:ppPct": { + desc: "Power Play Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "PP%", + }, + "stat:gRec": { + desc: "Record as primary G", + sortSequence: ["desc", "asc"], + sortType: "record", + title: "Rec", + }, + "stat:gW": { + desc: "Wins as primary G", + sortSequence: ["desc", "asc"], + sortType: "record", + title: "GW", + }, + "stat:gL": { + desc: "Losses as primary G", + sortSequence: ["desc", "asc"], + sortType: "record", + title: "GL", + }, + "stat:gT": { + desc: "Ties as primary G", + sortSequence: ["desc", "asc"], + sortType: "record", + title: "GT", + }, + "stat:gOTL": { + desc: "Overtime losses as primary G", + sortSequence: ["desc", "asc"], + sortType: "record", + title: "GOTL", + }, + }, +}); +const cols: { + [key: string]: ColTemp; +} = { + "": { + sortSequence: ["desc", "asc"], + }, + "#": {}, + "@": { + desc: "Home or Away", + }, + "#AS": { + desc: "Number of All-Star Selections", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "%": { + desc: "Percentage", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Active: { + desc: "Number of Players Still Active", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "# Fathers": { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + HoF: { + desc: "Number of Players in the Hall of Fame", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "# Brothers": { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "# Players": { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "# Seasons": { + desc: "Number of Seasons", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "# Sons": { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "# Teams": { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "# Trades": { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + A: { + desc: "Attempted", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Acquired: { + desc: "How Player Was Acquired", + }, + Actions: {}, + Age: { + sortType: "number", + }, + Amount: { + sortSequence: ["desc", "asc"], + sortType: "currency", + }, + "Asking For": { + sortSequence: ["desc", "asc"], + sortType: "currency", + }, + "Avg Attendance": { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + AvgAge: { + desc: "Average age, weighted by minutes played", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Age", + }, + Born: { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "Cap Space": { + sortSequence: ["desc", "asc"], + sortType: "currency", + }, + "Captain 1": { + sortType: "name", + }, + "Captain 2": { + sortType: "name", + }, + Cash: { + sortSequence: ["desc", "asc"], + sortType: "currency", + }, + College: {}, + Conference: {}, + Contract: { + sortSequence: ["desc", "asc"], + sortType: "currency", + }, + Count: { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Country: {}, + Created: { + desc: "Created Date", + searchType: "string", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Current: { + desc: "Current Team Rating (With Injuries)", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "Current Contract": { + desc: "Current Contract", + sortSequence: ["desc", "asc"], + sortType: "currency", + title: "Current", + }, + "Projected Contract": { + desc: "Projected Contract", + sortSequence: ["desc", "asc"], + sortType: "currency", + title: "Projected", + }, + Details: {}, + Died: { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Diff: { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Difficulty: { + sortSequence: ["desc", "asc"], + }, + Division: {}, + Draft: { + noSearch: true, + sortSequence: [], + }, + "Draft Picks": { + sortSequence: [], + }, + "Draft Year": { + sortType: "number", + }, + Drafted: { + sortType: "number", + }, + "Dunk Winner": { + desc: "Slam Dunk Contest Winner", + sortType: "name", + }, + End: { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Exp: { + desc: "Contract Expiration", + sortSequence: ["asc", "desc"], + sortType: "number", + }, + Experience: { + desc: "Number of Years in the League", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Finals: { + desc: "Finals Appearances", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "Finals Won": { + desc: "Finals Won", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "Finals Lost": { + desc: "Finals Lost", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + From: {}, + GB: { + desc: "Games Back", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Games: { + desc: "Number of Games", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + GOAT: { + desc: "GOAT Score", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Healthy: { + desc: "Team Rating (When Healthy)", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Height: { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + HOF: { + sortSequence: ["desc", "asc"], + }, + Injury: {}, + L: { + desc: "Losses", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + L10: { + desc: "Last Ten Games", + sortSequence: ["desc", "asc"], + sortType: "lastTen", + }, + Last: { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "Last Played": { + desc: "Last Played Date", + sortSequence: ["desc", "asc"], + searchType: "string", + sortType: "number", + }, + "Last Season": { + desc: "Last Season with Team", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "League Champion": {}, + League: { + desc: "League Name", + }, + Links: { + noSearch: true, + sortSequence: [], + }, + M: { + desc: "Made", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Mood: { + width: "1px", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + MVP: { + desc: "Most Valuable Player", + sortType: "name", + }, + Name: { + sortType: "name", + render: (p: Player) => ( + + {p.name} + + ), + }, + Negotiate: { + sortSequence: [], + }, + Note: {}, + Opp: { + desc: "Opponent", + }, + Ovr: { + desc: "Overall Rating", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "rating:ovr": { + desc: "Overall Rating", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Ovr", + }, + "Ovr Drop": { + desc: "Decrease in Overall Rating", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + PA: { + desc: `${isSport("hockey") ? "Goals" : "Points"} Against`, + sortSequence: ["desc", "asc"], + sortType: "number", + title: isSport("hockey") ? "GA" : undefined, + }, + PS: { + desc: `${isSport("hockey") ? "Goals" : "Points"} Scored`, + sortSequence: ["desc", "asc"], + sortType: "number", + title: isSport("hockey") ? "GF" : undefined, + }, + "PA/g": { + desc: `${isSport("hockey") ? "Goals" : "Points"} Against Per Game`, + sortSequence: ["desc", "asc"], + sortType: "number", + title: isSport("hockey") ? "GA" : undefined, + }, + "PS/g": { + desc: `${isSport("hockey") ? "Goals" : "Points"} Scored Per Game`, + sortSequence: ["desc", "asc"], + sortType: "number", + title: isSport("hockey") ? "GF" : undefined, + }, + Payroll: { + sortSequence: ["desc", "asc"], + sortType: "currency", + }, + "Peak Ovr": { + desc: "Peak Overall Rating", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Phase: { + desc: "League Season and Phase", + sortSequence: ["desc", "asc"], + }, + Pick: { + desc: "Draft Pick", + sortType: "draftPick", + }, + Pop: { + desc: "Region Population", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Playoffs: { + desc: "Playoff Appearances", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Pos: { + desc: "Position", + render: (p: Player) => p.ratings.pos, + }, + Pot: { + desc: "Potential Rating", + sortSequence: ["desc", "asc"], + sortType: "number", + render: (p: Player) => + p.ratings["dpot"] ? ( + + {p.ratings["pot"]} + + ) : ( + p.ratings["pot"] + ), + }, + "rating:pot": { + desc: "Potential Rating", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Pot", + render: (p: Player) => p.ratings.pot, + }, + "Pot Drop": { + desc: "Decrease in Potential Rating", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Prog: { + desc: "Progression From Previous Season", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "Profit (YTD)": { + sortSequence: ["desc", "asc"], + sortType: "currency", + }, + PTS: { + desc: "Points", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "PTS%": { + desc: "Points Divided By Maximum Points", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Received: { + desc: "Assets Received in Trade", + }, + Record: { + desc: "Record", + sortType: "record", + }, + Relation: {}, + Result: {}, + Retired: { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "Revenue (YTD)": { + sortSequence: ["desc", "asc"], + sortType: "currency", + }, + "Roster Spots": { + desc: "Number of Open Roster Spots", + sortSequence: ["desc", "asc"], + }, + "Rounds Lost": { + desc: "Playoff Rounds Lost", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "Rounds Won": { + desc: "Playoff Rounds Won", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "Runner Up": {}, + Season: { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Seed: { + desc: "Playoff Seed", + sortType: "number", + }, + Skills: {}, + Start: { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + T: { + desc: "Ties", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + "Ticket Price": { + sortSequence: ["desc", "asc"], + sortType: "currency", + }, + Trade: { + desc: "Ties", + noSearch: true, + }, + OTL: { + desc: "Overtime Losses", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Team: {}, + "Three-Point Winner": { + desc: "Three-Point Contest Winner", + sortType: "name", + }, + Titles: { + desc: "Championships Won", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Type: { + desc: "Type of Game", + }, + TypeInjury: { + desc: "Type of Injury", + title: "Type", + }, + W: { + desc: "Wins", + sortSequence: ["desc", "asc"], + sortType: "number", + }, + Weight: { + sortSequence: ["desc", "asc"], + sortType: "number", + }, + X: { + desc: "Exclude from counter offers", + noSearch: true, + sortSequence: [], + }, + Year: { + sortType: "number", + }, + Summary: {}, + "rating:endu": { + desc: "Endurance", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "End", + }, + "rating:hgt": { + desc: "Height", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Hgt", + }, + "rating:spd": { + desc: "Speed", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Spd", + }, + "rating:stre": { + desc: "Strength", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Str", + }, + "stat:gp": { + desc: "Games Played", + sortSequence: ["desc", "asc"], + sortType: "number", + title: gp, + }, + "stat:gpPerPlayer": { + desc: "Games Played Per Player", + sortSequence: ["desc", "asc"], + sortType: "number", + title: `${gp}/Player`, + }, + "stat:gs": { + desc: "Games Started", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "GS", + }, + "stat:jerseyNumber": { + desc: "Jersey Number", + sortSequence: ["asc", "desc"], + sortType: "number", + title: "#", + }, + "stat:min": { + desc: isSport("hockey") ? "Time On Ice" : "Minutes", + sortSequence: ["desc", "asc"], + sortType: "number", + title: isSport("hockey") ? "TOI" : "MP", + }, + "stat:mov": { + desc: "Average Margin of Victory", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "MOV", + }, + "stat:diff": { + desc: "Point Differential", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "Diff", + }, + "stat:yearsWithTeam": { + desc: "Years With Team", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "YWT", + }, + "count:allDefense": { + desc: "All-Defensive Team", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ADT", + }, + "count:allLeague": { + desc: "All-League Team", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ALT", + }, + "count:allRookie": { + desc: "All-Rookie Team", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ART", + }, + "count:allStar": { + desc: "All-Star", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "AS", + }, + "count:allStarMVP": { + desc: "All-Star MVP", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ASMVP", + }, + "count:bestRecord": { + desc: "Best Record", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "BR", + }, + "count:bestRecordConf": { + desc: "Best Conference Record", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "BRC", + }, + "count:dpoy": { + desc: "Defensive Player of the Year", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "DPOY", + }, + "count:dfoy": { + desc: "Defensive Forward of the Year", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "DFOY", + }, + "count:goy": { + desc: "Goalie of the Year", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "GOY", + }, + "count:mip": { + desc: "Most Improved Player", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "MIP", + }, + "count:mvp": { + desc: "Most Valuable Player", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "MVP", + }, + "count:roy": { + desc: "Rookie of the Year", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "ROY", + }, + "count:smoy": { + desc: "Sixth Man of the Year", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "SMOY", + }, + "count:oroy": { + desc: "Offensive Rookie of the Year", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OROY", + }, + "count:droy": { + desc: "Defensive Rookie of the Year", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "DROY", + }, + "award:dpoy": { + desc: "Defensive Player of the Year", + sortType: "name", + title: "DPOY", + }, + "award:dfoy": { + desc: "Defensive Forward of the Year", + sortType: "name", + title: "DFOY", + }, + "award:goy": { + desc: "Goalie of the Year", + sortType: "name", + title: "GOY", + }, + "award:finalsMvp": { + desc: `${isSport("hockey") ? "Playoffs" : "Finals"} Most Valuable Player`, + sortType: "name", + title: `${isSport("hockey") ? "Playoffs" : "Finals"} MVP`, + }, + "award:mip": { + desc: "Most Improved Player", + sortType: "name", + title: "MIP", + }, + "award:mvp": { + desc: "Most Valuable Player", + sortType: "name", + title: "MVP", + }, + "award:roy": { + desc: "Rookie of the Year", + sortType: "name", + title: "ROY", + }, + "award:smoy": { + desc: "Sixth Man of the Year", + sortType: "name", + title: "SMOY", + }, + "award:oroy": { + desc: "Offensive Rookie of the Year", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "OROY", + }, + "award:droy": { + desc: "Defensive Rookie of the Year", + sortSequence: ["desc", "asc"], + sortType: "number", + title: "DROY", + }, + ...sportSpecificCols, +}; + +export default ( + titles: string[], + overrides: Record> = {}, +): Col[] => { + return titles.map(title => { + if (!cols.hasOwnProperty(title)) { + throw new Error(`Unknown column: "${title}"`); + } + + return { + ...cols[title], + title: cols[title].title ?? title, + ...overrides[title], + }; + }); +}; diff --git a/src/ui/views/FreeAgents.tsx b/src/ui/views/FreeAgents.tsx index 6e3e26a984..9674c47514 100644 --- a/src/ui/views/FreeAgents.tsx +++ b/src/ui/views/FreeAgents.tsx @@ -10,9 +10,10 @@ import { RosterSalarySummary, } from "../components"; import useTitleBar from "../hooks/useTitleBar"; -import { confirm, getCols, helpers, toWorker, useLocalShallow } from "../util"; +import { confirm, helpers, toWorker, useLocalShallow } from "../util"; import type { View } from "../../common/types"; import { dataTableWrappedMood } from "../components/Mood"; +import getCols from "../util/getCols"; const FreeAgents = ({ capSpace, @@ -86,20 +87,13 @@ const FreeAgents = ({ "Exp", "Negotiate", ]); + console.log(cols[0]); const rows = players.map(p => { return { key: p.pid, data: [ - - {p.name} - , + cols[0].render(p), p.ratings.pos, p.age, !challengeNoRatings ? p.ratings.ovr : null, From 4bfd88afc45cd9b568d2006f137e3322e9ec9dba Mon Sep 17 00:00:00 2001 From: Vac1911 Date: Mon, 29 Nov 2021 14:01:23 -0500 Subject: [PATCH 03/43] Unified Column Configuration --- src/ui/util/TableConfig.ts | 42 + .../util/{getCols.tsx => columns/getCols.ts} | 1286 +++++++++-------- src/ui/util/columns/getTemplate.ts | 8 + src/ui/util/columns/templates/Age.tsx | 4 + src/ui/util/columns/templates/AskingFor.tsx | 6 + src/ui/util/columns/templates/Contract.tsx | 6 + src/ui/util/columns/templates/Exp.tsx | 4 + src/ui/util/columns/templates/Mood.tsx | 6 + src/ui/util/columns/templates/Name.tsx | 15 + src/ui/util/columns/templates/Negotiate.tsx | 14 + src/ui/util/columns/templates/Ovr.tsx | 12 + src/ui/util/columns/templates/PlayingTime.tsx | 7 + src/ui/util/columns/templates/Pos.tsx | 4 + src/ui/util/columns/templates/Pot.tsx | 12 + src/ui/util/columns/templates/Rating.tsx | 5 + src/ui/util/columns/templates/Release.tsx | 13 + src/ui/util/columns/templates/Stat.tsx | 7 + src/ui/util/columns/templates/Trade.tsx | 13 + src/ui/util/columns/templates/index.tsx | 15 + src/ui/views/FreeAgents.tsx | 80 +- .../views/Roster/RosterCustomizeColumns.tsx | 42 +- src/ui/views/Roster/index.tsx | 224 +-- src/worker/api/index.ts | 1 + src/worker/views/freeAgents.ts | 26 +- src/worker/views/roster.ts | 70 +- 25 files changed, 988 insertions(+), 934 deletions(-) create mode 100644 src/ui/util/TableConfig.ts rename src/ui/util/{getCols.tsx => columns/getCols.ts} (75%) create mode 100644 src/ui/util/columns/getTemplate.ts create mode 100644 src/ui/util/columns/templates/Age.tsx create mode 100644 src/ui/util/columns/templates/AskingFor.tsx create mode 100644 src/ui/util/columns/templates/Contract.tsx create mode 100644 src/ui/util/columns/templates/Exp.tsx create mode 100644 src/ui/util/columns/templates/Mood.tsx create mode 100644 src/ui/util/columns/templates/Name.tsx create mode 100644 src/ui/util/columns/templates/Negotiate.tsx create mode 100644 src/ui/util/columns/templates/Ovr.tsx create mode 100644 src/ui/util/columns/templates/PlayingTime.tsx create mode 100644 src/ui/util/columns/templates/Pos.tsx create mode 100644 src/ui/util/columns/templates/Pot.tsx create mode 100644 src/ui/util/columns/templates/Rating.tsx create mode 100644 src/ui/util/columns/templates/Release.tsx create mode 100644 src/ui/util/columns/templates/Stat.tsx create mode 100644 src/ui/util/columns/templates/Trade.tsx create mode 100644 src/ui/util/columns/templates/index.tsx diff --git a/src/ui/util/TableConfig.ts b/src/ui/util/TableConfig.ts new file mode 100644 index 0000000000..52b50b4ac0 --- /dev/null +++ b/src/ui/util/TableConfig.ts @@ -0,0 +1,42 @@ +import { idb } from "../../worker/db"; +import type { ColTemp } from "./columns/getCols"; +import getCols from "./columns/getCols"; +import { uniq } from "lodash-es"; + +export class TableConfig { + get ratingsNeeded(): string[] | undefined { + return this._ratingsNeeded; + } + get statsNeeded(): string[] | undefined { + return this._statsNeeded; + } + + protected fallback: string[]; + private _statsNeeded?: string[]; + private _ratingsNeeded?: string[]; + public columns: ColTemp[]; + public tableName: string; + + constructor(tableName: string, fallback: string[]) { + this.tableName = tableName; + this.fallback = fallback; + } + + public async load() { + const colOptions: object[] | undefined = await idb.meta.get( + "tables", + this.tableName, + ); + this.columns = getCols( + colOptions + ? colOptions.filter(c => !c.hidden).map(c => c.key) + : this.fallback, + ); + this._statsNeeded = uniq( + this.columns.reduce((needed, c) => needed.concat(c.stats ?? []), []), + ); + this._ratingsNeeded = uniq( + this.columns.reduce((needed, c) => needed.concat(c.ratings ?? []), []), + ); + } +} diff --git a/src/ui/util/getCols.tsx b/src/ui/util/columns/getCols.ts similarity index 75% rename from src/ui/util/getCols.tsx rename to src/ui/util/columns/getCols.ts index e999fbec74..a8a4d451ea 100644 --- a/src/ui/util/getCols.tsx +++ b/src/ui/util/columns/getCols.ts @@ -1,12 +1,13 @@ -import type { Col } from "../components/DataTable"; -import bySport from "../../common/bySport"; -import isSport from "../../common/isSport"; -import { PlayerNameLabels, RatingWithChange } from "../components"; -import type { Player } from "../../common/types"; +import type { Col } from "../../components/DataTable"; +import bySport from "../../../common/bySport"; +import isSport from "../../../common/isSport"; -type ColTemp = Omit & { +export type ColTemp = Omit & { title?: string; - render?: (p: Player) => JSX.Element; + ratings?: string[]; + stats?: string[]; + template?: string; + key?: string; }; const gp = isSport("hockey") ? "GP" : "G"; @@ -16,468 +17,624 @@ const sportSpecificCols = bySport<{ }>({ basketball: { "rating:fg": { + template: "Rating", + ratings: ["fg"], desc: "Mid Range", sortSequence: ["desc", "asc"], sortType: "number", title: "2Pt", }, "rating:tp": { + template: "Rating", + ratings: ["tp"], desc: "Three Pointers", sortSequence: ["desc", "asc"], sortType: "number", title: "3Pt", }, "rating:oiq": { + template: "Rating", + ratings: ["oiq"], desc: "Offensive IQ", sortSequence: ["desc", "asc"], sortType: "number", title: "oIQ", }, "rating:dnk": { + template: "Rating", + ratings: ["dnk"], desc: "Dunks/Layups", sortSequence: ["desc", "asc"], sortType: "number", title: "Dnk", }, "rating:drb": { + template: "Rating", + ratings: ["drb"], desc: "Dribbling", sortSequence: ["desc", "asc"], sortType: "number", title: "Drb", }, "rating:ins": { + template: "Rating", + ratings: ["ins"], desc: "Inside Scoring", sortSequence: ["desc", "asc"], sortType: "number", title: "Ins", }, "rating:jmp": { + template: "Rating", + ratings: ["jmp"], desc: "Jumping", sortSequence: ["desc", "asc"], sortType: "number", title: "Jmp", }, "rating:ft": { + template: "Rating", + ratings: ["ft"], desc: "Free Throws", sortSequence: ["desc", "asc"], sortType: "number", title: "FT", }, "rating:pss": { + template: "Rating", + ratings: ["pss"], desc: "Passing", sortSequence: ["desc", "asc"], sortType: "number", title: "Pss", }, "rating:reb": { + template: "Rating", + ratings: ["reb"], desc: "Rebounding", sortSequence: ["desc", "asc"], sortType: "number", title: "Reb", }, "rating:diq": { + template: "Rating", + ratings: ["diq"], desc: "Defensive IQ", sortSequence: ["desc", "asc"], sortType: "number", title: "dIQ", }, "stat:2pp": { + template: "Stat", + stats: ["2pp"], desc: "Two Point Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "2P%", }, "stat:2p": { + template: "Stat", + stats: ["2p"], desc: "Two Pointers Made", sortSequence: ["desc", "asc"], sortType: "number", title: "2P", }, "stat:2pa": { + template: "Stat", + stats: ["2pa"], desc: "Two Pointers Attempted", sortSequence: ["desc", "asc"], sortType: "number", title: "2PA", }, "stat:pm": { + template: "Stat", + stats: ["pm"], desc: "Plus/Minus", sortSequence: ["desc", "asc"], sortType: "number", title: "+/-", }, "stat:tpp": { + template: "Stat", + stats: ["tpp"], desc: "Three Point Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "3P%", }, "stat:tp": { + template: "Stat", + stats: ["tp"], desc: "Three Pointers Made", sortSequence: ["desc", "asc"], sortType: "number", title: "3P", }, "stat:tpa": { + template: "Stat", + stats: ["tpa"], desc: "Three Pointers Attempted", sortSequence: ["desc", "asc"], sortType: "number", title: "3PA", }, "stat:tpar": { + template: "Stat", + stats: ["tpar"], desc: "Three Point Attempt Rate (3PA / FGA)", sortSequence: ["desc", "asc"], sortType: "number", title: "3PAr", }, "stat:astp": { + template: "Stat", + stats: ["astp"], desc: "Percentage of teammate field goals a player assisted while on the floor", sortSequence: ["desc", "asc"], sortType: "number", title: "AST%", }, "stat:ast": { + template: "Stat", + stats: ["ast"], desc: "Assists", sortSequence: ["desc", "asc"], sortType: "number", title: "AST", }, "stat:ba": { + template: "Stat", + stats: ["ba"], desc: "Blocks Against", sortSequence: ["desc", "asc"], sortType: "number", title: "BA", }, "stat:blk": { + template: "Stat", + stats: ["blk"], desc: "Blocks", sortSequence: ["desc", "asc"], sortType: "number", title: "BLK", }, "stat:blkp": { + template: "Stat", + stats: ["blkp"], desc: "Percentage of opponent two-pointers blocked", sortSequence: ["desc", "asc"], sortType: "number", title: "BLK%", }, "stat:drb": { + template: "Stat", + stats: ["drb"], desc: "Defensive Rebounds", sortSequence: ["desc", "asc"], sortType: "number", title: "DRB", }, "stat:drbp": { + template: "Stat", + stats: ["drbp"], desc: "Percentage of available defensive rebounds grabbed", sortSequence: ["desc", "asc"], sortType: "number", title: "DRB%", }, "stat:drtg": { + template: "Stat", + stats: ["drtg"], desc: "Defensive Rating (points allowed per 100 possessions)", sortSequence: ["asc", "desc"], sortType: "number", title: "DRtg", }, "stat:dws": { + template: "Stat", + stats: ["dws"], desc: "Defensive Win Shares", sortSequence: ["desc", "asc"], sortType: "number", title: "DWS", }, "stat:ewa": { + template: "Stat", + stats: ["ewa"], desc: "Estimated Wins Added", sortSequence: ["desc", "asc"], sortType: "number", title: "EWA", }, "stat:efg": { + template: "Stat", + stats: ["efg"], desc: "Effective Field Goal Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "eFG%", }, "stat:fgp": { + template: "Stat", + stats: ["fgp"], desc: "Field Goal Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "FG%", }, "stat:fg": { + template: "Stat", + stats: ["fg"], desc: "Field Goals Made", sortSequence: ["desc", "asc"], sortType: "number", title: "FG", }, "stat:fga": { + template: "Stat", + stats: ["fga"], desc: "Field Goals Attempted", sortSequence: ["desc", "asc"], sortType: "number", title: "FGA", }, "stat:ftp": { + template: "Stat", + stats: ["ftp"], desc: "Free Throw Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "FT%", }, "stat:ft": { + template: "Stat", + stats: ["ft"], desc: "Free Throws Made", sortSequence: ["desc", "asc"], sortType: "number", title: "FT", }, "stat:fta": { + template: "Stat", + stats: ["fta"], desc: "Free Throws Attempted", sortSequence: ["desc", "asc"], sortType: "number", title: "FTA", }, "stat:ftpFga": { + template: "Stat", + stats: ["ftpFga"], desc: "Free Throws per Field Goal Attempted", sortSequence: ["desc", "asc"], sortType: "number", title: "FTr", }, "stat:ftr": { + template: "Stat", + stats: ["ftr"], desc: "Free Throw Attempt Rate (FTA / FGA)", sortSequence: ["desc", "asc"], sortType: "number", title: "FT/FGA", }, "stat:gmsc": { + template: "Stat", + stats: ["gmsc"], desc: "Game Score", sortSequence: ["desc", "asc"], sortType: "number", title: "GmSc", }, "stat:nrtg": { + template: "Stat", + stats: ["nrtg"], desc: "Net Rating (point differential per 100 possessions)", sortSequence: ["desc", "asc"], sortType: "number", title: "NRtg", }, "stat:orb": { + template: "Stat", + stats: ["orb"], desc: "Offensive Rebounds", sortSequence: ["desc", "asc"], sortType: "number", title: "ORB", }, "stat:orbp": { + template: "Stat", + stats: ["orbp"], desc: "Percentage of available offensive rebounds grabbed", sortSequence: ["desc", "asc"], sortType: "number", title: "ORB%", }, "stat:ortg": { + template: "Stat", + stats: ["ortg"], desc: "Offensive Rating (points produced/scored per 100 possessions)", sortSequence: ["desc", "asc"], sortType: "number", title: "ORtg", }, "stat:ows": { + template: "Stat", + stats: ["ows"], desc: "Offensive Win Shares", sortSequence: ["desc", "asc"], sortType: "number", title: "OWS", }, "stat:pace": { + template: "Stat", + stats: ["pace"], desc: "Possessions Per Game", sortSequence: ["desc", "asc"], sortType: "number", title: "Pace", }, "stat:per": { + template: "Stat", + stats: ["per"], desc: "Player Efficiency Rating", sortSequence: ["desc", "asc"], sortType: "number", title: "PER", }, "stat:pf": { + template: "Stat", + stats: ["pf"], desc: "Personal Fouls", sortSequence: ["desc", "asc"], sortType: "number", title: "PF", }, "stat:pl": { + template: "Stat", + stats: ["pl"], desc: "Pythagorean Losses (expected losses based on points scored and allowed)", sortSequence: ["desc", "asc"], sortType: "number", title: "PL", }, "stat:pts": { + template: "Stat", + stats: ["pts"], desc: "Points", sortSequence: ["desc", "asc"], sortType: "number", title: "PTS", }, "stat:pw": { + template: "Stat", + stats: ["pw"], desc: "Pythagorean Wins (expected wins based on points scored and allowed)", sortSequence: ["desc", "asc"], sortType: "number", title: "PW", }, "stat:stl": { + template: "Stat", + stats: ["stl"], desc: "Steals", sortSequence: ["desc", "asc"], sortType: "number", title: "STL", }, "stat:stlp": { + template: "Stat", + stats: ["stlp"], desc: "Percentage of opponent possessions ending in steals", sortSequence: ["desc", "asc"], sortType: "number", title: "STL%", }, "stat:tovp": { + template: "Stat", + stats: ["tovp"], desc: "Turnovers per 100 plays", sortSequence: ["desc", "asc"], sortType: "number", title: "TOV%", }, "stat:trb": { + template: "Stat", + stats: ["trb"], desc: "Total Rebounds", sortSequence: ["desc", "asc"], sortType: "number", title: "TRB", }, "stat:trbp": { + template: "Stat", + stats: ["trbp"], desc: "Percentage of available rebounds grabbed", sortSequence: ["desc", "asc"], sortType: "number", title: "TRB%", }, "stat:tsp": { + template: "Stat", + stats: ["tsp"], desc: "True Shooting Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "TS%", }, "stat:tov": { + template: "Stat", + stats: ["tov"], desc: "Turnovers", sortSequence: ["desc", "asc"], sortType: "number", title: "TOV", }, "stat:usgp": { + template: "Stat", + stats: ["usgp"], desc: "Percentage of team plays used", sortSequence: ["desc", "asc"], sortType: "number", title: "USG%", }, "stat:ws": { + template: "Stat", + stats: ["ws"], desc: "Win Shares", sortSequence: ["desc", "asc"], sortType: "number", title: "WS", }, "stat:wsPerPlayer": { + template: "Stat", + stats: ["wsPerPlayer"], desc: "Win Shares Per Player", sortSequence: ["desc", "asc"], sortType: "number", title: "WS/Player", }, "stat:ws48": { + template: "Stat", + stats: ["ws48"], desc: "Win Shares Per 48 Minutes", sortSequence: ["desc", "asc"], sortType: "number", title: "WS/48", }, "stat:obpm": { + template: "Stat", + stats: ["obpm"], desc: "Offensive Box Plus-Minus", sortSequence: ["desc", "asc"], sortType: "number", title: "OBPM", }, "stat:dbpm": { + template: "Stat", + stats: ["dbpm"], desc: "Defensive Box Plus-Minus", sortSequence: ["desc", "asc"], sortType: "number", title: "DBPM", }, "stat:bpm": { + template: "Stat", + stats: ["bpm"], desc: "Box Plus-Minus", sortSequence: ["desc", "asc"], sortType: "number", title: "BPM", }, "stat:vorp": { + template: "Stat", + stats: ["vorp"], desc: "Value Over Replacement Player", sortSequence: ["desc", "asc"], sortType: "number", title: "VORP", }, "stat:fgAtRim": { + template: "Stat", + stats: ["fgAtRim"], desc: "At Rim Made", sortSequence: ["desc", "asc"], sortType: "number", title: "M", }, "stat:fgaAtRim": { + template: "Stat", + stats: ["fgaAtRim"], desc: "At Rim Attempted", sortSequence: ["desc", "asc"], sortType: "number", title: "A", }, "stat:fgpAtRim": { + template: "Stat", + stats: ["fgpAtRim"], desc: "At Rim Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "%", }, "stat:fgLowPost": { + template: "Stat", + stats: ["fgLowPost"], desc: "Low Post Made", sortSequence: ["desc", "asc"], sortType: "number", title: "M", }, "stat:fgaLowPost": { + template: "Stat", + stats: ["fgaLowPost"], desc: "Low Post Attempted", sortSequence: ["desc", "asc"], sortType: "number", title: "A", }, "stat:fgpLowPost": { + template: "Stat", + stats: ["fgpLowPost"], desc: "Low Post Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "%", }, "stat:fgMidRange": { + template: "Stat", + stats: ["fgMidRange"], desc: "Mid Range Made", sortSequence: ["desc", "asc"], sortType: "number", title: "M", }, "stat:fgaMidRange": { + template: "Stat", + stats: ["fgaMidRange"], desc: "Mid Range Attempted", sortSequence: ["desc", "asc"], sortType: "number", title: "A", }, "stat:fgpMidRange": { + template: "Stat", + stats: ["fgpMidRange"], desc: "Mid Range Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "%", }, "stat:dd": { + template: "Stat", + stats: ["dd"], desc: "Double Doubles", sortSequence: ["desc", "asc"], sortType: "number", title: "DD", }, "stat:td": { + template: "Stat", + stats: ["td"], desc: "Triple Doubles", sortSequence: ["desc", "asc"], sortType: "number", title: "TD", }, "stat:qd": { + template: "Stat", + stats: ["qd"], desc: "Quadruple Doubles", sortSequence: ["desc", "asc"], sortType: "number", title: "QD", }, "stat:fxf": { + template: "Stat", + stats: ["fxf"], desc: "Five by Fives", sortSequence: ["desc", "asc"], sortType: "number", @@ -541,966 +698,1288 @@ const sportSpecificCols = bySport<{ title: "P", }, "rating:thv": { + template: "Rating", + ratings: ["thv"], desc: "Throwing Vision", sortSequence: ["desc", "asc"], sortType: "number", title: "ThV", }, "rating:thp": { + template: "Rating", + ratings: ["thp"], desc: "Throwing Power", sortSequence: ["desc", "asc"], sortType: "number", title: "ThP", }, "rating:tha": { + template: "Rating", + ratings: ["tha"], desc: "Throwing Accuracy", sortSequence: ["desc", "asc"], sortType: "number", title: "ThA", }, "rating:bsc": { + template: "Rating", + ratings: ["bsc"], desc: "Ball Security", sortSequence: ["desc", "asc"], sortType: "number", title: "BSc", }, "rating:elu": { + template: "Rating", + ratings: ["elu"], desc: "Elusiveness", sortSequence: ["desc", "asc"], sortType: "number", title: "Elu", }, "rating:rtr": { + template: "Rating", + ratings: ["rtr"], desc: "Route Running", sortSequence: ["desc", "asc"], sortType: "number", title: "RtR", }, "rating:hnd": { + template: "Rating", + ratings: ["hnd"], desc: "Hands", sortSequence: ["desc", "asc"], sortType: "number", title: "Hnd", }, "rating:rbk": { + template: "Rating", + ratings: ["rbk"], desc: "Run Blocking", sortSequence: ["desc", "asc"], sortType: "number", title: "RBk", }, "rating:pbk": { + template: "Rating", + ratings: ["pbk"], desc: "Pass Blocking", sortSequence: ["desc", "asc"], sortType: "number", title: "PBk", }, "rating:pcv": { + template: "Rating", + ratings: ["pcv"], desc: "Pass Coverage", sortSequence: ["desc", "asc"], sortType: "number", title: "PCv", }, "rating:tck": { + template: "Rating", + ratings: ["tck"], desc: "Tackling", sortSequence: ["desc", "asc"], sortType: "number", title: "Tck", }, "rating:prs": { + template: "Rating", + ratings: ["prs"], desc: "Pass Rushing", sortSequence: ["desc", "asc"], sortType: "number", title: "PRs", }, "rating:rns": { + template: "Rating", + ratings: ["rns"], desc: "Run Stopping", sortSequence: ["desc", "asc"], sortType: "number", title: "RnS", }, "rating:kpw": { + template: "Rating", + ratings: ["kpw"], desc: "Kicking Power", sortSequence: ["desc", "asc"], sortType: "number", title: "KPw", }, "rating:kac": { + template: "Rating", + ratings: ["kac"], desc: "Kicking Accuracy", sortSequence: ["desc", "asc"], sortType: "number", title: "KAc", }, "rating:ppw": { + template: "Rating", + ratings: ["ppw"], desc: "Punting Power", sortSequence: ["desc", "asc"], sortType: "number", title: "PPw", }, "rating:pac": { + template: "Rating", + ratings: ["pac"], desc: "Punting Accuracy", sortSequence: ["desc", "asc"], sortType: "number", title: "PAc", }, "rating:ovrQB": { + template: "Rating", + ratings: ["ovrQB"], desc: "Overall Rating (QB)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrQB", }, "rating:ovrRB": { + template: "Rating", + ratings: ["ovrRB"], desc: "Overall Rating (RB)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrRB", }, "rating:ovrWR": { + template: "Rating", + ratings: ["ovrWR"], desc: "Overall Rating (WR)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrWR", }, "rating:ovrTE": { + template: "Rating", + ratings: ["ovrTE"], desc: "Overall Rating (TE)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrTE", }, "rating:ovrOL": { + template: "Rating", + ratings: ["ovrOL"], desc: "Overall Rating (OL)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrOL", }, "rating:ovrDL": { + template: "Rating", + ratings: ["ovrDL"], desc: "Overall Rating (DL)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrDL", }, "rating:ovrLB": { + template: "Rating", + ratings: ["ovrLB"], desc: "Overall Rating (LB)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrLB", }, "rating:ovrCB": { + template: "Rating", + ratings: ["ovrCB"], desc: "Overall Rating (CB)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrCB", }, "rating:ovrS": { + template: "Rating", + ratings: ["ovrS"], desc: "Overall Rating (S)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrS", }, "rating:ovrK": { + template: "Rating", + ratings: ["ovrK"], desc: "Overall Rating (K)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrK", }, "rating:ovrP": { + template: "Rating", + ratings: ["ovrP"], desc: "Overall Rating (P)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrP", }, "rating:ovrKR": { + template: "Rating", + ratings: ["ovrKR"], desc: "Overall Rating (KR)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrKR", }, "rating:ovrPR": { + template: "Rating", + ratings: ["ovrPR"], desc: "Overall Rating (PR)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrPR", }, "rating:potQB": { + template: "Rating", + ratings: ["potQB"], desc: "Potential Rating (QB)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotQB", }, "rating:potRB": { + template: "Rating", + ratings: ["potRB"], desc: "Potential Rating (RB)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotRB", }, "rating:potWR": { + template: "Rating", + ratings: ["potWR"], desc: "Potential Rating (WR)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotWR", }, "rating:potTE": { + template: "Rating", + ratings: ["potTE"], desc: "Potential Rating (TE)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotTE", }, "rating:potOL": { + template: "Rating", + ratings: ["potOL"], desc: "Potential Rating (OL)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotOL", }, "rating:potDL": { + template: "Rating", + ratings: ["potDL"], desc: "Potential Rating (DL)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotDL", }, "rating:potLB": { + template: "Rating", + ratings: ["potLB"], desc: "Potential Rating (LB)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotLB", }, "rating:potCB": { + template: "Rating", + ratings: ["potCB"], desc: "Potential Rating (CB)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotCB", }, "rating:potS": { + template: "Rating", + ratings: ["potS"], desc: "Potential Rating (S)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotS", }, "rating:potK": { + template: "Rating", + ratings: ["potK"], desc: "Potential Rating (K)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotK", }, "rating:potP": { + template: "Rating", + ratings: ["potP"], desc: "Potential Rating (P)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotP", }, "rating:potKR": { + template: "Rating", + ratings: ["potKR"], desc: "Potential Rating (KR)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotKR", }, "rating:potPR": { + template: "Rating", + ratings: ["potPR"], desc: "Potential Rating (PR)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotPR", }, "stat:fmb": { + template: "Stat", + stats: ["fmb"], desc: "Fumbles", sortSequence: ["desc", "asc"], sortType: "number", title: "Fmb", }, "stat:fmbLost": { + template: "Stat", + stats: ["fmbLost"], desc: "Fumbles Lost", sortSequence: ["desc", "asc"], sortType: "number", title: "FL", }, "stat:fp": { + template: "Stat", + stats: ["fp"], desc: "Fantasy Points", sortSequence: ["desc", "asc"], sortType: "number", title: "FP", }, "stat:pssCmp": { + template: "Stat", + stats: ["pssCmp"], desc: "Completions", sortSequence: ["desc", "asc"], sortType: "number", title: "Cmp", }, "stat:pss": { + template: "Stat", + stats: ["pss"], desc: "Passing Attempts", sortSequence: ["desc", "asc"], sortType: "number", title: "Att", }, "stat:pssYds": { + template: "Stat", + stats: ["pssYds"], desc: "Passing Yards", sortSequence: ["desc", "asc"], sortType: "number", title: "Yds", }, "stat:pssTD": { + template: "Stat", + stats: ["pssTD"], desc: "Passing Touchdowns", sortSequence: ["desc", "asc"], sortType: "number", title: "TD", }, "stat:pssInt": { + template: "Stat", + stats: ["pssInt"], desc: "Interceptions", sortSequence: ["desc", "asc"], sortType: "number", title: "Int", }, "stat:pssLng": { + template: "Stat", + stats: ["pssLng"], desc: "Longest Pass", sortSequence: ["desc", "asc"], sortType: "number", title: "Lng", }, "stat:pssSk": { + template: "Stat", + stats: ["pssSk"], desc: "Times Sacked", sortSequence: ["desc", "asc"], sortType: "number", title: "Sk", }, "stat:pssSkYds": { + template: "Stat", + stats: ["pssSkYds"], desc: "Yards lost due to sacks", sortSequence: ["desc", "asc"], sortType: "number", title: "Yds", }, "stat:rus": { + template: "Stat", + stats: ["rus"], desc: "Rushing Attempts", sortSequence: ["desc", "asc"], sortType: "number", title: "Rush", }, "stat:rusYds": { + template: "Stat", + stats: ["rusYds"], desc: "Rushing Yards", sortSequence: ["desc", "asc"], sortType: "number", title: "Yds", }, "stat:rusTD": { + template: "Stat", + stats: ["rusTD"], desc: "Rushing Touchdowns", sortSequence: ["desc", "asc"], sortType: "number", title: "TD", }, "stat:rusLng": { + template: "Stat", + stats: ["rusLng"], desc: "Longest Run", sortSequence: ["desc", "asc"], sortType: "number", title: "Lng", }, "stat:tgt": { + template: "Stat", + stats: ["tgt"], desc: "Targets", sortSequence: ["desc", "asc"], sortType: "number", title: "Tgt", }, "stat:rec": { + template: "Stat", + stats: ["rec"], desc: "Receptions", sortSequence: ["desc", "asc"], sortType: "number", title: "Rec", }, "stat:recYds": { + template: "Stat", + stats: ["recYds"], desc: "Receiving Yards", sortSequence: ["desc", "asc"], sortType: "number", title: "Yds", }, "stat:recTD": { + template: "Stat", + stats: ["recTD"], desc: "Receiving Touchdowns", sortSequence: ["desc", "asc"], sortType: "number", title: "TD", }, "stat:recLng": { + template: "Stat", + stats: ["recLng"], desc: "Longest Reception", sortSequence: ["desc", "asc"], sortType: "number", title: "Lng", }, "stat:pr": { + template: "Stat", + stats: ["pr"], desc: "Punt Returns", sortSequence: ["desc", "asc"], sortType: "number", title: "PR", }, "stat:prYds": { + template: "Stat", + stats: ["prYds"], desc: "Punt Return Yards", sortSequence: ["desc", "asc"], sortType: "number", title: "Yds", }, "stat:prTD": { + template: "Stat", + stats: ["prTD"], desc: "Punts returned for touchdowns", sortSequence: ["desc", "asc"], sortType: "number", title: "TD", }, "stat:prLng": { + template: "Stat", + stats: ["prLng"], desc: "Longest Punt Return", sortSequence: ["desc", "asc"], sortType: "number", title: "Lng", }, "stat:kr": { + template: "Stat", + stats: ["kr"], desc: "Kickoff Returns", sortSequence: ["desc", "asc"], sortType: "number", title: "KR", }, "stat:krYds": { + template: "Stat", + stats: ["krYds"], desc: "Kickoff Return Yards", sortSequence: ["desc", "asc"], sortType: "number", title: "Yds", }, "stat:krTD": { + template: "Stat", + stats: ["krTD"], desc: "Kickoffs returned for touchdowns", sortSequence: ["desc", "asc"], sortType: "number", title: "TD", }, "stat:krLng": { + template: "Stat", + stats: ["krLng"], desc: "Longest Kickoff Return", sortSequence: ["desc", "asc"], sortType: "number", title: "Lng", }, "stat:defInt": { + template: "Stat", + stats: ["defInt"], desc: "Interceptions", sortSequence: ["desc", "asc"], sortType: "number", title: "Int", }, "stat:defIntYds": { + template: "Stat", + stats: ["defIntYds"], desc: "Yards interceptions were returned for", sortSequence: ["desc", "asc"], sortType: "number", title: "Yds", }, "stat:defIntTD": { + template: "Stat", + stats: ["defIntTD"], desc: "Interceptions returned for touchdowns", sortSequence: ["desc", "asc"], sortType: "number", title: "TD", }, "stat:defIntLng": { + template: "Stat", + stats: ["defIntLng"], desc: "Longest Interception Return", sortSequence: ["desc", "asc"], sortType: "number", title: "Lng", }, "stat:defPssDef": { + template: "Stat", + stats: ["defPssDef"], desc: "Passes Defended", sortSequence: ["desc", "asc"], sortType: "number", title: "PD", }, "stat:defFmbFrc": { + template: "Stat", + stats: ["defFmbFrc"], desc: "Forced Fumbles", sortSequence: ["desc", "asc"], sortType: "number", title: "FF", }, "stat:defFmbRec": { + template: "Stat", + stats: ["defFmbRec"], desc: "Fumbles Recovered", sortSequence: ["desc", "asc"], sortType: "number", title: "FR", }, "stat:defFmbYds": { + template: "Stat", + stats: ["defFmbYds"], desc: "Yards fumbles were returned for", sortSequence: ["desc", "asc"], sortType: "number", title: "Yds", }, "stat:defFmbTD": { + template: "Stat", + stats: ["defFmbTD"], desc: "Fumbles returned for touchdowns", sortSequence: ["desc", "asc"], sortType: "number", title: "TD", }, "stat:defFmbLng": { + template: "Stat", + stats: ["defFmbLng"], desc: "Longest Fumble Return", sortSequence: ["desc", "asc"], sortType: "number", title: "Lng", }, "stat:defSk": { + template: "Stat", + stats: ["defSk"], desc: "Sacks", sortSequence: ["desc", "asc"], sortType: "number", title: "Sk", }, "stat:defTckSolo": { + template: "Stat", + stats: ["defTckSolo"], desc: "Solo Tackles", sortSequence: ["desc", "asc"], sortType: "number", title: "Solo", }, "stat:defTckAst": { + template: "Stat", + stats: ["defTckAst"], desc: "Assists On Tackles", sortSequence: ["desc", "asc"], sortType: "number", title: "Ast", }, "stat:defTckLoss": { + template: "Stat", + stats: ["defTckLoss"], desc: "Tackes For Loss", sortSequence: ["desc", "asc"], sortType: "number", title: "TFL", }, "stat:defSft": { + template: "Stat", + stats: ["defSft"], desc: "Safeties Scored", sortSequence: ["desc", "asc"], sortType: "number", title: "Sfty", }, "stat:fg0": { + template: "Stat", + stats: ["fg0"], desc: "Field Goals Made, 19 yards and under", sortSequence: ["desc", "asc"], sortType: "number", title: "FG10", }, "stat:fga0": { + template: "Stat", + stats: ["fga0"], desc: "Field Goals Attempted, 19 yards and under", sortSequence: ["desc", "asc"], sortType: "number", title: "FGA10", }, "stat:fg20": { + template: "Stat", + stats: ["fg20"], desc: "Field Goals Made, 20-29 yards", sortSequence: ["desc", "asc"], sortType: "number", title: "FG20", }, "stat:fga20": { + template: "Stat", + stats: ["fga20"], desc: "Field Goals Attempted, 20-29 yards", sortSequence: ["desc", "asc"], sortType: "number", title: "FGA20", }, "stat:fg30": { + template: "Stat", + stats: ["fg30"], desc: "Field Goals Made, 30-39 yards", sortSequence: ["desc", "asc"], sortType: "number", title: "FG30", }, "stat:fga30": { + template: "Stat", + stats: ["fga30"], desc: "Field Goals Attempted, 30-39 yards", sortSequence: ["desc", "asc"], sortType: "number", title: "FGA30", }, "stat:fg40": { + template: "Stat", + stats: ["fg40"], desc: "Field Goals Made, 40-49 yards", sortSequence: ["desc", "asc"], sortType: "number", title: "FG40", }, "stat:fga40": { + template: "Stat", + stats: ["fga40"], desc: "Field Goals Attempted, 40-49 yards", sortSequence: ["desc", "asc"], sortType: "number", title: "FGA40", }, "stat:fg50": { + template: "Stat", + stats: ["fg50"], desc: "Field Goals Made, 50+ yards", sortSequence: ["desc", "asc"], sortType: "number", title: "FG50", }, "stat:fga50": { + template: "Stat", + stats: ["fga50"], desc: "Field Goals Attempted, 50+ yards", sortSequence: ["desc", "asc"], sortType: "number", title: "FGA50", }, "stat:fgLng": { + template: "Stat", + stats: ["fgLng"], desc: "Longest Field Goal", sortSequence: ["desc", "asc"], sortType: "number", title: "Lng", }, "stat:xp": { + template: "Stat", + stats: ["xp"], desc: "Extra Points Made", sortSequence: ["desc", "asc"], sortType: "number", title: "XPM", }, "stat:xpa": { + template: "Stat", + stats: ["xpa"], desc: "Extra Points Attempted", sortSequence: ["desc", "asc"], sortType: "number", title: "XPA", }, "stat:pnt": { + template: "Stat", + stats: ["pnt"], desc: "Times Punted", sortSequence: ["desc", "asc"], sortType: "number", title: "Pnt", }, "stat:pntYds": { + template: "Stat", + stats: ["pntYds"], desc: "Total Punt Yardage", sortSequence: ["desc", "asc"], sortType: "number", title: "Yds", }, "stat:pntLng": { + template: "Stat", + stats: ["pntLng"], desc: "Longest Punt", sortSequence: ["desc", "asc"], sortType: "number", title: "Lng", }, "stat:pntBlk": { + template: "Stat", + stats: ["pntBlk"], desc: "Times Punts Blocked", sortSequence: ["desc", "asc"], sortType: "number", title: "Blk", }, "stat:pen": { + template: "Stat", + stats: ["pen"], desc: "Penalties", sortSequence: ["desc", "asc"], sortType: "number", title: "Pen", }, "stat:penYds": { + template: "Stat", + stats: ["penYds"], desc: "Penalty Yards", sortSequence: ["desc", "asc"], sortType: "number", title: "Yds", }, "stat:cmpPct": { + template: "Stat", + stats: ["cmpPct"], desc: "Completion Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "Pct", }, "stat:qbRat": { + template: "Stat", + stats: ["qbRat"], desc: "Quarterback Rating", sortSequence: ["desc", "asc"], sortType: "number", title: "QBRat", }, "stat:rusYdsPerAtt": { + template: "Stat", + stats: ["rusYdsPerAtt"], desc: "Rushing Yards Per Attempt", sortSequence: ["desc", "asc"], sortType: "number", title: "Y/A", }, "stat:recYdsPerAtt": { + template: "Stat", + stats: ["recYdsPerAtt"], desc: "Yards Per Catch", sortSequence: ["desc", "asc"], sortType: "number", title: "Y/A", }, "stat:fg": { + template: "Stat", + stats: ["fg"], desc: "Field Goals Made", sortSequence: ["desc", "asc"], sortType: "number", title: "FGM", }, "stat:fga": { + template: "Stat", + stats: ["fga"], desc: "Field Goals Attempted", sortSequence: ["desc", "asc"], sortType: "number", title: "FGA", }, "stat:fgPct": { + template: "Stat", + stats: ["fgPct"], desc: "Field Goal Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "Pct", }, "stat:xpPct": { + template: "Stat", + stats: ["xpPct"], desc: "Extra Point Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "Pct", }, "stat:kickingPts": { + template: "Stat", + stats: ["kickingPts"], desc: "Kicking Points", sortSequence: ["desc", "asc"], sortType: "number", title: "Pts", }, "stat:pntYdsPerAtt": { + template: "Stat", + stats: ["pntYdsPerAtt"], desc: "Yards Per Punt", sortSequence: ["desc", "asc"], sortType: "number", title: "Y/A", }, "stat:pntTB": { + template: "Stat", + stats: ["pntTB"], desc: "Punt Touchbacks", sortSequence: ["desc", "asc"], sortType: "number", title: "TB", }, "stat:pntIn20": { + template: "Stat", + stats: ["pntIn20"], desc: "Punts Inside 20", sortSequence: ["desc", "asc"], sortType: "number", title: "In20", }, "stat:krYdsPerAtt": { + template: "Stat", + stats: ["krYdsPerAtt"], desc: "Yards Per Kick Return", sortSequence: ["desc", "asc"], sortType: "number", title: "Y/A", }, "stat:prYdsPerAtt": { + template: "Stat", + stats: ["prYdsPerAtt"], desc: "Yards Per Punt Return", sortSequence: ["desc", "asc"], sortType: "number", title: "Y/A", }, "stat:defTck": { + template: "Stat", + stats: ["defTck"], desc: "Total Tackles", sortSequence: ["desc", "asc"], sortType: "number", title: "Tck", }, "stat:keyStats": { + template: "Stat", + stats: ["keyStats"], desc: "Key Stats", sortSequence: ["desc", "asc"], sortType: "string", title: "Stats", }, "stat:pts": { + template: "Stat", + stats: ["pts"], desc: "", sortSequence: ["desc", "asc"], sortType: "number", title: "Pts", }, "stat:yds": { + template: "Stat", + stats: ["yds"], desc: "Offensive Yards", sortSequence: ["desc", "asc"], sortType: "number", title: "Yds", }, "stat:ply": { + template: "Stat", + stats: ["ply"], desc: "Plays", sortSequence: ["desc", "asc"], sortType: "number", title: "Ply", }, "stat:ydsPerPlay": { + template: "Stat", + stats: ["ydsPerPlay"], desc: "Yards Per Play", sortSequence: ["desc", "asc"], sortType: "number", title: "Y/P", }, "stat:tov": { + template: "Stat", + stats: ["tov"], desc: "Turnovers", sortSequence: ["desc", "asc"], sortType: "number", title: "TO", }, "stat:drives": { + template: "Stat", + stats: ["drives"], desc: "Number of Drives", sortSequence: ["desc", "asc"], sortType: "number", title: "#Dr", }, "stat:drivesScoringPct": { + template: "Stat", + stats: ["drivesScoringPct"], desc: "Percentage of drives ending in a score", sortSequence: ["desc", "asc"], sortType: "number", title: "Sc%", }, "stat:drivesTurnoverPct": { + template: "Stat", + stats: ["drivesTurnoverPct"], desc: "Percentage of drives ending in a turnover", sortSequence: ["desc", "asc"], sortType: "number", title: "TO%", }, "stat:avgFieldPosition": { + template: "Stat", + stats: ["avgFieldPosition"], desc: "Average Starting Field Position", sortSequence: ["desc", "asc"], sortType: "number", title: "Start", }, "stat:timePerDrive": { + template: "Stat", + stats: ["timePerDrive"], desc: "Time Per Drive (minutes)", sortSequence: ["desc", "asc"], sortType: "number", title: "Tm/D", }, "stat:playsPerDrive": { + template: "Stat", + stats: ["playsPerDrive"], desc: "Number of Plays Per Drive", sortSequence: ["desc", "asc"], sortType: "number", title: "Ply/D", }, "stat:ydsPerDrive": { + template: "Stat", + stats: ["ydsPerDrive"], desc: "Yards Per Drive", sortSequence: ["desc", "asc"], sortType: "number", title: "Y/D", }, "stat:ptsPerDrive": { + template: "Stat", + stats: ["ptsPerDrive"], desc: "Points Per Drive", sortSequence: ["desc", "asc"], sortType: "number", title: "Pts/D", }, "stat:qbRec": { + template: "Stat", + stats: ["qbRec"], desc: "Record as primary QB", sortSequence: ["desc", "asc"], sortType: "record", title: "QBRec", }, "stat:qbW": { + template: "Stat", + stats: ["qbW"], desc: "Wins as primary QB", sortSequence: ["desc", "asc"], sortType: "record", title: "QBW", }, "stat:qbL": { + template: "Stat", + stats: ["qbL"], desc: "Losses as primary QB", sortSequence: ["desc", "asc"], sortType: "record", title: "QBL", }, "stat:qbT": { + template: "Stat", + stats: ["qbT"], desc: "Ties as primary QB", sortSequence: ["desc", "asc"], sortType: "record", title: "QBT", }, "stat:qbOTL": { + template: "Stat", + stats: ["qbOTL"], desc: "Overtime losses as primary QB", sortSequence: ["desc", "asc"], sortType: "record", title: "QBOTL", }, "stat:pssTDPct": { + template: "Stat", + stats: ["pssTDPct"], desc: "Percentage of passes that result in touchdowns", sortSequence: ["desc", "asc"], sortType: "number", title: "TD%", }, "stat:pssIntPct": { + template: "Stat", + stats: ["pssIntPct"], desc: "Percentage of passes that result in interceptions", sortSequence: ["desc", "asc"], sortType: "number", title: "Int%", }, "stat:pssYdsPerAtt": { + template: "Stat", + stats: ["pssYdsPerAtt"], desc: "Pass Yards Per Attempt", sortSequence: ["desc", "asc"], sortType: "number", title: "Y/A", }, "stat:pssAdjYdsPerAtt": { + template: "Stat", + stats: ["pssAdjYdsPerAtt"], desc: "Adjusted Pass Yards Per Attempt ((yds + 20 * TD - 45 * int) / att)", sortSequence: ["desc", "asc"], sortType: "number", title: "AY/A", }, "stat:pssYdsPerCmp": { + template: "Stat", + stats: ["pssYdsPerCmp"], desc: "Pass Yards Per Completion", sortSequence: ["desc", "asc"], sortType: "number", title: "Y/C", }, "stat:pssYdsPerGame": { + template: "Stat", + stats: ["pssYdsPerGame"], desc: "Pass Yards Per Game", sortSequence: ["desc", "asc"], sortType: "number", title: "Y/G", }, "stat:pssNetYdsPerAtt": { + template: "Stat", + stats: ["pssNetYdsPerAtt"], desc: "Net Pass Yards Per Attempt (passes and sacks)", sortSequence: ["desc", "asc"], sortType: "number", title: "NY/A", }, "stat:pssAdjNetYdsPerAtt": { + template: "Stat", + stats: ["pssAdjNetYdsPerAtt"], desc: "Adjusted Net Pass Yards Per Attempt ((yds + 20 * TD - 45 * int - skYds) / (att + sk))", sortSequence: ["desc", "asc"], sortType: "number", title: "ANY/A", }, "stat:pssSkPct": { + template: "Stat", + stats: ["pssSkPct"], desc: "Percentage of times sacked when attempting a pass", sortSequence: ["desc", "asc"], sortType: "number", title: "Sk%", }, "stat:rusYdsPerGame": { + template: "Stat", + stats: ["rusYdsPerGame"], desc: "Rushing Yards Per Game", sortSequence: ["desc", "asc"], sortType: "number", title: "Y/G", }, "stat:rusPerGame": { + template: "Stat", + stats: ["rusPerGame"], desc: "Rushing Attempts Per Game", sortSequence: ["desc", "asc"], sortType: "number", title: "A/G", }, "stat:recYdsPerRec": { + template: "Stat", + stats: ["recYdsPerRec"], desc: "Yards Per Reception", sortSequence: ["desc", "asc"], sortType: "number", title: "Y/R", }, "stat:recPerGame": { + template: "Stat", + stats: ["recPerGame"], desc: "Receptions Per Game", sortSequence: ["desc", "asc"], sortType: "number", title: "R/G", }, "stat:recYdsPerGame": { + template: "Stat", + stats: ["recYdsPerGame"], desc: "Receiving Yards Per Game", sortSequence: ["desc", "asc"], sortType: "number", title: "Y/G", }, "stat:recCatchPct": { + template: "Stat", + stats: ["recCatchPct"], desc: "Catch Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "Ctch%", }, "stat:touches": { + template: "Stat", + stats: ["touches"], desc: "Touches (Rushing Attempts And Receptions)", sortSequence: ["desc", "asc"], sortType: "number", title: "Tch", }, "stat:ydsPerTouch": { + template: "Stat", + stats: ["ydsPerTouch"], desc: "Yards Per Touch", sortSequence: ["desc", "asc"], sortType: "number", title: "Y/Tch", }, "stat:ydsFromScrimmage": { + template: "Stat", + stats: ["ydsFromScrimmage"], desc: "Total Rushing and Receiving Yards From Scrimmage", sortSequence: ["desc", "asc"], sortType: "number", title: "YScm", }, "stat:rusRecTD": { + template: "Stat", + stats: ["rusRecTD"], desc: "Total Rushing and Receiving Touchdowns", sortSequence: ["desc", "asc"], sortType: "number", title: "RRTD", }, "stat:allPurposeYds": { + template: "Stat", + stats: ["allPurposeYds"], desc: "All Purpose Yards (Rushing, Receiving, and Kick/Punt/Fumble/Interception Returns)", sortSequence: ["desc", "asc"], sortType: "number", title: "APY", }, "stat:av": { + template: "Stat", + stats: ["av"], desc: "Approximate Value", sortSequence: ["desc", "asc"], sortType: "number", title: "AV", }, "stat:avPerPlayer": { + template: "Stat", + stats: ["avPerPlayer"], desc: "Approximate Value Per Player", sortSequence: ["desc", "asc"], sortType: "number", @@ -1529,396 +2008,528 @@ const sportSpecificCols = bySport<{ title: "G", }, "rating:pss": { + template: "Rating", + ratings: ["pss"], desc: "Passing", sortSequence: ["desc", "asc"], sortType: "number", title: "Pss", }, "rating:wst": { + template: "Rating", + ratings: ["wst"], desc: "Wristshot", sortSequence: ["desc", "asc"], sortType: "number", title: "Wst", }, "rating:sst": { + template: "Rating", + ratings: ["sst"], desc: "Slapshot", sortSequence: ["desc", "asc"], sortType: "number", title: "Sst", }, "rating:stk": { + template: "Rating", + ratings: ["stk"], desc: "Stickhandling", sortSequence: ["desc", "asc"], sortType: "number", title: "Stk", }, "rating:oiq": { + template: "Rating", + ratings: ["oiq"], desc: "Offensive IQ", sortSequence: ["desc", "asc"], sortType: "number", title: "oIQ", }, "rating:chk": { + template: "Rating", + ratings: ["chk"], desc: "Checking", sortSequence: ["desc", "asc"], sortType: "number", title: "Chk", }, "rating:blk": { + template: "Rating", + ratings: ["blk"], desc: "Shot Blocking", sortSequence: ["desc", "asc"], sortType: "number", title: "Blk", }, "rating:fcf": { + template: "Rating", + ratings: ["fcf"], desc: "Faceoffs", sortSequence: ["desc", "asc"], sortType: "number", title: "Fcf", }, "rating:diq": { + template: "Rating", + ratings: ["diq"], desc: "Defensive IQ", sortSequence: ["desc", "asc"], sortType: "number", title: "dIQ", }, "rating:glk": { + template: "Rating", + ratings: ["glk"], desc: "Goalkeeping", sortSequence: ["desc", "asc"], sortType: "number", title: "Glk", }, "rating:ovrC": { + template: "Rating", + ratings: ["ovrC"], desc: "Overall Rating (Center)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrC", }, "rating:ovrW": { + template: "Rating", + ratings: ["ovrW"], desc: "Overall Rating (Winger)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrW", }, "rating:ovrD": { + template: "Rating", + ratings: ["ovrD"], desc: "Overall Rating (Defenseman)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrD", }, "rating:ovrG": { + template: "Rating", + ratings: ["ovrG"], desc: "Overall Rating (Goalie)", sortSequence: ["desc", "asc"], sortType: "number", title: "OvrG", }, "rating:potC": { + template: "Rating", + ratings: ["potC"], desc: "Potential Rating (Center)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotC", }, "rating:potW": { + template: "Rating", + ratings: ["potW"], desc: "Potential Rating (Winger)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotW", }, "rating:potD": { + template: "Rating", + ratings: ["potD"], desc: "Potential Rating (Defenseman)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotD", }, "rating:potG": { + template: "Rating", + ratings: ["potG"], desc: "Potential Rating (Goalie)", sortSequence: ["desc", "asc"], sortType: "number", title: "PotG", }, "stat:gpGoalie": { + template: "Stat", + stats: ["gpGoalie"], desc: "Games Played (Goalie)", sortSequence: ["desc", "asc"], sortType: "number", title: gp, }, "stat:gpSkater": { + template: "Stat", + stats: ["gpSkater"], desc: "Games Played (Skater)", sortSequence: ["desc", "asc"], sortType: "number", title: gp, }, "stat:pm": { + template: "Stat", + stats: ["pm"], desc: "Plus/Minus", sortSequence: ["desc", "asc"], sortType: "number", title: "+/-", }, "stat:pim": { + template: "Stat", + stats: ["pim"], desc: "Penalty Minutes", sortSequence: ["desc", "asc"], sortType: "number", title: "PIM", }, "stat:evG": { + template: "Stat", + stats: ["evG"], desc: "Even Strength Goals", sortSequence: ["desc", "asc"], sortType: "number", title: "evG", }, "stat:ppG": { + template: "Stat", + stats: ["ppG"], desc: "Power Play Goals", sortSequence: ["desc", "asc"], sortType: "number", title: "ppG", }, "stat:shG": { + template: "Stat", + stats: ["shG"], desc: "Short-Handed Goals", sortSequence: ["desc", "asc"], sortType: "number", title: "shG", }, "stat:gwG": { + template: "Stat", + stats: ["gwG"], desc: "Game Winning Goals", sortSequence: ["desc", "asc"], sortType: "number", title: "gwG", }, "stat:evA": { + template: "Stat", + stats: ["evA"], desc: "Even Strength Assists", sortSequence: ["desc", "asc"], sortType: "number", title: "evA", }, "stat:ppA": { + template: "Stat", + stats: ["ppA"], desc: "Power Play Assists", sortSequence: ["desc", "asc"], sortType: "number", title: "ppA", }, "stat:shA": { + template: "Stat", + stats: ["shA"], desc: "Short-Handed Assists", sortSequence: ["desc", "asc"], sortType: "number", title: "shA", }, "stat:gwA": { + template: "Stat", + stats: ["gwA"], desc: "Game Winning Assists", sortSequence: ["desc", "asc"], sortType: "number", title: "gwA", }, "stat:s": { + template: "Stat", + stats: ["s"], desc: "Shots on Goal", sortSequence: ["desc", "asc"], sortType: "number", title: "S", }, "stat:tsa": { + template: "Stat", + stats: ["tsa"], desc: "Total Shots Attempted", sortSequence: ["desc", "asc"], sortType: "number", title: "TSA", }, "stat:fow": { + template: "Stat", + stats: ["fow"], desc: "Faceoff Wins", sortSequence: ["desc", "asc"], sortType: "number", title: "FOW", }, "stat:fol": { + template: "Stat", + stats: ["fol"], desc: "Faceoff Losses", sortSequence: ["desc", "asc"], sortType: "number", title: "FOL", }, "stat:foPct": { + template: "Stat", + stats: ["foPct"], desc: "Faceoff Win Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "FO%", }, "stat:blk": { + template: "Stat", + stats: ["blk"], desc: "Blocks", sortSequence: ["desc", "asc"], sortType: "number", title: "BLK", }, "stat:hit": { + template: "Stat", + stats: ["hit"], desc: "Hits", sortSequence: ["desc", "asc"], sortType: "number", title: "HIT", }, "stat:tk": { + template: "Stat", + stats: ["tk"], desc: "Takeaways", sortSequence: ["desc", "asc"], sortType: "number", title: "TK", }, "stat:gv": { + template: "Stat", + stats: ["gv"], desc: "Giveaways", sortSequence: ["desc", "asc"], sortType: "number", title: "GV", }, "stat:ga": { + template: "Stat", + stats: ["ga"], desc: "Goals Against", sortSequence: ["desc", "asc"], sortType: "number", title: "GA", }, "stat:sv": { + template: "Stat", + stats: ["sv"], desc: "Saves", sortSequence: ["desc", "asc"], sortType: "number", title: "SV", }, "stat:so": { + template: "Stat", + stats: ["so"], desc: "Shutouts", sortSequence: ["desc", "asc"], sortType: "number", title: "SO", }, "stat:g": { + template: "Stat", + stats: ["g"], desc: "Goals", sortSequence: ["desc", "asc"], sortType: "number", title: "G", }, "stat:a": { + template: "Stat", + stats: ["a"], desc: "Assists", sortSequence: ["desc", "asc"], sortType: "number", title: "A", }, "stat:pts": { + template: "Stat", + stats: ["pts"], desc: "Points", sortSequence: ["desc", "asc"], sortType: "number", title: "PTS", }, "stat:sPct": { + template: "Stat", + stats: ["sPct"], desc: "Shooting Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "S%", }, "stat:svPct": { + template: "Stat", + stats: ["svPct"], desc: "Save Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "SV%", }, "stat:sa": { + template: "Stat", + stats: ["sa"], desc: "Shots Against", sortSequence: ["desc", "asc"], sortType: "number", title: "SA", }, "stat:gaa": { + template: "Stat", + stats: ["gaa"], desc: "Goals Against Average", sortSequence: ["desc", "asc"], sortType: "number", title: "GAA", }, "stat:keyStats": { + template: "Stat", + stats: ["keyStats"], desc: "Key Stats", sortSequence: ["desc", "asc"], sortType: "string", title: "Stats", }, "stat:ps": { + template: "Stat", + stats: ["ps"], desc: "Point Shares", sortSequence: ["desc", "asc"], sortType: "number", title: "PS", }, "stat:psPerPlayer": { + template: "Stat", + stats: ["psPerPlayer"], desc: "Point Shares Per Player", sortSequence: ["desc", "asc"], sortType: "number", title: "PS/Player", }, "stat:ops": { + template: "Stat", + stats: ["ops"], desc: "Offensive Point Shares", sortSequence: ["desc", "asc"], sortType: "number", title: "OPS", }, "stat:dps": { + template: "Stat", + stats: ["dps"], desc: "Defensive Point Shares", sortSequence: ["desc", "asc"], sortType: "number", title: "DPS", }, "stat:gps": { + template: "Stat", + stats: ["gps"], desc: "Goalie Point Shares", sortSequence: ["desc", "asc"], sortType: "number", title: "GPS", }, "stat:gc": { + template: "Stat", + stats: ["gc"], desc: "Goals Created", sortSequence: ["desc", "asc"], sortType: "number", title: "GC", }, "stat:amin": { + template: "Stat", + stats: ["amin"], desc: "Average Time On Ice", sortSequence: ["desc", "asc"], sortType: "number", title: "ATOI", }, "stat:ppMin": { + template: "Stat", + stats: ["ppMin"], desc: "Power Play Time On Ice", sortSequence: ["desc", "asc"], sortType: "number", title: "ppTOI", }, "stat:shMin": { + template: "Stat", + stats: ["shMin"], desc: "Short Handed Time On Ice", sortSequence: ["desc", "asc"], sortType: "number", title: "shTOI", }, "stat:ppo": { + template: "Stat", + stats: ["ppo"], desc: "Power Play Opportunities", sortSequence: ["desc", "asc"], sortType: "number", title: "PPO", }, "stat:ppPct": { + template: "Stat", + stats: ["ppPct"], desc: "Power Play Percentage", sortSequence: ["desc", "asc"], sortType: "number", title: "PP%", }, "stat:gRec": { + template: "Stat", + stats: ["gRec"], desc: "Record as primary G", sortSequence: ["desc", "asc"], sortType: "record", title: "Rec", }, "stat:gW": { + template: "Stat", + stats: ["gW"], desc: "Wins as primary G", sortSequence: ["desc", "asc"], sortType: "record", title: "GW", }, "stat:gL": { + template: "Stat", + stats: ["gL"], desc: "Losses as primary G", sortSequence: ["desc", "asc"], sortType: "record", title: "GL", }, "stat:gT": { + template: "Stat", + stats: ["gT"], desc: "Ties as primary G", sortSequence: ["desc", "asc"], sortType: "record", title: "GT", }, "stat:gOTL": { + template: "Stat", + stats: ["gOTL"], desc: "Overtime losses as primary G", sortSequence: ["desc", "asc"], sortType: "record", @@ -1929,736 +2540,182 @@ const sportSpecificCols = bySport<{ const cols: { [key: string]: ColTemp; } = { - "": { - sortSequence: ["desc", "asc"], - }, - "#": {}, - "@": { - desc: "Home or Away", - }, - "#AS": { - desc: "Number of All-Star Selections", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "%": { - desc: "Percentage", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - Active: { - desc: "Number of Players Still Active", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "# Fathers": { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - HoF: { - desc: "Number of Players in the Hall of Fame", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "# Brothers": { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "# Players": { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "# Seasons": { - desc: "Number of Seasons", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "# Sons": { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "# Teams": { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "# Trades": { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - A: { - desc: "Attempted", - sortSequence: ["desc", "asc"], - sortType: "number", - }, Acquired: { desc: "How Player Was Acquired", }, Actions: {}, Age: { sortType: "number", - }, - Amount: { - sortSequence: ["desc", "asc"], - sortType: "currency", + template: "Age", }, "Asking For": { sortSequence: ["desc", "asc"], sortType: "currency", + template: "AskingFor", }, - "Avg Attendance": { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - AvgAge: { - desc: "Average age, weighted by minutes played", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "Age", - }, - Born: { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "Cap Space": { - sortSequence: ["desc", "asc"], - sortType: "currency", - }, - "Captain 1": { - sortType: "name", - }, - "Captain 2": { - sortType: "name", - }, - Cash: { - sortSequence: ["desc", "asc"], - sortType: "currency", - }, - College: {}, - Conference: {}, Contract: { sortSequence: ["desc", "asc"], sortType: "currency", + template: "Contract", }, - Count: { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - Country: {}, - Created: { - desc: "Created Date", - searchType: "string", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - Current: { - desc: "Current Team Rating (With Injuries)", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "Current Contract": { - desc: "Current Contract", - sortSequence: ["desc", "asc"], - sortType: "currency", - title: "Current", - }, - "Projected Contract": { - desc: "Projected Contract", - sortSequence: ["desc", "asc"], - sortType: "currency", - title: "Projected", - }, - Details: {}, - Died: { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - Diff: { + Mood: { + width: "1px", sortSequence: ["desc", "asc"], sortType: "number", + template: "Mood", }, - Difficulty: { - sortSequence: ["desc", "asc"], + Name: { + sortType: "name", + ratings: ["skills"], + template: "Name", }, - Division: {}, - Draft: { - noSearch: true, + Negotiate: { sortSequence: [], + template: "Negotiate", }, - "Draft Picks": { + Release: { sortSequence: [], + template: "Release", }, - "Draft Year": { - sortType: "number", - }, - Drafted: { - sortType: "number", - }, - "Dunk Winner": { - desc: "Slam Dunk Contest Winner", - sortType: "name", - }, - End: { - sortSequence: ["desc", "asc"], - sortType: "number", + Trade: { + sortSequence: [], + template: "Trade", }, Exp: { desc: "Contract Expiration", sortSequence: ["asc", "desc"], sortType: "number", - }, - Experience: { - desc: "Number of Years in the League", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - Finals: { - desc: "Finals Appearances", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "Finals Won": { - desc: "Finals Won", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "Finals Lost": { - desc: "Finals Lost", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - From: {}, - GB: { - desc: "Games Back", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - Games: { - desc: "Number of Games", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - GOAT: { - desc: "GOAT Score", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - Healthy: { - desc: "Team Rating (When Healthy)", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - Height: { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - HOF: { - sortSequence: ["desc", "asc"], - }, - Injury: {}, - L: { - desc: "Losses", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - L10: { - desc: "Last Ten Games", - sortSequence: ["desc", "asc"], - sortType: "lastTen", - }, - Last: { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "Last Played": { - desc: "Last Played Date", - sortSequence: ["desc", "asc"], - searchType: "string", - sortType: "number", - }, - "Last Season": { - desc: "Last Season with Team", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "League Champion": {}, - League: { - desc: "League Name", - }, - Links: { - noSearch: true, - sortSequence: [], - }, - M: { - desc: "Made", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - Mood: { - width: "1px", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - MVP: { - desc: "Most Valuable Player", - sortType: "name", - }, - Name: { - sortType: "name", - render: (p: Player) => ( - - {p.name} - - ), - }, - Negotiate: { - sortSequence: [], - }, - Note: {}, - Opp: { - desc: "Opponent", + template: "Exp", }, Ovr: { desc: "Overall Rating", + ratings: ["dovr", "ovr"], sortSequence: ["desc", "asc"], sortType: "number", - }, - "rating:ovr": { - desc: "Overall Rating", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "Ovr", + template: "Ovr", }, "Ovr Drop": { desc: "Decrease in Overall Rating", sortSequence: ["desc", "asc"], sortType: "number", }, - PA: { - desc: `${isSport("hockey") ? "Goals" : "Points"} Against`, - sortSequence: ["desc", "asc"], - sortType: "number", - title: isSport("hockey") ? "GA" : undefined, - }, - PS: { - desc: `${isSport("hockey") ? "Goals" : "Points"} Scored`, - sortSequence: ["desc", "asc"], - sortType: "number", - title: isSport("hockey") ? "GF" : undefined, - }, - "PA/g": { - desc: `${isSport("hockey") ? "Goals" : "Points"} Against Per Game`, - sortSequence: ["desc", "asc"], - sortType: "number", - title: isSport("hockey") ? "GA" : undefined, - }, - "PS/g": { - desc: `${isSport("hockey") ? "Goals" : "Points"} Scored Per Game`, - sortSequence: ["desc", "asc"], - sortType: "number", - title: isSport("hockey") ? "GF" : undefined, - }, - Payroll: { - sortSequence: ["desc", "asc"], - sortType: "currency", - }, "Peak Ovr": { desc: "Peak Overall Rating", sortSequence: ["desc", "asc"], sortType: "number", }, - Phase: { - desc: "League Season and Phase", - sortSequence: ["desc", "asc"], - }, - Pick: { - desc: "Draft Pick", - sortType: "draftPick", - }, - Pop: { - desc: "Region Population", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - Playoffs: { - desc: "Playoff Appearances", - sortSequence: ["desc", "asc"], - sortType: "number", + PT: { + desc: "Playing Time", + template: "PlayingTime", }, Pos: { desc: "Position", - render: (p: Player) => p.ratings.pos, + ratings: ["pos"], + template: "Pos", }, Pot: { desc: "Potential Rating", + ratings: ["dpot", "pot"], sortSequence: ["desc", "asc"], sortType: "number", - render: (p: Player) => - p.ratings["dpot"] ? ( - - {p.ratings["pot"]} - - ) : ( - p.ratings["pot"] - ), - }, - "rating:pot": { - desc: "Potential Rating", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "Pot", - render: (p: Player) => p.ratings.pot, + template: "Pot", }, "Pot Drop": { desc: "Decrease in Potential Rating", sortSequence: ["desc", "asc"], sortType: "number", }, - Prog: { - desc: "Progression From Previous Season", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "Profit (YTD)": { - sortSequence: ["desc", "asc"], - sortType: "currency", - }, PTS: { desc: "Points", sortSequence: ["desc", "asc"], sortType: "number", }, - "PTS%": { - desc: "Points Divided By Maximum Points", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - Received: { - desc: "Assets Received in Trade", - }, - Record: { - desc: "Record", - sortType: "record", - }, - Relation: {}, - Result: {}, - Retired: { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "Revenue (YTD)": { - sortSequence: ["desc", "asc"], - sortType: "currency", - }, - "Roster Spots": { - desc: "Number of Open Roster Spots", - sortSequence: ["desc", "asc"], - }, - "Rounds Lost": { - desc: "Playoff Rounds Lost", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "Rounds Won": { - desc: "Playoff Rounds Won", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "Runner Up": {}, - Season: { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - Seed: { - desc: "Playoff Seed", - sortType: "number", - }, Skills: {}, - Start: { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - T: { - desc: "Ties", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - "Ticket Price": { - sortSequence: ["desc", "asc"], - sortType: "currency", - }, - Trade: { - desc: "Ties", - noSearch: true, - }, - OTL: { - desc: "Overtime Losses", - sortSequence: ["desc", "asc"], - sortType: "number", - }, Team: {}, - "Three-Point Winner": { - desc: "Three-Point Contest Winner", - sortType: "name", - }, - Titles: { - desc: "Championships Won", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - Type: { - desc: "Type of Game", - }, - TypeInjury: { - desc: "Type of Injury", - title: "Type", - }, - W: { - desc: "Wins", - sortSequence: ["desc", "asc"], - sortType: "number", - }, - Weight: { - sortSequence: ["desc", "asc"], - sortType: "number", - }, - X: { - desc: "Exclude from counter offers", - noSearch: true, - sortSequence: [], - }, - Year: { - sortType: "number", - }, Summary: {}, "rating:endu": { + template: "Rating", + ratings: ["endu"], desc: "Endurance", sortSequence: ["desc", "asc"], sortType: "number", title: "End", }, "rating:hgt": { + template: "Rating", + ratings: ["hgt"], desc: "Height", sortSequence: ["desc", "asc"], sortType: "number", title: "Hgt", }, "rating:spd": { + template: "Rating", + ratings: ["spd"], desc: "Speed", sortSequence: ["desc", "asc"], sortType: "number", title: "Spd", }, "rating:stre": { + template: "Rating", + ratings: ["stre"], desc: "Strength", sortSequence: ["desc", "asc"], sortType: "number", title: "Str", }, "stat:gp": { + template: "Stat", + stats: ["gp"], desc: "Games Played", sortSequence: ["desc", "asc"], sortType: "number", title: gp, }, - "stat:gpPerPlayer": { - desc: "Games Played Per Player", - sortSequence: ["desc", "asc"], - sortType: "number", - title: `${gp}/Player`, - }, "stat:gs": { + template: "Stat", + stats: ["gs"], desc: "Games Started", sortSequence: ["desc", "asc"], sortType: "number", title: "GS", }, "stat:jerseyNumber": { + template: "Stat", + stats: ["jerseyNumber"], desc: "Jersey Number", sortSequence: ["asc", "desc"], sortType: "number", title: "#", }, "stat:min": { + template: "Stat", + stats: ["min"], desc: isSport("hockey") ? "Time On Ice" : "Minutes", sortSequence: ["desc", "asc"], sortType: "number", title: isSport("hockey") ? "TOI" : "MP", }, - "stat:mov": { - desc: "Average Margin of Victory", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "MOV", - }, - "stat:diff": { - desc: "Point Differential", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "Diff", - }, "stat:yearsWithTeam": { + template: "Stat", + stats: ["yearsWithTeam"], desc: "Years With Team", sortSequence: ["desc", "asc"], sortType: "number", title: "YWT", }, - "count:allDefense": { - desc: "All-Defensive Team", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "ADT", - }, - "count:allLeague": { - desc: "All-League Team", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "ALT", - }, - "count:allRookie": { - desc: "All-Rookie Team", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "ART", - }, - "count:allStar": { - desc: "All-Star", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "AS", - }, - "count:allStarMVP": { - desc: "All-Star MVP", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "ASMVP", - }, - "count:bestRecord": { - desc: "Best Record", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "BR", - }, - "count:bestRecordConf": { - desc: "Best Conference Record", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "BRC", - }, - "count:dpoy": { - desc: "Defensive Player of the Year", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "DPOY", - }, - "count:dfoy": { - desc: "Defensive Forward of the Year", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "DFOY", - }, - "count:goy": { - desc: "Goalie of the Year", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "GOY", - }, - "count:mip": { - desc: "Most Improved Player", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "MIP", - }, - "count:mvp": { - desc: "Most Valuable Player", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "MVP", - }, - "count:roy": { - desc: "Rookie of the Year", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "ROY", - }, - "count:smoy": { - desc: "Sixth Man of the Year", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "SMOY", - }, - "count:oroy": { - desc: "Offensive Rookie of the Year", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "OROY", - }, - "count:droy": { - desc: "Defensive Rookie of the Year", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "DROY", - }, - "award:dpoy": { - desc: "Defensive Player of the Year", - sortType: "name", - title: "DPOY", - }, - "award:dfoy": { - desc: "Defensive Forward of the Year", - sortType: "name", - title: "DFOY", - }, - "award:goy": { - desc: "Goalie of the Year", - sortType: "name", - title: "GOY", - }, - "award:finalsMvp": { - desc: `${isSport("hockey") ? "Playoffs" : "Finals"} Most Valuable Player`, - sortType: "name", - title: `${isSport("hockey") ? "Playoffs" : "Finals"} MVP`, - }, - "award:mip": { - desc: "Most Improved Player", - sortType: "name", - title: "MIP", - }, - "award:mvp": { - desc: "Most Valuable Player", - sortType: "name", - title: "MVP", - }, - "award:roy": { - desc: "Rookie of the Year", - sortType: "name", - title: "ROY", - }, - "award:smoy": { - desc: "Sixth Man of the Year", - sortType: "name", - title: "SMOY", - }, - "award:oroy": { - desc: "Offensive Rookie of the Year", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "OROY", - }, - "award:droy": { - desc: "Defensive Rookie of the Year", - sortSequence: ["desc", "asc"], - sortType: "number", - title: "DROY", - }, ...sportSpecificCols, }; +export function getAllCols(): ColTemp[] { + return Object.entries(cols).map(([name, col]) => { + col.title ??= name; + col.key = name; + return col; + }); +} + export default ( titles: string[], overrides: Record> = {}, @@ -2671,6 +2728,7 @@ export default ( return { ...cols[title], title: cols[title].title ?? title, + key: title, ...overrides[title], }; }); diff --git a/src/ui/util/columns/getTemplate.ts b/src/ui/util/columns/getTemplate.ts new file mode 100644 index 0000000000..0f057a13f7 --- /dev/null +++ b/src/ui/util/columns/getTemplate.ts @@ -0,0 +1,8 @@ +import * as templates from "./templates"; +import type { ColTemp } from "./getCols"; +import type { Player } from "../../../common/types"; + +export default function (p: Player, c: ColTemp, vars: object) { + if (!(c.template in templates)) return ""; + return templates[c.template](p, c, vars); +} diff --git a/src/ui/util/columns/templates/Age.tsx b/src/ui/util/columns/templates/Age.tsx new file mode 100644 index 0000000000..1ce5570f05 --- /dev/null +++ b/src/ui/util/columns/templates/Age.tsx @@ -0,0 +1,4 @@ +import { Player } from "../../../../common/types"; +import type { ColTemp } from "../getCols"; + +export default (p: Player, c: ColTemp) => p.age; diff --git a/src/ui/util/columns/templates/AskingFor.tsx b/src/ui/util/columns/templates/AskingFor.tsx new file mode 100644 index 0000000000..563ef8470b --- /dev/null +++ b/src/ui/util/columns/templates/AskingFor.tsx @@ -0,0 +1,6 @@ +import { Player } from "../../../../common/types"; +import { helpers } from "../../index"; +import type { ColTemp } from "../getCols"; + +export default (p: Player, c: ColTemp) => + helpers.formatCurrency(p.mood.user.contractAmount / 1000, "M"); diff --git a/src/ui/util/columns/templates/Contract.tsx b/src/ui/util/columns/templates/Contract.tsx new file mode 100644 index 0000000000..e6a91e9033 --- /dev/null +++ b/src/ui/util/columns/templates/Contract.tsx @@ -0,0 +1,6 @@ +import { Player } from "../../../../common/types"; +import { helpers } from "../../index"; +import type { ColTemp } from "../getCols"; + +export default (p: Player, c: ColTemp) => + `${helpers.formatCurrency(p.contract.amount, "M")} thru ${p.contract.exp}`; diff --git a/src/ui/util/columns/templates/Exp.tsx b/src/ui/util/columns/templates/Exp.tsx new file mode 100644 index 0000000000..f11e639f75 --- /dev/null +++ b/src/ui/util/columns/templates/Exp.tsx @@ -0,0 +1,4 @@ +import type { Player } from "../../../../common/types"; +import type { ColTemp } from "../getCols"; + +export default (p: Player, c: ColTemp) => p.contract.exp.toString(); diff --git a/src/ui/util/columns/templates/Mood.tsx b/src/ui/util/columns/templates/Mood.tsx new file mode 100644 index 0000000000..340326c3e0 --- /dev/null +++ b/src/ui/util/columns/templates/Mood.tsx @@ -0,0 +1,6 @@ +import type { Player } from "../../../../common/types"; +import { dataTableWrappedMood } from "../../../components/Mood"; +import type { ColTemp } from "../getCols"; + +export default (p: Player, c: ColTemp) => + dataTableWrappedMood({ defaultType: "user", maxWidth: true, p })?.value; diff --git a/src/ui/util/columns/templates/Name.tsx b/src/ui/util/columns/templates/Name.tsx new file mode 100644 index 0000000000..d4be25ffd8 --- /dev/null +++ b/src/ui/util/columns/templates/Name.tsx @@ -0,0 +1,15 @@ +import type { Player } from "../../../../common/types"; +import { PlayerNameLabels } from "../../../components"; +import type { ColTemp } from "../getCols"; + +export default (p: Player, c: ColTemp) => ( + + {p.name} + +); diff --git a/src/ui/util/columns/templates/Negotiate.tsx b/src/ui/util/columns/templates/Negotiate.tsx new file mode 100644 index 0000000000..9d5f08cd1d --- /dev/null +++ b/src/ui/util/columns/templates/Negotiate.tsx @@ -0,0 +1,14 @@ +import type { Player } from "../../../../common/types"; +import { NegotiateButtons } from "../../../components"; +import { ColTemp } from "../getCols"; + +export default (p: Player, c: ColTemp, vars: object) => ( + +); diff --git a/src/ui/util/columns/templates/Ovr.tsx b/src/ui/util/columns/templates/Ovr.tsx new file mode 100644 index 0000000000..72338b732a --- /dev/null +++ b/src/ui/util/columns/templates/Ovr.tsx @@ -0,0 +1,12 @@ +import type { Player } from "../../../../common/types"; +import { RatingWithChange } from "../../../components"; +import type { ColTemp } from "../getCols"; + +export default (p: Player, c: ColTemp) => + p.ratings["dovr"] ? ( + + {p.ratings["ovr"]} + + ) : ( + p.ratings["ovr"] + ); diff --git a/src/ui/util/columns/templates/PlayingTime.tsx b/src/ui/util/columns/templates/PlayingTime.tsx new file mode 100644 index 0000000000..7383711005 --- /dev/null +++ b/src/ui/util/columns/templates/PlayingTime.tsx @@ -0,0 +1,7 @@ +import type { Player } from "../../../../common/types"; +import type { ColConfig } from "../../../views/Roster/RosterCustomizeColumns"; +import PlayingTime from "../../../views/Roster/PlayingTime"; + +export default (p: Player, c: ColConfig, vars: object) => ( + +); diff --git a/src/ui/util/columns/templates/Pos.tsx b/src/ui/util/columns/templates/Pos.tsx new file mode 100644 index 0000000000..004554a53b --- /dev/null +++ b/src/ui/util/columns/templates/Pos.tsx @@ -0,0 +1,4 @@ +import { Player } from "../../../../common/types"; +import type { ColTemp } from "../getCols"; + +export default (p: Player, c: ColTemp) => p.ratings.pos; diff --git a/src/ui/util/columns/templates/Pot.tsx b/src/ui/util/columns/templates/Pot.tsx new file mode 100644 index 0000000000..6e56ef0121 --- /dev/null +++ b/src/ui/util/columns/templates/Pot.tsx @@ -0,0 +1,12 @@ +import { Player } from "../../../../common/types"; +import { RatingWithChange } from "../../../components"; +import type { ColTemp } from "../getCols"; + +export default (p: Player, c: ColTemp) => + p.ratings["dpot"] ? ( + + {p.ratings["pot"]} + + ) : ( + p.ratings["pot"] + ); diff --git a/src/ui/util/columns/templates/Rating.tsx b/src/ui/util/columns/templates/Rating.tsx new file mode 100644 index 0000000000..17b1ec0843 --- /dev/null +++ b/src/ui/util/columns/templates/Rating.tsx @@ -0,0 +1,5 @@ +import { Player } from "../../../../common/types"; +import type { ColTemp } from "../getCols"; + +export default (p: Player, c: ColTemp) => + p.ratings[c.title?.split(":").pop()].toString(); diff --git a/src/ui/util/columns/templates/Release.tsx b/src/ui/util/columns/templates/Release.tsx new file mode 100644 index 0000000000..c0ef3a7865 --- /dev/null +++ b/src/ui/util/columns/templates/Release.tsx @@ -0,0 +1,13 @@ +import type { Player } from "../../../../common/types"; +import { NegotiateButtons } from "../../../components"; +import { ColTemp } from "../getCols"; + +export default (p: Player, c: ColTemp, vars: object) => ( + +); diff --git a/src/ui/util/columns/templates/Stat.tsx b/src/ui/util/columns/templates/Stat.tsx new file mode 100644 index 0000000000..ced1262e80 --- /dev/null +++ b/src/ui/util/columns/templates/Stat.tsx @@ -0,0 +1,7 @@ +import { Player } from "../../../../common/types"; +import type { ColTemp } from "../getCols"; + +export default (p: Player, c: ColTemp) => { + const key: string = c.stats[0].toLowerCase(); + return key in p.stats ? p.stats[key].toFixed(1) : c.name; +}; diff --git a/src/ui/util/columns/templates/Trade.tsx b/src/ui/util/columns/templates/Trade.tsx new file mode 100644 index 0000000000..59d4dd53ec --- /dev/null +++ b/src/ui/util/columns/templates/Trade.tsx @@ -0,0 +1,13 @@ +import type { Player } from "../../../../common/types"; +import { NegotiateButtons } from "../../../components"; +import { ColTemp } from "../getCols"; + +export default (p: Player, c: ColTemp, vars: object) => ( + +); diff --git a/src/ui/util/columns/templates/index.tsx b/src/ui/util/columns/templates/index.tsx new file mode 100644 index 0000000000..ff500ff3fd --- /dev/null +++ b/src/ui/util/columns/templates/index.tsx @@ -0,0 +1,15 @@ +export { default as Age } from "./Age"; +export { default as AskingFor } from "./AskingFor"; +export { default as Contract } from "./Contract"; +export { default as Exp } from "./Exp"; +export { default as Mood } from "./Mood"; +export { default as Name } from "./Name"; +export { default as Negotiate } from "./Negotiate"; +export { default as Ovr } from "./Ovr"; +export { default as PlayingTime } from "./PlayingTime"; +export { default as Pos } from "./Pos"; +export { default as Pot } from "./Pot"; +export { default as Rating } from "./Rating"; +export { default as Release } from "./Release"; +export { default as Stat } from "./Stat"; +export { default as Trade } from "./Trade"; diff --git a/src/ui/views/FreeAgents.tsx b/src/ui/views/FreeAgents.tsx index 9674c47514..56c56d3191 100644 --- a/src/ui/views/FreeAgents.tsx +++ b/src/ui/views/FreeAgents.tsx @@ -4,16 +4,14 @@ import { PHASE } from "../../common"; import { DataTable, MoreLinks, - NegotiateButtons, - PlayerNameLabels, RosterComposition, RosterSalarySummary, } from "../components"; import useTitleBar from "../hooks/useTitleBar"; -import { confirm, helpers, toWorker, useLocalShallow } from "../util"; +import { confirm, toWorker, useLocalShallow } from "../util"; import type { View } from "../../common/types"; -import { dataTableWrappedMood } from "../components/Mood"; -import getCols from "../util/getCols"; +import getTemplate from "../util/columns/getTemplate"; +import RosterCustomizeColumns from "./Roster/RosterCustomizeColumns"; const FreeAgents = ({ capSpace, @@ -27,15 +25,18 @@ const FreeAgents = ({ spectator, phase, players, - stats, + config, userPlayers, }: View<"freeAgents">) => { const [addFilters, setAddFilters] = useState< (string | undefined)[] | undefined >(); + const cols = config.columns; + + const [showColumnsModal, setShowColumnsModal] = useState(false); const showAfforablePlayers = useCallback(() => { - const newAddFilters: (string | undefined)[] = new Array(9 + stats.length); + const newAddFilters: (string | undefined)[] = new Array(9); if (capSpace * 1000 > minContract && !challengeNoFreeAgents) { newAddFilters[newAddFilters.length - 3] = `<${capSpace}`; } else { @@ -50,7 +51,7 @@ const FreeAgents = ({ setTimeout(() => { setAddFilters(undefined); }, 0); - }, [capSpace, challengeNoFreeAgents, minContract, stats]); + }, [capSpace, challengeNoFreeAgents, minContract]); useTitleBar({ title: "Free Agents" }); @@ -75,53 +76,17 @@ const FreeAgents = ({ ); } - const cols = getCols([ - "Name", - "Pos", - "Age", - "Ovr", - "Pot", - ...stats.map(stat => `stat:${stat}`), - "Mood", - "Asking For", - "Exp", - "Negotiate", - ]); - console.log(cols[0]); + const vars = { + capSpace, + gameSimInProgress, + minContract, + spectator, + }; const rows = players.map(p => { return { key: p.pid, - data: [ - cols[0].render(p), - p.ratings.pos, - p.age, - !challengeNoRatings ? p.ratings.ovr : null, - !challengeNoRatings ? p.ratings.pot : null, - ...stats.map(stat => helpers.roundStat(p.stats[stat], stat)), - dataTableWrappedMood({ - defaultType: "user", - maxWidth: true, - p, - }), - helpers.formatCurrency(p.mood.user.contractAmount / 1000, "M"), - p.contract.exp, - { - value: ( - // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/20544 - // @ts-ignore - - ), - searchValue: p.mood.user.willing ? "Negotiate Sign" : "Refuses!", - }, - ], + data: cols.map(col => getTemplate(p, col, vars)), }; }); @@ -185,6 +150,19 @@ const FreeAgents = ({

) : null} + + + location.reload()} + /> + void; }) => { @@ -56,36 +58,20 @@ const Container = SortableContainer( ); const RosterCustomizeColumns = ({ - allStats, - allRatings, onHide, - cols, + config, show, - table, }: { - allStats: string[]; - allRatings: string[]; + config: TableConfig; onHide: () => void; - cols: string[]; show: boolean; - table: string; }) => { - let i = 1; - const initialColumns: Col[] = [ - ...allRatings.map(col => ({ - title: col, - key: i++, - hidden: !cols.includes(col), - type: "ratings", - })), - ...allStats.map(col => ({ - title: col, - key: i++, - hidden: !cols.includes(col), - type: "stats", - })), - ]; - const [columns, setColumns] = useState(initialColumns); + const initialColumns: ColTemp[] = getAllCols().map(c => ({ + title: c.title, + hidden: !config.columns.some(col => col.key === c.key), + key: c.key, + })); + const [columns, setColumns] = useState(initialColumns); const [isDragged, setIsDragged] = useState(false); const onSortEnd = ({ oldIndex, newIndex }) => { @@ -107,7 +93,7 @@ const RosterCustomizeColumns = ({ const hide = async () => { await toWorker("main", "updateColumns", { columns: columns, - key: table, + key: config.tableName, }); onHide(); }; diff --git a/src/ui/views/Roster/index.tsx b/src/ui/views/Roster/index.tsx index 6b76531943..9e10b90f78 100644 --- a/src/ui/views/Roster/index.tsx +++ b/src/ui/views/Roster/index.tsx @@ -17,8 +17,10 @@ import useTitleBar from "../../hooks/useTitleBar"; import { confirm, getCols, helpers, logEvent, toWorker } from "../../util"; import PlayingTime, { ptStyles } from "./PlayingTime"; import TopStuff from "./TopStuff"; -import type { Phase, View } from "../../../common/types"; +import type { Phase, Player, View } from "../../../common/types"; import RosterCustomizeColumns from "./RosterCustomizeColumns"; +import { ColTemp } from "../../util/columns/getCols"; +import getTemplate from "../../util/columns/getTemplate"; // If a player was just drafted and the regular season hasn't started, then he can be released without paying anything const justDrafted = ( @@ -91,16 +93,11 @@ const Roster = ({ showRelease, showTradeFor, showTradingBlock, - stats, - ratings, - allStats, - allRatings, t, tid, userTid, - columns, + config, }: View<"roster">) => { - console.log(columns, stats); const [sortedPids, setSortedPids] = useState(undefined); const [prevPlayers, setPrevPlayers] = useState(players); const [showColumnsModal, setShowColumnsModal] = useState(false); @@ -135,10 +132,19 @@ const Roster = ({ const profit = t.seasonAttrs !== undefined ? t.seasonAttrs.profit : 0; - const ratingCols = getCols(ratings.map(rating => `rating:${rating}`)); - const statCols = getCols(stats.map(stat => `stat:${stat}`)); - - const showMood = season === currentSeason; + const cols: ColTemp[] = config.columns; + const vars = { + userTid, + showTradeFor, + handleTrade: (p: Player) => { + if (showTradeFor) { + toWorker("actions", "tradeFor", { pid: p.pid }); + } else { + toWorker("actions", "addToTradingBlock", p.pid); + } + }, + handleRelease: (p: Player) => handleRelease(p, phase, season), + }; return ( <> @@ -179,10 +185,7 @@ const Roster = ({ location.reload()} /> @@ -228,199 +231,16 @@ const Roster = ({ }} cols={() => ( <> - Name - Age - {ratingCols.map(({ desc, title }) => ( - - {title} - - ))} - {season === currentSeason ? Contract : null} - YWT - - {statCols.map(({ desc, title }) => ( + {cols.map(({ desc, title }) => ( {title} ))} - {editable ? ( - - PT{" "} - -

- Your coach will divide up playing time based on ability and - stamina. If you want to influence his judgement, your - options are: -

-

- 0 No Playing Time -
- - Less Playing Time -
- -     Let Coach Decide - -
- + More Playing Time -
- - ++ Even More Playing Time - -

-
- - ) : null} - {showMood ? ( - - Mood{" "} - - See{" "} - - the manual - {" "} - for more info about player mood. - - - ) : null} - {showRelease ? ( - - Release{" "} - -

- To free up a roster spot, you can release a player from your - team. You will still have to pay his salary (and have it - count against the salary cap) until his contract expires - (you can view your released players' contracts in your{" "} - - Team Finances - - ). -

- {!hardCap ? ( -

- However, if you just drafted a player and the regular - season has not started yet, his contract is not guaranteed - and you can release him for free. -

- ) : null} -
- - ) : null} - {showTradeFor || showTradingBlock ? Trade : null} - Acquired )} - row={({ value: p }) => { - const showRatings = !challengeNoRatings || p.tid === PLAYER.RETIRED; - return ( - <> - - - {p.name} - - - {p.age} - {showRatings - ? ratings.map(rating => - p.ratings["d" + rating] ? ( - - - {p.ratings[rating]} - - - ) : ( - {p.ratings[rating]} - ), - ) - : null} - {season === currentSeason ? ( - - {helpers.formatCurrency(p.contract.amount, "M")} thru{" "} - {p.contract.exp} - - ) : null} - {playoffs === "playoffs" ? null : p.stats.yearsWithTeam} - - - - - - {stats.map(stat => ( - {helpers.roundStat(p.stats[stat], stat)} - ))} - {editable ? ( - - - - ) : null} - {showMood ? ( - - - - ) : null} - {showRelease ? ( - - - - ) : null} - {showTradeFor || showTradingBlock ? ( - - - - ) : null} - - - - - ); - }} + row={({ value: p }) => + cols.map(col => {getTemplate(p, col, vars)}) + } /> ); diff --git a/src/worker/api/index.ts b/src/worker/api/index.ts index 213670a75b..5fbddaf8f0 100644 --- a/src/worker/api/index.ts +++ b/src/worker/api/index.ts @@ -2928,6 +2928,7 @@ const updateMultiTeamMode = async (gameAttributes: { }; const updateColumns = async (data: { key: string; columns: object[] }) => { + console.log(data); await idb.meta.put("tables", data.columns, data.key); }; diff --git a/src/worker/views/freeAgents.ts b/src/worker/views/freeAgents.ts index 71af630a0e..8272a359c4 100644 --- a/src/worker/views/freeAgents.ts +++ b/src/worker/views/freeAgents.ts @@ -3,6 +3,7 @@ import type { Player } from "../../common/types"; import { player, team } from "../core"; import { idb } from "../db"; import { g } from "../util"; +import { TableConfig } from "../../ui/util/TableConfig"; export const addMood = async (players: Player[]) => { const moods: Awaited>[] = []; @@ -27,11 +28,19 @@ const updateFreeAgents = async () => { await idb.cache.players.indexGetAll("playersByTid", PLAYER.FREE_AGENT), ); const capSpace = (g.get("salaryCap") - payroll) / 1000; - const stats = bySport({ - basketball: ["min", "pts", "trb", "ast", "per"], - football: ["gp", "keyStats", "av"], - hockey: ["gp", "keyStats", "ops", "dps", "ps"], - }); + + const config: TableConfig = new TableConfig("freeAgents", [ + "Name", + "Pos", + "Age", + "Ovr", + "Pot", + "Mood", + "Asking For", + "Exp", + "Negotiate", + ]); + await config.load(); const players = await idb.getCopies.playersPlus(playersAll, { attrs: [ @@ -43,9 +52,10 @@ const updateFreeAgents = async () => { "watch", "jerseyNumber", "mood", + "pos", ], - ratings: ["ovr", "pot", "skills", "pos"], - stats, + ratings: config.ratingsNeeded, + stats: config.statsNeeded, season: g.get("season"), showNoStats: true, showRookies: true, @@ -73,8 +83,8 @@ const updateFreeAgents = async () => { numRosterSpots: g.get("maxRosterSize") - userPlayers.length, spectator: g.get("spectator"), phase: g.get("phase"), + config, players, - stats, userPlayers, }; }; diff --git a/src/worker/views/roster.ts b/src/worker/views/roster.ts index 4584dcfc12..b8396a7a11 100644 --- a/src/worker/views/roster.ts +++ b/src/worker/views/roster.ts @@ -16,6 +16,7 @@ import type { } from "../../common/types"; import { addMood } from "./freeAgents"; import { union } from "lodash-es"; +import { TableConfig } from "../../ui/util/TableConfig"; const footballScore = (p: { ratings: { @@ -111,24 +112,40 @@ const updateRoster = async ( "value", ]; // tid and draft are used for checking if a player can be released without paying his salary - const columns = await idb.meta.get("tables", "roster"); + const stats = bySport({ + basketball: [ + "stat:gp", + "stat:min", + "stat:pts", + "stat:trb", + "stat:ast", + "stat:per", + ], + football: ["stat:gp", "stat:keyStats", "stat:av"], + hockey: [ + "stat:gp", + "stat:amin", + "stat:keyStats", + "stat:ops", + "stat:dps", + "stat:ps", + ], + }); - let ratings, stats; - if (columns) { - ratings = columns - .filter(c => !c.hidden && c.type == "ratings") - .map(c => c.title); - stats = columns - .filter(c => !c.hidden && c.type == "stats") - .map(c => c.title); - } else { - stats = bySport({ - basketball: ["gp", "min", "pts", "trb", "ast", "per"], - football: ["gp", "keyStats", "av"], - hockey: ["gp", "amin", "keyStats", "ops", "dps", "ps"], - }); - ratings = ["ovr", "pot", "dovr", "dpot", "skills", "pos", "ovrs"]; - } + const config: TableConfig = new TableConfig("roster", [ + "Name", + "Pos", + "Age", + "Ovr", + "Pot", + "Contract", + ...stats, + "PT", + "Mood", + "Trade", + "Release", + ]); + await config.load(); let players: any[]; let payroll: number | undefined; @@ -156,10 +173,10 @@ const updateRoster = async ( players = await idb.getCopies.playersPlus(playersAll, { attrs, - ratings, playoffs: inputs.playoffs === "playoffs", regularSeason: inputs.playoffs !== "playoffs", - stats: [...stats, "jerseyNumber", "yearsWithTeam"], + ratings: config.ratingsNeeded, + stats: config.statsNeeded, season: inputs.season, tid: inputs.tid, showNoStats: true, @@ -201,10 +218,10 @@ const updateRoster = async ( }); players = await idb.getCopies.playersPlus(playersAll, { attrs, - ratings, + ratings: config.ratingsNeeded, + stats: config.statsNeeded, playoffs: inputs.playoffs === "playoffs", regularSeason: inputs.playoffs !== "playoffs", - stats: stats2, season: inputs.season, tid: inputs.tid, fuzz: true, @@ -233,11 +250,6 @@ const updateRoster = async ( }; t2.seasonAttrs.avgAge = t2.seasonAttrs.avgAge ?? team.avgAge(players); - const allRatings = ["ovr", "pot", "pos", ...RATINGS]; - const allStats = union( - PLAYER_STATS_TABLES.regular.stats, - PLAYER_STATS_TABLES.advanced.stats, - ); return { abbrev: inputs.abbrev, budget: g.get("budget"), @@ -269,11 +281,7 @@ const updateRoster = async ( inputs.season === g.get("season") && inputs.tid === g.get("userTid") && !g.get("spectator"), - stats, - ratings, - allStats, - allRatings, - columns, + config, t: t2, tid: inputs.tid, userTid: g.get("userTid"), From 53433f130cce5dca26e346792d6d7d76e483a29b Mon Sep 17 00:00:00 2001 From: Vac1911 Date: Mon, 29 Nov 2021 16:10:54 -0500 Subject: [PATCH 04/43] Better Column Labels --- src/ui/util/columns/getCols.ts | 18 +++++++++--------- src/ui/views/Roster/RosterCustomizeColumns.tsx | 8 +++++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ui/util/columns/getCols.ts b/src/ui/util/columns/getCols.ts index a8a4d451ea..785e900891 100644 --- a/src/ui/util/columns/getCols.ts +++ b/src/ui/util/columns/getCols.ts @@ -537,76 +537,76 @@ const sportSpecificCols = bySport<{ title: "VORP", }, "stat:fgAtRim": { + title: "fgAtRim", template: "Stat", stats: ["fgAtRim"], desc: "At Rim Made", sortSequence: ["desc", "asc"], sortType: "number", - title: "M", }, "stat:fgaAtRim": { + title: "fgaAtRim", template: "Stat", stats: ["fgaAtRim"], desc: "At Rim Attempted", sortSequence: ["desc", "asc"], sortType: "number", - title: "A", }, "stat:fgpAtRim": { + title: "fgpAtRim", template: "Stat", stats: ["fgpAtRim"], desc: "At Rim Percentage", sortSequence: ["desc", "asc"], sortType: "number", - title: "%", }, "stat:fgLowPost": { + title: "fgLowPost", template: "Stat", stats: ["fgLowPost"], desc: "Low Post Made", sortSequence: ["desc", "asc"], sortType: "number", - title: "M", }, "stat:fgaLowPost": { + title: "fgaLowPost", template: "Stat", stats: ["fgaLowPost"], desc: "Low Post Attempted", sortSequence: ["desc", "asc"], sortType: "number", - title: "A", }, "stat:fgpLowPost": { + title: "fgpLowPost", template: "Stat", stats: ["fgpLowPost"], desc: "Low Post Percentage", sortSequence: ["desc", "asc"], sortType: "number", - title: "%", }, "stat:fgMidRange": { + title: "fgMidRange", template: "Stat", stats: ["fgMidRange"], desc: "Mid Range Made", sortSequence: ["desc", "asc"], sortType: "number", - title: "M", }, "stat:fgaMidRange": { + title: "fgaMidRange", template: "Stat", stats: ["fgaMidRange"], desc: "Mid Range Attempted", sortSequence: ["desc", "asc"], sortType: "number", - title: "A", }, "stat:fgpMidRange": { + title: "fgpMidRange", template: "Stat", stats: ["fgpMidRange"], desc: "Mid Range Percentage", sortSequence: ["desc", "asc"], sortType: "number", - title: "%", }, "stat:dd": { template: "Stat", diff --git a/src/ui/views/Roster/RosterCustomizeColumns.tsx b/src/ui/views/Roster/RosterCustomizeColumns.tsx index e62b9cff8e..91aa9deeab 100644 --- a/src/ui/views/Roster/RosterCustomizeColumns.tsx +++ b/src/ui/views/Roster/RosterCustomizeColumns.tsx @@ -10,6 +10,7 @@ import type { Col } from "../../components/DataTable"; export type ColConfig = { title: string; + desc?: string; hidden: boolean; key: number; }; @@ -24,8 +25,6 @@ const Item = SortableElement( hidden: boolean; onToggleHidden: () => void; }) => { - const title = col.title; - return (
- +
); }, @@ -68,6 +69,7 @@ const RosterCustomizeColumns = ({ }) => { const initialColumns: ColTemp[] = getAllCols().map(c => ({ title: c.title, + desc: c.desc, hidden: !config.columns.some(col => col.key === c.key), key: c.key, })); From 47c8f66b04d5c91f6280a412258f643be7ae83ed Mon Sep 17 00:00:00 2001 From: Vac1911 Date: Tue, 30 Nov 2021 17:00:03 -0500 Subject: [PATCH 05/43] sortable columns prototype --- src/ui/components/DataTable/Header.tsx | 115 +++++++++++++++++- src/ui/components/DataTable/index.tsx | 8 ++ src/ui/util/columns/getCols.ts | 18 +-- .../views/Roster/RosterCustomizeColumns.tsx | 2 +- 4 files changed, 132 insertions(+), 11 deletions(-) diff --git a/src/ui/components/DataTable/Header.tsx b/src/ui/components/DataTable/Header.tsx index 3eb942331d..e35b997193 100644 --- a/src/ui/components/DataTable/Header.tsx +++ b/src/ui/components/DataTable/Header.tsx @@ -1,7 +1,14 @@ import classNames from "classnames"; import PropTypes from "prop-types"; -import type { SyntheticEvent, MouseEvent } from "react"; +import type { MouseEvent, SyntheticEvent } from "react"; +import { ReactNode, useCallback, useState } from "react"; import type { Col, SortBy, SuperCol } from "."; +import { + arrayMove, + SortableContainer, + SortableElement, + SortableHandle, +} from "react-sortable-hoc"; const FilterHeader = ({ colOrder, @@ -109,6 +116,79 @@ const SuperCols = ({ ); }; +const SortableColumnHandle = SortableHandle( + (props: { isDragged: boolean; selected: boolean; children: ReactNode }) => { + return ( + + {props.children} + + ); + }, +); +SortableColumnHandle.propTypes = { + isDragged: PropTypes.bool.isRequired, +}; + +const SortableColumn = SortableElement( + (props: { + isDragged: boolean; + selected: boolean; + col: Col; + sortBy: SortBy | undefined; + }) => { + return ( + +
+
{props.col.title}
+
+
+ + ); + }, +); +const SortableColumnHeader = SortableContainer( + (props: { + indexSelected: number | undefined; + isDragged: boolean; + cols: Col[]; + sortBys: SortBy[]; + }) => { + return ( + + {props.cols.map((col, index) => ( + sort[0] === index)} + /> + ))} + + ); + }, +); const Header = ({ colOrder, @@ -116,6 +196,7 @@ const Header = ({ enableFilters, filters, handleColClick, + handleReorder, handleFilterUpdate, sortBys, superCols, @@ -127,15 +208,47 @@ const Header = ({ enableFilters: boolean; filters: string[]; handleColClick: (b: MouseEvent, a: number) => void; + handleReorder: (nextCols: Col[]) => void; handleFilterUpdate: (b: SyntheticEvent, a: number) => void; sortBys: SortBy[]; superCols?: SuperCol[]; }) => { + const [isDragged, setIsDragged] = useState(false); + const [indexSelected, setIndexSelected] = useState( + undefined, + ); + + const onSortStart = useCallback(({ index }) => { + setIsDragged(true); + setIndexSelected(index); + }, []); + + const onSortEnd = useCallback( + ({ oldIndex, newIndex }) => { + setIsDragged(false); + setIndexSelected(undefined); + + handleReorder(arrayMove(colOrder, oldIndex, newIndex)); + }, + [handleReorder, cols], + ); + return ( {superCols ? ( ) : null} + {colOrder.map(({ colIndex }) => { const { diff --git a/src/ui/components/DataTable/index.tsx b/src/ui/components/DataTable/index.tsx index 7e720583d1..8b667283e8 100644 --- a/src/ui/components/DataTable/index.tsx +++ b/src/ui/components/DataTable/index.tsx @@ -213,6 +213,13 @@ const DataTable = ({ }); }; + const handleReorder = (nextCols: Col[]) => { + console.log(nextCols); + setStatePartial({ + colOrder: nextCols, + }); + }; + const handleColClick = (event: MouseEvent, i: number) => { const col = cols[i]; // Ignore click on unsortable column @@ -520,6 +527,7 @@ const DataTable = ({ cols={cols} enableFilters={state.enableFilters} filters={state.filters} + handleReorder={handleReorder} handleColClick={handleColClick} handleFilterUpdate={handleFilterUpdate} sortBys={state.sortBys} diff --git a/src/ui/util/columns/getCols.ts b/src/ui/util/columns/getCols.ts index 785e900891..3959faea87 100644 --- a/src/ui/util/columns/getCols.ts +++ b/src/ui/util/columns/getCols.ts @@ -537,7 +537,7 @@ const sportSpecificCols = bySport<{ title: "VORP", }, "stat:fgAtRim": { - title: "fgAtRim", + title: "FG Rim", template: "Stat", stats: ["fgAtRim"], desc: "At Rim Made", @@ -545,7 +545,7 @@ const sportSpecificCols = bySport<{ sortType: "number", }, "stat:fgaAtRim": { - title: "fgaAtRim", + title: "FGA Rim", template: "Stat", stats: ["fgaAtRim"], desc: "At Rim Attempted", @@ -553,7 +553,7 @@ const sportSpecificCols = bySport<{ sortType: "number", }, "stat:fgpAtRim": { - title: "fgpAtRim", + title: "FG% Rim", template: "Stat", stats: ["fgpAtRim"], desc: "At Rim Percentage", @@ -561,7 +561,7 @@ const sportSpecificCols = bySport<{ sortType: "number", }, "stat:fgLowPost": { - title: "fgLowPost", + title: "FG Post", template: "Stat", stats: ["fgLowPost"], desc: "Low Post Made", @@ -569,7 +569,7 @@ const sportSpecificCols = bySport<{ sortType: "number", }, "stat:fgaLowPost": { - title: "fgaLowPost", + title: "FGA Post", template: "Stat", stats: ["fgaLowPost"], desc: "Low Post Attempted", @@ -577,7 +577,7 @@ const sportSpecificCols = bySport<{ sortType: "number", }, "stat:fgpLowPost": { - title: "fgpLowPost", + title: "FG% Post", template: "Stat", stats: ["fgpLowPost"], desc: "Low Post Percentage", @@ -585,7 +585,7 @@ const sportSpecificCols = bySport<{ sortType: "number", }, "stat:fgMidRange": { - title: "fgMidRange", + title: "FG Mid", template: "Stat", stats: ["fgMidRange"], desc: "Mid Range Made", @@ -593,7 +593,7 @@ const sportSpecificCols = bySport<{ sortType: "number", }, "stat:fgaMidRange": { - title: "fgaMidRange", + title: "FGA Mid", template: "Stat", stats: ["fgaMidRange"], desc: "Mid Range Attempted", @@ -601,7 +601,7 @@ const sportSpecificCols = bySport<{ sortType: "number", }, "stat:fgpMidRange": { - title: "fgpMidRange", + title: "FG% Mid", template: "Stat", stats: ["fgpMidRange"], desc: "Mid Range Percentage", diff --git a/src/ui/views/Roster/RosterCustomizeColumns.tsx b/src/ui/views/Roster/RosterCustomizeColumns.tsx index 91aa9deeab..1ea7e630b0 100644 --- a/src/ui/views/Roster/RosterCustomizeColumns.tsx +++ b/src/ui/views/Roster/RosterCustomizeColumns.tsx @@ -34,7 +34,7 @@ const Item = SortableElement( onChange={onToggleHidden} />
); From 6b825386c9ebcc81ba674e3308b162fe397bcc9d Mon Sep 17 00:00:00 2001 From: Vac1911 Date: Wed, 1 Dec 2021 14:10:34 -0500 Subject: [PATCH 06/43] Proper column sorting --- public/css/dark.scss | 3 +- public/css/light.scss | 5 +- src/ui/components/DataTable/Header.tsx | 133 +++++++++--------- src/ui/components/DataTable/index.tsx | 119 +++++++++------- .../DataTable/loadStateFromCache.ts | 15 +- src/ui/util/columns/getCols.ts | 12 +- src/ui/views/FreeAgents.tsx | 2 +- 7 files changed, 159 insertions(+), 130 deletions(-) diff --git a/public/css/dark.scss b/public/css/dark.scss index 6cef6bd1a1..36e1a26cc1 100644 --- a/public/css/dark.scss +++ b/public/css/dark.scss @@ -324,7 +324,6 @@ input[type="checkbox"][disabled]:not(.custom-control-input) { } } -.sorting_asc, -.sorting_desc { +.sorted { background-color: #5f583c !important; } diff --git a/public/css/light.scss b/public/css/light.scss index b0bec49c97..7708c22693 100644 --- a/public/css/light.scss +++ b/public/css/light.scss @@ -1299,7 +1299,6 @@ code { transition: none !important; } -.sorting_asc, -.sorting_desc { - background-color: #ffeeba !important; +.sorted { + background-color: #5f583c !important; } diff --git a/src/ui/components/DataTable/Header.tsx b/src/ui/components/DataTable/Header.tsx index 6821167258..5cf1061556 100644 --- a/src/ui/components/DataTable/Header.tsx +++ b/src/ui/components/DataTable/Header.tsx @@ -2,7 +2,7 @@ import classNames from "classnames"; import PropTypes from "prop-types"; import type { MouseEvent, SyntheticEvent } from "react"; import { ReactNode, useCallback, useState } from "react"; -import type { Col, SortBy, SuperCol } from "."; +import type { Col, Filter, SortBy, SuperCol } from "."; import { arrayMove, SortableContainer, @@ -11,33 +11,26 @@ import { } from "react-sortable-hoc"; const FilterHeader = ({ - colOrder, cols, filters, handleFilterUpdate, }: { - colOrder: { - colIndex: number; - hidden?: boolean; - }[]; cols: Col[]; - filters: string[]; - handleFilterUpdate: (b: SyntheticEvent, a: number) => void; + filters: Filter[]; + handleFilterUpdate: (b: SyntheticEvent, a: string) => void; }) => { return ( - {colOrder.map(({ colIndex }) => { - const col = cols[colIndex]; - - const filter = filters[colIndex] ?? ""; + {cols.map((col, colIndex) => { + const filter = filters.find(f => col.key === f.col); return ( {col.noSearch ? null : ( handleFilterUpdate(event, colIndex)} + onChange={event => handleFilterUpdate(event, col.key ?? "")} type="text" - value={filter} + value={filter ? filter.value : ""} /> )} @@ -145,17 +138,26 @@ const SortableColumn = SortableElement( selected: boolean; col: Col; sortBy: SortBy | undefined; + colIndex: number; + handleColClick: (b: MouseEvent, a: number) => void; }) => { return ( - +
{props.col.title}
{ + props.handleColClick(event, props.colIndex); + }} style={{ width: "19px" }} - className={classNames(props.col.classNames, { + className={classNames({ sorting: !props.sortBy && !props.isDragged, sorting_asc: props.sortBy && props.sortBy[1] === "asc", sorting_desc: props.sortBy && props.sortBy[1] === "desc", @@ -172,6 +174,7 @@ const SortableColumnHeader = SortableContainer( isDragged: boolean; cols: Col[]; sortBys: SortBy[]; + handleColClick: (b: MouseEvent, a: number) => void; }) => { return ( @@ -181,7 +184,9 @@ const SortableColumnHeader = SortableContainer( isDragged={props.isDragged} selected={props.indexSelected === index} index={index} + colIndex={index} col={col} + handleColClick={props.handleColClick} sortBy={props.sortBys.find((sort: SortBy) => sort[0] === index)} /> ))} @@ -191,7 +196,6 @@ const SortableColumnHeader = SortableContainer( ); const Header = ({ - colOrder, cols, enableFilters, filters, @@ -201,15 +205,12 @@ const Header = ({ sortBys, superCols, }: { - colOrder: { - colIndex: number; - }[]; cols: Col[]; enableFilters: boolean; - filters: string[]; + filters: Filter[]; handleColClick: (b: MouseEvent, a: number) => void; - handleReorder: (nextCols: Col[]) => void; - handleFilterUpdate: (b: SyntheticEvent, a: number) => void; + handleReorder: (oldIndex: number, newIndex: number) => void; + handleFilterUpdate: (b: SyntheticEvent, a: string) => void; sortBys: SortBy[]; superCols?: SuperCol[]; }) => { @@ -218,6 +219,8 @@ const Header = ({ undefined, ); + console.log(filters); + const onSortStart = useCallback(({ index }) => { setIsDragged(true); setIndexSelected(index); @@ -228,16 +231,16 @@ const Header = ({ setIsDragged(false); setIndexSelected(undefined); - handleReorder(arrayMove(colOrder, oldIndex, newIndex)); + handleReorder(oldIndex, newIndex); }, [handleReorder, cols], ); return ( - {superCols ? ( - - ) : null} + {/*{superCols ? (*/} + {/* */} + {/*) : null}*/} - - {colOrder.map(({ colIndex }) => { - const { - classNames: colClassNames, - desc, - sortSequence, - title, - width, - } = cols[colIndex]; + {/**/} + {/* {colOrder.map(({ colIndex }) => {*/} + {/* const {*/} + {/* classNames: colClassNames,*/} + {/* desc,*/} + {/* sortSequence,*/} + {/* title,*/} + {/* width,*/} + {/* } = cols[colIndex];*/} - let className; - if (sortSequence && sortSequence.length === 0) { - className = null; - } else { - className = "sorting"; + {/* let className;*/} + {/* if (sortSequence && sortSequence.length === 0) {*/} + {/* className = null;*/} + {/* } else {*/} + {/* className = "sorting";*/} - for (const sortBy of sortBys) { - if (sortBy[0] === colIndex) { - className = - sortBy[1] === "asc" ? "sorting_asc" : "sorting_desc"; - break; - } - } - } + {/* for (const sortBy of sortBys) {*/} + {/* if (sortBy[0] === colIndex) {*/} + {/* className =*/} + {/* sortBy[1] === "asc" ? "sorting_asc" : "sorting_desc";*/} + {/* break;*/} + {/* }*/} + {/* }*/} + {/* }*/} - return ( - { - handleColClick(event, colIndex); - }} - title={desc} - style={{ width }} - > - {title} - - ); - })} - + {/* return (*/} + {/* {*/} + {/* handleColClick(event, colIndex);*/} + {/* }}*/} + {/* title={desc}*/} + {/* style={{ width }}*/} + {/* >*/} + {/* {title}*/} + {/* */} + {/* );*/} + {/* })}*/} + {/**/} {enableFilters ? ( { - const [state, setState] = useState(() => - loadStateFromCache({ + let i: number = 1; + cols = cols.map(col => ({ + ...col, + key: col.key ?? `col${i++}`, + })); + + const [state, setState] = useState(() => ({ + ...loadStateFromCache({ cols, defaultSort, - disableSettingsCache, + disableSettingsCache: true, name, }), - ); + rows, + })); const setStatePartial = useCallback((newState: Partial) => { setState(state2 => ({ @@ -134,25 +150,26 @@ const DataTable = ({ const processRows = () => { const filterFunctions = state.enableFilters - ? state.filters.map((filter, i) => - createFilterFunction( - filter, - cols[i] ? cols[i].sortType : undefined, - cols[i] ? cols[i].searchType : undefined, - ), - ) + ? state.cols.map(col => { + const filter = state.filters.find(f => col.key === f.col); + return createFilterFunction( + filter?.value || "", + col.sortType, + col.searchType, + ); + }) : []; const skipFiltering = state.searchText === "" && !state.enableFilters; const searchText = state.searchText.toLowerCase(); const rowsFiltered = skipFiltering - ? rows - : rows.filter(row => { + ? state.rows + : state.rows.filter(row => { // Search if (state.searchText !== "") { let found = false; for (let i = 0; i < row.data.length; i++) { - if (cols[i].noSearch) { + if (state.cols[i].noSearch) { continue; } @@ -170,7 +187,7 @@ const DataTable = ({ // Filter if (state.enableFilters) { for (let i = 0; i < row.data.length; i++) { - if (cols[i].noSearch) { + if (state.cols[i].noSearch) { continue; } @@ -191,34 +208,31 @@ const DataTable = ({ state.sortBys.map(sortBy => row => { let i = sortBy[0]; - if (typeof i !== "number" || i >= row.data.length || i >= cols.length) { + if ( + typeof i !== "number" || + i >= row.data.length || + i >= state.cols.length + ) { i = 0; } - return getSortVal(row.data[i], cols[i].sortType); + return getSortVal(row.data[i], state.cols[i].sortType); }), state.sortBys.map(sortBy => sortBy[1]), ); - const colOrderFiltered = state.colOrder.filter( - ({ hidden, colIndex }) => !hidden && cols[colIndex], - ); - - return rowsOrdered.map((row, i) => { - return { - ...row, - data: colOrderFiltered.map(({ colIndex }) => - colIndex === rankCol ? i + 1 : row.data[colIndex], - ), - }; - }); + return rowsOrdered; }; - const handleReorder = (nextCols: Col[]) => { - console.log(nextCols); + const handleReorder = (oldIndex: number, newIndex: number) => { setStatePartial({ - colOrder: nextCols, + cols: arrayMove(state.cols, oldIndex, newIndex), + rows: state.rows.map(row => { + row.data = arrayMove([...row.data], oldIndex, newIndex); + return row; + }), }); + processedRows = processRows(); }; const handleColClick = (event: MouseEvent, i: number) => { @@ -238,10 +252,10 @@ const DataTable = ({ const handleExportCSV = () => { const colOrderFiltered = state.colOrder.filter( - ({ hidden, colIndex }) => !hidden && cols[colIndex], + ({ hidden, colIndex }) => !hidden && state.cols[colIndex], ); const columns = colOrderFiltered.map( - ({ colIndex }) => cols[colIndex].title, + ({ colIndex }) => state.cols[colIndex].title, ); const rows = processRows().map(row => row.data.map(val => getSearchVal(val, false)), @@ -287,11 +301,19 @@ const DataTable = ({ const handleFilterUpdate = ( event: SyntheticEvent, - i: number, + colKey: string, ) => { const filters = helpers.deepCopy(state.filters); // eslint-disable-line react/no-access-state-in-setstate + const filterIndex = filters.findIndex(f => colKey === f.col); + + if (filterIndex !== -1) + filters[filterIndex].value = event.currentTarget.value; + else + filters.push({ + col: colKey, + value: event.currentTarget.value, + }); - filters[i] = event.currentTarget.value; setStatePartial({ currentPage: 1, filters, @@ -328,7 +350,7 @@ const DataTable = ({ // If name changes, it means this is a whole new table and it has a different state (example: Player Stats switching between regular and advanced stats). // If colOrder does not match cols, need to run reconciliation code in loadStateFromCache (example: current vs past seasons in League Finances). - if (name !== state.prevName || cols.length > state.colOrder.length) { + if (name !== state.prevName || state.cols.length > state.colOrder.length) { setState( loadStateFromCache({ cols, @@ -389,13 +411,13 @@ const DataTable = ({ } const colOrderFiltered = state.colOrder.filter( - ({ hidden, colIndex }) => !hidden && cols[colIndex], + ({ hidden, colIndex }) => !hidden && state.cols[colIndex], ); return ( <> { - const newOrder = cols.map((col, i) => ({ + const newOrder = state.cols.map((col, i) => ({ colIndex: i, })); setStatePartial({ @@ -476,8 +498,7 @@ const DataTable = ({ })} >
) : null} diff --git a/src/ui/components/DataTable/loadStateFromCache.ts b/src/ui/components/DataTable/loadStateFromCache.ts index b5cbd417e3..8a24fdfa51 100644 --- a/src/ui/components/DataTable/loadStateFromCache.ts +++ b/src/ui/components/DataTable/loadStateFromCache.ts @@ -1,5 +1,5 @@ import { safeLocalStorage } from "../../util"; -import type { Props, State, SortBy } from "."; +import type { Props, State, SortBy, Filter } from "."; import SettingsCache from "./SettingsCache"; const loadStateFromCache = ({ @@ -30,13 +30,13 @@ const loadStateFromCache = ({ } // Don't let sortBy reference invalid col - sortBys = sortBys.filter(sortBy => sortBy[0] < cols.length); + sortBys = sortBys.filter(sortBy => cols.find(col => col.key === sortBy[0])); if (sortBys.length === 0) { sortBys = [defaultSort]; } - const defaultFilters: string[] = cols.map(() => ""); + const defaultFilters: Filter[] = []; const filtersFromStorage = settingsCache.get("DataTableFilters"); let filters; @@ -47,11 +47,14 @@ const loadStateFromCache = ({ filters = filtersFromStorage; // Confirm valid filters - if (!Array.isArray(filters) || filters.length !== cols.length) { + if (!Array.isArray(filters)) { filters = defaultFilters; } else { for (const filter of filters) { - if (typeof filter !== "string") { + if ( + typeof filter.col !== "string" || + typeof filter.value !== "string" + ) { filters = defaultFilters; break; } @@ -81,6 +84,8 @@ const loadStateFromCache = ({ // If too many cols... who cares, will get filtered out return { + cols, + rows: [], colOrder, currentPage: 1, enableFilters: filters !== defaultFilters, diff --git a/src/ui/util/columns/getCols.ts b/src/ui/util/columns/getCols.ts index 3959faea87..543dfcb519 100644 --- a/src/ui/util/columns/getCols.ts +++ b/src/ui/util/columns/getCols.ts @@ -2708,11 +2708,13 @@ const cols: { ...sportSpecificCols, }; -export function getAllCols(): ColTemp[] { - return Object.entries(cols).map(([name, col]) => { - col.title ??= name; - col.key = name; - return col; +export function getAllCols(): Col[] { + return Object.entries(cols).map(([name, col]): Col => { + return { + ...col, + title: col.title ?? name, + key: name, + }; }); } diff --git a/src/ui/views/FreeAgents.tsx b/src/ui/views/FreeAgents.tsx index 56c56d3191..d58e724e34 100644 --- a/src/ui/views/FreeAgents.tsx +++ b/src/ui/views/FreeAgents.tsx @@ -165,7 +165,7 @@ const FreeAgents = ({ Date: Wed, 1 Dec 2021 17:05:26 -0500 Subject: [PATCH 07/43] associative row data --- src/ui/components/DataTable/Header.tsx | 4 +- src/ui/components/DataTable/Row.tsx | 15 ++---- src/ui/components/DataTable/index.tsx | 10 ++-- src/ui/util/columns/getCols.ts | 4 +- src/ui/util/columns/getTemplate.ts | 1 + src/ui/views/TradingBlock.tsx | 71 ++++++++++---------------- src/worker/views/tradingBlock.ts | 34 +++++++++--- 7 files changed, 69 insertions(+), 70 deletions(-) diff --git a/src/ui/components/DataTable/Header.tsx b/src/ui/components/DataTable/Header.tsx index 5cf1061556..ec230f1538 100644 --- a/src/ui/components/DataTable/Header.tsx +++ b/src/ui/components/DataTable/Header.tsx @@ -219,8 +219,6 @@ const Header = ({ undefined, ); - console.log(filters); - const onSortStart = useCallback(({ index }) => { setIsDragged(true); setIndexSelected(index); @@ -233,7 +231,7 @@ const Header = ({ handleReorder(oldIndex, newIndex); }, - [handleReorder, cols], + [handleReorder], ); return ( diff --git a/src/ui/components/DataTable/Row.tsx b/src/ui/components/DataTable/Row.tsx index fd749a21c2..e95bf3847f 100644 --- a/src/ui/components/DataTable/Row.tsx +++ b/src/ui/components/DataTable/Row.tsx @@ -3,17 +3,11 @@ import PropTypes from "prop-types"; import type { MouseEvent } from "react"; import useClickable from "../../hooks/useClickable"; // eslint-disable-next-line import/no-unresolved -import type { Argument } from "classnames"; +import type { Col, DataTableRow } from "./index"; -const Row = ({ - row, -}: { - row: { - classNames?: Argument; - data: any[]; - }; -}) => { +const Row = ({ row, cols }: { row: DataTableRow; cols: Col[] }) => { const { clicked, toggleClicked } = useClickable(); + console.log(row); return ( - {row.data.map((value = null, i) => { + {cols.map((col, i) => { + const value = row.data[col.key || ""] ?? null; // Value is either the value, or an object containing the value as a property const actualValue = value !== null && value.hasOwnProperty("value") ? value.value : value; diff --git a/src/ui/components/DataTable/index.tsx b/src/ui/components/DataTable/index.tsx index 4d4af8ec40..697e8fecfc 100644 --- a/src/ui/components/DataTable/index.tsx +++ b/src/ui/components/DataTable/index.tsx @@ -227,10 +227,10 @@ const DataTable = ({ const handleReorder = (oldIndex: number, newIndex: number) => { setStatePartial({ cols: arrayMove(state.cols, oldIndex, newIndex), - rows: state.rows.map(row => { - row.data = arrayMove([...row.data], oldIndex, newIndex); - return row; - }), + // rows: state.rows.map(row => { + // row.data = arrayMove([...row.data], oldIndex, newIndex); + // return row; + // }), }); processedRows = processRows(); }; @@ -509,7 +509,7 @@ const DataTable = ({ /> {processedRows.map(row => ( - + ))}