diff --git a/CHANGELOG.md b/CHANGELOG.md index 75bf11859..06592c552 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 0cb96dd87..89b99606c 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 4dceb6282..0cefc8550 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 30cc7447f..3779a097b 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 ba7b207c7..ffb1753ab 100644 --- a/src/lib/Matchups/BracketsColumn.svelte +++ b/src/lib/Matchups/BracketsColumn.svelte @@ -101,20 +101,30 @@ return ''; } - const calculatePoints = (points) => { - if(!points) return 0; + const calculatePoints = (allPoints) => { 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 +252,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 62e7c08fa..37d24f302 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 cece15110..75305297c 100644 --- a/src/lib/utils/helperFunctions/leagueBrackets.js +++ b/src/lib/utils/helperFunctions/leagueBrackets.js @@ -7,29 +7,51 @@ import { get } from 'svelte/store'; import {brackets} from '$lib/stores'; export const getBrackets = async () => { - if(get(brackets).champs) { - return get(brackets); - } + if(get(brackets).champs) { + return get(brackets); + } // get roster, user, and league data - const [rosterRes, users, leagueData] = await waitForAll( - getLeagueRosters(), - getLeagueUsers(), - getLeagueData(), - ).catch((err) => { console.error(err); }); + const [rosterRes, users, leagueData] = await waitForAll( + getLeagueRosters(), + getLeagueUsers(), + getLeagueData(), + ).catch((err) => { console.error(err); }); - const rosters = rosterRes.rosters; + const rosters = rosterRes.rosters; // Number of rosters (in order to determine the number of places, i.e. 1st - 12th) const numRosters = rosters.length; // get bracket data for winners and losers - const bracketsAndMatchupFetches = [ + const bracketsAndMatchupFetches = [ fetch(`https://api.sleeper.app/v1/league/${leagueID}/winners_bracket`, {compress: true}), 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; + 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, @@ -79,18 +100,20 @@ export const getBrackets = async () => { losers, } - brackets.update(() => finalBrackets); + brackets.update(() => finalBrackets); - return finalBrackets; + 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 - }) - } 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 - }) - } + const t2 = playoffBracket.t2; + matchup.push(generateMatchupData(t2, t2From, {m, r, playoffMatchups, i, rosters, users, playoffType, winners, fromWinners, consolation, p})); - } else { - matchup.push({ - manager: null, - consolation, - t2From, - winners, - fromWinners, - r, - m, - }); + 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, } - return matchup; -} \ No newline at end of file + + 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.manager = { + name: 'Unknown Manager', + avatar: `https://sleepercdn.com/images/v2/icons/player_default.webp`, + }; + } + } + + 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 840f41ca6..323e9adc1 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 3a1715d21..e4e623357 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 96ba7ca47..b15b635e6 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%;