239 lines
8.9 KiB
Vue
239 lines
8.9 KiB
Vue
<!-- eslint-disable indent -->
|
|
<template>
|
|
<div class="schedule-view">
|
|
|
|
<div class="centerDiv">
|
|
<div class="row">
|
|
<h1>Season {{ seasonNumber }} Schedule</h1>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-sm-7">
|
|
<div class="row">
|
|
<h2 id="week-num">Week {{ selectedWeekNumber }}</h2>
|
|
</div>
|
|
<!-- Matchups -->
|
|
<div class="row">
|
|
<div v-for="(matchup, index) in gamesGroupedByMatchup" :key="index" class="col-sm-auto">
|
|
<div class="table-responsive-sm" style="text-align: center">
|
|
<table class="table table-sm table-striped">
|
|
<thead class="thead-dark">
|
|
<tr>
|
|
<th style="width: 3rem">Away</th>
|
|
<th style="width: 5rem">Score</th>
|
|
<th style="width: 3rem">Home</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody :id="`matchup-${index}`">
|
|
<tr v-for="game in matchup" :key="game.id" :id="`game-id-${game.id}`">
|
|
<td>
|
|
<RouterLink
|
|
:to="{ name: 'team', params: { seasonNumber: seasonNumber, teamAbbreviation: game.away_team.abbrev } }"
|
|
:style="{ 'font-weight': game.away_score > game.home_score ? 'bold' : 'normal' }">
|
|
{{ game.away_team.abbrev }}
|
|
</RouterLink>
|
|
</td>
|
|
<td>
|
|
<RouterLink v-if="game.away_score || game.home_score"
|
|
:to="{ name: 'games', params: { seasonNumber: seasonNumber, weekNumber: selectedWeekNumber, gameNumber: game.game_num, team1Abbreviation: game.away_team.abbrev, team2Abbreviation: game.home_team.abbrev } }">
|
|
{{ `${game.away_score}-${game.home_score}` }}
|
|
</RouterLink>
|
|
<template v-else>@</template>
|
|
</td>
|
|
<td>
|
|
<RouterLink
|
|
:to="{ name: 'team', params: { seasonNumber: seasonNumber, teamAbbreviation: game.home_team.abbrev } }"
|
|
:style="{ 'font-weight': game.home_score > game.away_score ? 'bold' : 'normal' }">
|
|
{{ game.home_team.abbrev }}
|
|
</RouterLink>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Week Buttons -->
|
|
<div class="row">
|
|
<div class="col-sm">
|
|
<button v-if="selectedWeekNumber > 1" class="btn btn-outline-primary m-1"
|
|
@click="$router.push({ name: 'schedule', params: { seasonNumber: seasonNumber, weekNumber: selectedWeekNumber - 1 } })">
|
|
<< Week {{ selectedWeekNumber - 1 }}
|
|
</button>
|
|
<button class="btn btn-primary m-1">
|
|
Week {{ selectedWeekNumber }}
|
|
</button>
|
|
<!-- TODO might want to do regular season week + post season week amount here -->
|
|
<button v-if="selectedWeekNumber < 21" class="btn btn-outline-primary m-1"
|
|
@click="$router.push({ name: 'schedule', params: { seasonNumber: seasonNumber, weekNumber: selectedWeekNumber + 1 } })">
|
|
Week {{ selectedWeekNumber + 1 }} >>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-5">
|
|
<div class="row">
|
|
<div>
|
|
<h2>Season Schedule
|
|
<a v-if="isAuthenticated && sheetsUrl" target="_blank" :href="sheetsUrl"
|
|
title="Master Schedule per Lyle">
|
|
🡵
|
|
</a>
|
|
</h2>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="table-responsive-xl">
|
|
<table class="table table-sm table-striped">
|
|
<thead class="thead-dark">
|
|
<tr>
|
|
<th>Week</th>
|
|
<th>Start Date</th>
|
|
<th>End Date</th>
|
|
<th>Notes</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="week in scheduleWeeks" :key="week.weekNumber">
|
|
<td>
|
|
<RouterLink
|
|
:to="{ name: 'schedule', params: { seasonNumber: seasonNumber, weekNumber: week.weekNumber } }">
|
|
Week {{ week.weekNumber }}
|
|
</RouterLink>
|
|
</td>
|
|
<td>{{ week.weekStart }}</td>
|
|
<td>{{ week.weekEnd }}</td>
|
|
<td>{{ week.weekSpecialInfo }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import type { Game } from '@/services/apiResponseTypes'
|
|
import { type LeagueInfo, fetchCurrentLeagueInfo } from '@/services/currentService'
|
|
import { CHRISTMAS, CURRENT_SEASON, SEASON_START_DATE, THANKSGIVING } from '@/services/utilities'
|
|
import { fetchGamesBySeasonAndWeek } from '@/services/gameService'
|
|
import dayjs from 'dayjs'
|
|
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
|
import { isDiscordAuthenticated } from '@/services/authenticationService'
|
|
dayjs.extend(customParseFormat)
|
|
|
|
interface ScheduleWeekRow {
|
|
weekNumber: number
|
|
weekStart: string
|
|
weekEnd: string
|
|
weekSpecialInfo: string
|
|
}
|
|
|
|
export default {
|
|
name: 'ScheduleView',
|
|
data() {
|
|
return {
|
|
isAuthenticated: false as boolean,
|
|
sheetsUrl: 'https://docs.google.com/spreadsheets/d/1uYkbp3QWoBwBQHhgeW5EWfYF-_E7nKNmzrVbq084ZtQ/edit?usp=sharing',
|
|
currentWeekNumber: 0,
|
|
weekGames: [] as Game[]
|
|
}
|
|
},
|
|
props: {
|
|
seasonNumber: { type: Number, default: CURRENT_SEASON },
|
|
weekNumber: { type: Number, required: false }
|
|
},
|
|
created() {
|
|
this.fetchCurrentWeekNumber()
|
|
this.fetchData()
|
|
},
|
|
computed: {
|
|
selectedWeekNumber(): number {
|
|
if (this.weekNumber || this.weekNumber === 0) return this.weekNumber
|
|
return this.currentWeekNumber
|
|
},
|
|
gamesGroupedByMatchup(): Game[][] {
|
|
if (!this.weekGames.length) return []
|
|
|
|
const groupedGames = this.weekGames.reduce((storage, game) => {
|
|
const key = [game.home_team.abbrev, game.away_team.abbrev].sort().join('-')
|
|
if (storage[key]) {
|
|
storage[key].push(game)
|
|
} else {
|
|
storage[key] = [game]
|
|
}
|
|
return storage
|
|
}, {} as { [key: string]: Game[] })
|
|
|
|
return Object.values(groupedGames)
|
|
},
|
|
scheduleWeeks(): ScheduleWeekRow[] {
|
|
const schedule = []
|
|
let currentWeekStartDate = SEASON_START_DATE
|
|
|
|
for (let week = 1; week <= 21; week++) {
|
|
const weekStartDate = currentWeekStartDate
|
|
const weekEndDate = this.isLongSeries(weekStartDate, week)
|
|
? currentWeekStartDate.add(13, 'd')
|
|
: currentWeekStartDate.add(6, 'd')
|
|
|
|
schedule.push({
|
|
weekNumber: week,
|
|
weekStart: weekStartDate.format('MM/DD/YYYY'),
|
|
weekEnd: weekEndDate.format('MM/DD/YYYY'),
|
|
weekSpecialInfo: this.weekSpecialInfo(week)
|
|
})
|
|
|
|
currentWeekStartDate = weekEndDate.add(1, 'd')
|
|
}
|
|
|
|
return schedule
|
|
}
|
|
},
|
|
watch: {
|
|
seasonNumber(newValue, oldValue) {
|
|
if (newValue !== oldValue)
|
|
this.fetchData()
|
|
},
|
|
selectedWeekNumber(newValue, oldValue) {
|
|
if (newValue !== oldValue)
|
|
this.fetchData()
|
|
}
|
|
},
|
|
methods: {
|
|
async fetchCurrentWeekNumber(): Promise<void> {
|
|
const leagueInfo: LeagueInfo = await fetchCurrentLeagueInfo()
|
|
this.currentWeekNumber = leagueInfo.week
|
|
|
|
this.isAuthenticated = await isDiscordAuthenticated()
|
|
},
|
|
async fetchData(): Promise<void> {
|
|
this.weekGames = await fetchGamesBySeasonAndWeek(this.seasonNumber, this.selectedWeekNumber)
|
|
},
|
|
isLongSeries(weekStartDate: dayjs.Dayjs, week: number): boolean {
|
|
// current 18-week schedule has 2 week series for any game week that falls
|
|
// on the week of Thanksgiving or Christmas, and we are back to 2 weeks for
|
|
// LCS and WS in the postseason as well
|
|
return week === 20
|
|
|| week === 21
|
|
|| Math.abs(weekStartDate.diff(THANKSGIVING, 'days')) < 6
|
|
|| Math.abs(weekStartDate.diff(CHRISTMAS, 'days')) < 6
|
|
},
|
|
weekSpecialInfo(weekNumber: number): string {
|
|
if (weekNumber === 1) return 'Spring Begins'
|
|
if (weekNumber === 6) return 'Summer Begins'
|
|
if (weekNumber === 13) return 'Trade Deadline'
|
|
if (weekNumber === 15) return 'Fall Begins'
|
|
if (weekNumber === 18) return 'Regular Season Ends'
|
|
if (weekNumber === 19) return 'Division Series - Best of 5'
|
|
if (weekNumber === 20) return 'League Championship Series - Best of 7'
|
|
if (weekNumber === 21) return 'World Series Best of 7'
|
|
|
|
return ''
|
|
}
|
|
}
|
|
}
|
|
</script> |