From 4933af78b57fa9bd53fb188f8200d554bc0bc92c Mon Sep 17 00:00:00 2001 From: Nicholas Melhado Date: Wed, 13 Apr 2022 11:26:04 -0400 Subject: [PATCH] render league brackets correctly for two weeks per round leagues --- CHANGELOG.md | 6 + package-lock.json | 5 +- package.json | 2 +- src/lib/Matchups/Brackets.svelte | 30 ++- src/lib/Matchups/BracketsColumn.svelte | 31 ++- src/lib/Matchups/Matchup.svelte | 15 +- .../utils/helperFunctions/leagueBrackets.js | 228 +++++++++--------- src/lib/version.js | 2 +- src/theme/_smui-theme.scss | 2 +- src/theme/dark/_smui-theme.scss | 2 +- 10 files changed, 184 insertions(+), 139 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75bf118596..06592c5520 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. +## [1.2.17] - 2022-04-13 + +### Fixed + +- Brackets now account for two week per round leagues [issue #97](https://github.com/nmelhado/league-page/issues/97) + ## [1.2.16] - 2022-01-06 ### Fixed diff --git a/package-lock.json b/package-lock.json index 0cb96dd875..89b99606c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,11 @@ { "name": "league-page", - "version": "1.2.16", + "version": "1.2.17", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "league-page", - "version": "1.2.16", + "version": "1.2.17", "license": "MIT", "dependencies": { "@smui/button": "6.0.0-beta.13", diff --git a/package.json b/package.json index 4dceb62827..0cefc85502 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "league-page", - "version": "1.2.16", + "version": "1.2.17", "homepage": "https://github.com/nmelhado/league-page", "repository": { "type": "git", diff --git a/src/lib/Matchups/Brackets.svelte b/src/lib/Matchups/Brackets.svelte index 30cc7447fe..3779a097b7 100644 --- a/src/lib/Matchups/Brackets.svelte +++ b/src/lib/Matchups/Brackets.svelte @@ -1,6 +1,7 @@ @@ -84,6 +91,13 @@ padding: 2em 0; margin-bottom: 2em; } + + .buttonHolder { + display: flex; + flex-direction: column; + align-items: center; + margin: 3em 0; + }
@@ -104,6 +118,20 @@
{#if matchup} - + {#if matchup[0].starters[2] } +
+ + + + + + +
+ {/if} + {/if}
\ No newline at end of file diff --git a/src/lib/Matchups/BracketsColumn.svelte b/src/lib/Matchups/BracketsColumn.svelte index ba7b207c7c..f2d91540a5 100644 --- a/src/lib/Matchups/BracketsColumn.svelte +++ b/src/lib/Matchups/BracketsColumn.svelte @@ -101,20 +101,31 @@ return ''; } - const calculatePoints = (points) => { - if(!points) return 0; + const calculatePoints = (allPoints) => { + if(Array.isArray(allPoints)) return 0; let totalPoints = 0; - for(const point of points) { - totalPoints += point; + for(const k in allPoints) { + const points = allPoints[k]; + if(!points) break; + for(const point of points) { + totalPoints += point; + } } return round(totalPoints) } - const calculatePotentialPoints = (starters, ix, p) => { - if(!starters) return 0; + const calculatePotentialPoints = (startersWeeks, ix, p) => { + if(!startersWeeks) return 0; let totalPoints = 0; - for(const starter of starters) { - totalPoints += parseFloat(players[starter]?.wi && players[starter].wi[playoffsStart - ix]?.p ? players[starter].wi[playoffsStart - ix].p : 0); + + for(const k in startersWeeks) { + const starters = startersWeeks[k]; + if(!starters) break; + + const i = ix + k -1; + for(const starter of starters) { + totalPoints += parseFloat(players[starter]?.wi && players[starter].wi[playoffsStart - i]?.p ? players[starter].wi[playoffsStart - i].p : 0); + } } return round(totalPoints); } @@ -242,13 +253,13 @@ line-height: 1.1em; font-size: 0.85em; padding-left: 1em; - color: #333; + color: var(--g333); text-align: right; } .projectedPoints { font-size: 0.8em; - color: #888; + color: var(--g999); } /* SVG styling */ diff --git a/src/lib/Matchups/Matchup.svelte b/src/lib/Matchups/Matchup.svelte index 62e7c08fa1..37d24f302b 100644 --- a/src/lib/Matchups/Matchup.svelte +++ b/src/lib/Matchups/Matchup.svelte @@ -1,7 +1,7 @@ diff --git a/src/lib/utils/helperFunctions/leagueBrackets.js b/src/lib/utils/helperFunctions/leagueBrackets.js index cece15110a..6a6d42de04 100644 --- a/src/lib/utils/helperFunctions/leagueBrackets.js +++ b/src/lib/utils/helperFunctions/leagueBrackets.js @@ -29,7 +29,29 @@ export const getBrackets = async () => { fetch(`https://api.sleeper.app/v1/league/${leagueID}/losers_bracket`, {compress: true}), ] - const playoffsStart = leagueData.settings.playoff_week_start; + // variables for playoff records + // let numPOTeams = parseInt(leagueData.settings.playoff_teams); + let playoffType; + const year = parseInt(leagueData.season); + // let playoffCase; // for determining relevant (ie. PO bracket) matches + const playoffsStart = parseInt(leagueData.settings.playoff_week_start); + + // before 2020, 1 week/round was only option; in 2020, 2 weeks/rounds added; in 2021, 1 week/round + 2 champ + // 0: 1 week per round + // 1: 1 week per round + 2 champ + // 2: 2 weeks per round + if(year > 2019) { + playoffType = parseInt(leagueData.settings.playoff_round_type); + } else { + playoffType = 0; + } + + // in 2020 type 1 was 2 weeks per round, this was later changed to type 2 + if(year == 2020) { + if(playoffType == 1) playoffType++; + } + + // const playoffLength = getPlayoffLength(playoffType, numPOTeams) // add each week after the regular season to the fetch array for(let i = playoffsStart; i < 19; i++) { @@ -57,18 +79,17 @@ export const getBrackets = async () => { // The second element above was the winners bracket, so remove that, the remaining items are matchup weeks const losersData = playoffMatchups.shift(); - // determine the length of the playoffs by looking at the last bracket const playoffRounds = winnersData[winnersData.length - 1].r; const loserRounds = losersData[losersData.length - 1].r; // champBracket is an object where the key will be the round number // the value at each key will be an array of matchups - const champs = evaluateBracket(winnersData, playoffRounds, playoffMatchups, rosters, users); + const champs = evaluateBracket(winnersData, playoffRounds, playoffMatchups, rosters, users, playoffType); // champBracket is an object where the key will be the round number // the value at each key will be an array of matchups - let losers = evaluateBracket(losersData, loserRounds, playoffMatchups, rosters, users); + let losers = evaluateBracket(losersData, loserRounds, playoffMatchups, rosters, users, playoffType); const finalBrackets = { numRosters, @@ -84,13 +105,15 @@ export const getBrackets = async () => { return finalBrackets; } -const evaluateBracket = (contestants, rounds, playoffMatchups, rosters, users) => { +const evaluateBracket = (contestants, rounds, playoffMatchups, rosters, users, playoffType) => { let bracket = []; let consolations = []; // which matches in the previous round were consolation matches let consolationMs = []; // which matches in the previous round came from matches where they were winners let fromWs = []; + // teams seen + let teamsSeen = {}; for(let i = 1; i <= rounds; i++) { const playoffBrackets = contestants.filter(m => m.r == i); const roundMatchups = []; @@ -99,9 +122,9 @@ const evaluateBracket = (contestants, rounds, playoffMatchups, rosters, users) = const localConsolationMs = []; let localFromWs = []; for(const playoffBracket of playoffBrackets) { - if(!playoffBracket.t1_from && playoffBracket.t2_from) { + if((!playoffBracket.t1_from && playoffBracket.t2_from) || (!teamsSeen[playoffBracket.t1] && teamsSeen[playoffBracket.t2])) { // this was from a team that got a bye - let byeMatchup = processPlayoffMatchup(playoffBracket, playoffMatchups[i - 2], rosters, users, consolationMs, fromWs); + let byeMatchup = processPlayoffMatchup({playoffBracket, playoffMatchups, i: i - 2, rosters, users, consolationMs, fromWs, playoffType, teamsSeen}); byeMatchup.bye = true; byeMatchup[0].m = null; byeMatchup[1].m = null; @@ -116,7 +139,9 @@ const evaluateBracket = (contestants, rounds, playoffMatchups, rosters, users) = bracket[i - 2].push(byeMatchup); } } - const roundMatchup = processPlayoffMatchup(playoffBracket, playoffMatchups[i - 1], rosters, users, consolationMs, fromWs); + teamsSeen[playoffBracket.t1] = playoffBracket.m; + teamsSeen[playoffBracket.t2] = playoffBracket.m; + const roundMatchup = processPlayoffMatchup({playoffBracket, playoffMatchups, i: i - 1, rosters, users, consolationMs, fromWs, playoffType, teamsSeen}); if(roundMatchup[0].winners) { // This matchup came from winners localFromWs.push(roundMatchup[0].m) @@ -134,7 +159,7 @@ const evaluateBracket = (contestants, rounds, playoffMatchups, rosters, users) = for(const consolation of consolations) { for(const consolationMatchup of consolationMatchups) { // if this matchup originated from winners, then it is a continuation of a previous consolation match - if(consolationMatchup[0].winners && consolation[i-2] && consolationMatchup[0].t1From == consolation[i-2][0][0].m) { + if(consolationMatchup[0].winners && consolation[i-2] && consolation[i-2] && consolationMatchup[0].t1From == consolation[i-2][0][0].m) { consolation[i-1] = [consolationMatchup]; } } @@ -154,124 +179,99 @@ const evaluateBracket = (contestants, rounds, playoffMatchups, rosters, users) = } const newConsolation = (consolationMatchups, rounds, i) => { - const newConsolation = new Array(rounds).fill([]); - newConsolation[i - 1] = consolationMatchups; - return newConsolation; + const newCons = new Array(rounds).fill([]); + newCons[i - 1] = consolationMatchups; + return newCons; } -const processPlayoffMatchup = (bracket, matchups, rosters, users, consolationMs, fromWs) => { +const processPlayoffMatchup = ({playoffBracket, playoffMatchups, i, rosters, users, consolationMs, fromWs, playoffType, teamsSeen}) => { const matchup = []; - const m = bracket.m; - const r = bracket.r; - const t1From = bracket.t1_from?.w ? bracket.t1_from?.w : bracket.t1_from?.l; - const t2From = bracket.t2_from?.w ? bracket.t2_from?.w : bracket.t2_from?.l; - const winners = bracket.t1_from?.w && bracket.t2_from?.w ? true : false; + const m = playoffBracket.m; + const r = playoffBracket.r; + const p = playoffBracket.p; + const t1From = teamsSeen[playoffBracket.t1]; + const t2From = teamsSeen[playoffBracket.t2]; + const winners = playoffBracket.t1_from?.w && playoffBracket.t2_from?.w ? true : false; const fromWinners = fromWs.indexOf(t2From || -999) > -1 ? true : false; let consolation = false; - if((bracket.t1_from?.l && bracket.t2_from?.l) || consolationMs.indexOf(t1From) > -1 || consolationMs.indexOf(t2From) > -1) { + if((p && p != 1) || (playoffBracket.t1_from?.l && playoffBracket.t2_from?.l) || consolationMs.indexOf(t1From) > -1 || consolationMs.indexOf(t2From) > -1) { consolation = true; } // first team in matchup - const t1 = bracket.t1; - if(t1) { - const t1user = users[rosters[t1 - 1].owner_id]; - const t1Matchup = matchups.filter(m => m.roster_id == t1)[0] - - if(t1user) { - matchup.push({ - manager: { - name: t1user.metadata.team_name ? t1user.metadata.team_name : t1user.display_name, - avatar: `https://sleepercdn.com/avatars/thumbs/${t1user.avatar}`, - }, - starters: t1Matchup?.starters, - points: t1Matchup?.starters_points, - t1From, - m, - r, - winners, - fromWinners, - consolation - }) - } else { - matchup.push({ - manager: { - name: 'Unknown Manager', - avatar: `https://sleepercdn.com/images/v2/icons/player_default.webp`, - }, - starters: t1Matchup?.starters, - points: t1Matchup?.starters_points, - t1From, - m, - r, - winners, - fromWinners, - consolation - }) - } - - } else { - matchup.push({ - manager: null, - consolation, - t1From, - m, - r, - winners, - fromWinners, - }); - } + const t1 = playoffBracket.t1; + matchup.push(generateMatchupData(t1, t1From, {m, r, playoffMatchups, i, rosters, users, playoffType, winners, fromWinners, consolation, p})); // second team in matchup - const t2 = bracket.t2; - if(t2) { - const t2user = users[rosters[t2 - 1].owner_id]; - const t2Matchup = matchups.filter(m => m.roster_id == t2)[0] - - if(t2user) { - matchup.push({ - manager: { - name: t2user.metadata.team_name ? t2user.metadata.team_name : t2user.display_name, - avatar: `https://sleepercdn.com/avatars/thumbs/${t2user.avatar}`, - }, - starters: t2Matchup?.starters, - points: t2Matchup?.starters_points, - t2From, - m, - r, - winners, - fromWinners, - consolation - }) + const t2 = playoffBracket.t2; + matchup.push(generateMatchupData(t2, t2From, {m, r, playoffMatchups, i, rosters, users, playoffType, winners, fromWinners, consolation, p})); + + return matchup; +} + +const generateMatchupData = (t, tFrom, {m, r, playoffMatchups, i, rosters, users, playoffType, winners, fromWinners, consolation, p}) => { + let matchup = { + manager: null, + points: undefined, + starters: undefined, + consolation, + tFrom, + m, + r, + winners, + fromWinners, + } + + if(t) { + const tuser = users[rosters[t - 1].owner_id]; + const tMatchup = playoffMatchups[i].filter(ma => ma.roster_id == t)[0]; + let tMatchupStarters = {} + tMatchupStarters[1] = tMatchup?.starters; + const tMatchupStartersPoints = {}; + tMatchupStartersPoints[1] = tMatchup?.starters_points; + // playoffType 2: 2 weeks per round + // playoffType 1: 1 weeks per round, 2 in championship round + if(playoffType == 2 || (p && p == 1 && playoffType == 1)) { + const secondWeek = playoffMatchups[i+1].filter(ma => ma.roster_id == t)[0]; + tMatchupStarters[2] = secondWeek?.starters; + tMatchupStartersPoints[2] = secondWeek?.starters_points; + } + + matchup.starters = tMatchupStarters; + matchup.points = tMatchupStartersPoints; + + if(tuser) { + matchup.manager = { + name: tuser.metadata.team_name ? tuser.metadata.team_name : tuser.display_name, + avatar: `https://sleepercdn.com/avatars/thumbs/${tuser.avatar}`, + }; } else { - matchup.push({ - manager: { - name: 'Unknown Manager', - avatar: `https://sleepercdn.com/images/v2/icons/player_default.webp`, - }, - starters: t2Matchup?.starters, - points: t2Matchup?.starters_points, - t2From, - m, - r, - winners, - fromWinners, - consolation - }) + matchup.manager = { + name: 'Unknown Manager', + avatar: `https://sleepercdn.com/images/v2/icons/player_default.webp`, + }; } - - } else { - matchup.push({ - manager: null, - consolation, - t2From, - winners, - fromWinners, - r, - m, - }); } - return matchup; -} \ No newline at end of file + + return matchup; +} + +const getPlayoffLength = (playoffType, numPOTeams) => { + let playoffLength = 3; + + if(numPOTeams == 4) { + return playoffLength--; + } + + if(playoffType == 1) { + return playoffLength++; + } + + if(playoffType == 2) { + return playoffLength *= 2; + } + + return playoffLength +} diff --git a/src/lib/version.js b/src/lib/version.js index 840f41ca69..323e9adc17 100644 --- a/src/lib/version.js +++ b/src/lib/version.js @@ -5,4 +5,4 @@ available for your copy of League Page */ // Keep in sync with package.json -export const version = "1.2.16"; +export const version = "1.2.17"; diff --git a/src/theme/_smui-theme.scss b/src/theme/_smui-theme.scss index 3a1715d218..e4e623357b 100644 --- a/src/theme/_smui-theme.scss +++ b/src/theme/_smui-theme.scss @@ -58,7 +58,7 @@ --draftSwapped: #f8fcff; --waiverAdd: #e9fff1; --waiverDrop: #ffe9e9; - --bracketMatch: #f7fdff; + --bracketMatch: #fafeff; --matchupSelected: #fff; --fadeOne: rgba(255, 255, 255, 0) 0%; --fadeTwo: rgba(255, 255, 255, 0.7) 50%; diff --git a/src/theme/dark/_smui-theme.scss b/src/theme/dark/_smui-theme.scss index 96ba7ca47e..b15b635e6e 100644 --- a/src/theme/dark/_smui-theme.scss +++ b/src/theme/dark/_smui-theme.scss @@ -58,7 +58,7 @@ --draftSwapped: #202025; --waiverAdd: #3e4741; --waiverDrop: #423a3a; - --bracketMatch: #0b0b0c; + --bracketMatch: #010102; --matchupSelected: #2f2f35; --fadeOne: rgba(0, 0, 0, 0) 0%; --fadeTwo: rgba(0, 0, 0, 0.7) 50%;