From 77be97ac4f26dbc46b5347a5209bf82eb9916ce1 Mon Sep 17 00:00:00 2001 From: Peter Date: Sun, 21 Jan 2024 20:48:22 -0500 Subject: [PATCH] Make game page like old site --- src/components/TeamPitchingTable.vue | 4 +- src/router/index.ts | 16 + src/services/battingStatsService.ts | 16 + src/services/fieldingStatsService.ts | 16 + src/services/gameService.ts | 22 ++ src/services/pitchingStatsService.ts | 16 + src/views/GameView.vue | 444 +++++++++++++++++++++++++++ src/views/ScheduleView.vue | 4 +- 8 files changed, 534 insertions(+), 4 deletions(-) create mode 100644 src/views/GameView.vue diff --git a/src/components/TeamPitchingTable.vue b/src/components/TeamPitchingTable.vue index 459ea29..26271bb 100644 --- a/src/components/TeamPitchingTable.vue +++ b/src/components/TeamPitchingTable.vue @@ -39,7 +39,7 @@ - + @@ -118,7 +118,7 @@ import { aggregatePitchingStats, fetchPitchingStatsBySeasonAndTeamId, type Pitch import { outsToInnings, winPercentage, hitsPer9, hrsPer9 } from '@/services/utilities' export default { - name: "TeamPitchingTable", + name: 'TeamPitchingTable', props: { seasonNumber: { type: Number, required: true }, teamId: { type: Number, required: true }, diff --git a/src/router/index.ts b/src/router/index.ts index 2678e7f..a689d1c 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -53,6 +53,12 @@ export const routes: RouteRecordRaw[] = [ component: () => import('../views/ManagerView.vue'), props: castManagersRouteParams }, + { + path: '/games/:seasonNumber/:weekNumber/:gameNumber/:team1Abbreviation/:team2Abbreviation', + name: 'games', + component: () => import('../views/GameView.vue'), + props: castGamesRouteParams + }, ] function castTeamsRouteParams(route: { params: { teamAbbreviation: string, seasonNumber: string } }) { @@ -82,6 +88,16 @@ function castManagersRouteParams(route: { params: { managerName: string } }) { } } +function castGamesRouteParams(route: { params: { seasonNumber: string, weekNumber: string, gameNumber: string, team1Abbreviation: string, team2Abbreviation: string } }) { + return { + seasonNumber: Number(route.params.seasonNumber), + weekNumber: Number(route.params.weekNumber), + gameNumber: Number(route.params.gameNumber), + team1Abbreviation: route.params.team1Abbreviation, + team2Abbreviation: route.params.team2Abbreviation, + } +} + const router = createRouter({ history: createWebHistory(), //import.meta.env.BASE_URL), routes, diff --git a/src/services/battingStatsService.ts b/src/services/battingStatsService.ts index b9e31c6..91f2534 100644 --- a/src/services/battingStatsService.ts +++ b/src/services/battingStatsService.ts @@ -155,6 +155,22 @@ export async function fetchBattingStatsForLastFourGamesBySeasonAndPlayerId(seaso return battingStatsResponse.stats } +export async function fetchBattingStatsBySeries(seasonNumber: number, weekNumber: number, homeTeamId: number, awayTeamId: number): Promise { + // no support for pre-modern games yet + if (seasonNumber < MODERN_STAT_ERA_START) { + return [] + } + + const response = await fetch(`${SITE_URL}/api/v3/plays/batting?season=${seasonNumber}&week=${weekNumber}&team_id=${homeTeamId}&team_id=${awayTeamId}&group_by=playergame`) + + const battingStatsResponse: { + count: number + stats: BattingStat[] + } = await response.json() + + return battingStatsResponse.stats +} + export function aggregateBattingStats(battingStats: BattingStat[]): BattingStat { const totalStat: BattingStat = { player: battingStats[0].player, diff --git a/src/services/fieldingStatsService.ts b/src/services/fieldingStatsService.ts index bacf8cf..8320f98 100644 --- a/src/services/fieldingStatsService.ts +++ b/src/services/fieldingStatsService.ts @@ -137,6 +137,22 @@ export async function fetchFieldingStatsForLastFourGamesBySeasonAndPlayerId(seas return fieldingStatsResponse.stats.map(normalizeFieldingStat) } +export async function fetchFieldingStatsBySeries(seasonNumber: number, weekNumber: number, homeTeamId: number, awayTeamId: number): Promise { + // no support for pre-modern games yet + if (seasonNumber < MODERN_STAT_ERA_START) { + return [] + } + + const response = await fetch(`${SITE_URL}/api/v3/plays/fielding?season=${seasonNumber}&week=${weekNumber}&team_id=${homeTeamId}&team_id=${awayTeamId}&group_by=playerpositiongame`) + + const fieldingStatsResponse: { + count: number + stats: FieldingStatRaw[] + } = await response.json() + + return fieldingStatsResponse.stats.map(normalizeFieldingStat) +} + export function aggregateFieldingStats(fieldingStats: FieldingStat[]): FieldingStat[] { const fieldingStatsByPosition = fieldingStats.reduce((statsByPos: { [key: string]: FieldingStat }, stat: FieldingStat) => { if (!statsByPos[stat.pos]) { diff --git a/src/services/gameService.ts b/src/services/gameService.ts index 79831aa..96b4775 100644 --- a/src/services/gameService.ts +++ b/src/services/gameService.ts @@ -32,3 +32,25 @@ export async function fetchGamesBySeasonAndWeek(seasonNumber: number, weekNumber return gamesResponse.games } + +export async function fetchSingleGame(seasonNumber: number, weekNumber: number, gameNumber: number, homeTeamId: number, awayTeamId: number): Promise { + if (seasonNumber < MODERN_STAT_ERA_START) { + console.warn('Cannot use games endpoint to fetch stats before season 8') + return undefined + } + + const response = await fetch(`${SITE_URL}/api/v3/games?season=${seasonNumber}&week=${weekNumber}&game_num=${gameNumber}&team1_id=${homeTeamId}&team2_id=${awayTeamId}`) + + const gamesResponse: { + count: number + games: Game[] + } = await response.json() + + if (gamesResponse.count !== 1) { + throw new Error('gameService.fetchSingleGame - Expected one game, return contained none or many') + } + + return gamesResponse.games[0] +} + +// v3/games?season=9&week=1&game_num=1&team1_id=355&team2_id=361&short_output=TRUE diff --git a/src/services/pitchingStatsService.ts b/src/services/pitchingStatsService.ts index 60c583a..fdf90c2 100644 --- a/src/services/pitchingStatsService.ts +++ b/src/services/pitchingStatsService.ts @@ -222,6 +222,22 @@ export async function fetchPitchingStatsForLastFourGamesBySeasonAndPlayerId(seas return pitchingStatsResponse.stats.map(normalizePitchingStat) } +export async function fetchPitchingStatsBySeries(seasonNumber: number, weekNumber: number, homeTeamId: number, awayTeamId: number): Promise { + // no support for pre-modern games yet + if (seasonNumber < MODERN_STAT_ERA_START) { + return [] + } + + const response = await fetch(`${SITE_URL}/api/v3/plays/pitching?season=${seasonNumber}&week=${weekNumber}&team_id=${homeTeamId}&team_id=${awayTeamId}&group_by=playergame`) + + const pitchingStatsResponse: { + count: number + stats: PitchingStat[] + } = await response.json() + + return pitchingStatsResponse.stats +} + export function aggregatePitchingStats(pitchingStats: PitchingStat[]): PitchingStat { const totalStat: PitchingStat = { player: pitchingStats[0].player, diff --git a/src/views/GameView.vue b/src/views/GameView.vue new file mode 100644 index 0000000..5c7acff --- /dev/null +++ b/src/views/GameView.vue @@ -0,0 +1,444 @@ + + + \ No newline at end of file diff --git a/src/views/ScheduleView.vue b/src/views/ScheduleView.vue index 9ecd73f..f3695c1 100644 --- a/src/views/ScheduleView.vue +++ b/src/views/ScheduleView.vue @@ -160,7 +160,7 @@ export default { for (let week = 1; week <= 21; week++) { const weekStartDate = currentWeekStartDate - const weekEndDate = this.isLongSeries(week, weekStartDate) + const weekEndDate = this.isLongSeries(weekStartDate) ? currentWeekStartDate.add(13, 'd') : currentWeekStartDate.add(6, 'd') @@ -195,7 +195,7 @@ export default { async fetchData(): Promise { this.weekGames = await fetchGamesBySeasonAndWeek(this.seasonNumber, this.selectedWeekNumber) }, - isLongSeries(weekNumber: number, weekStartDate: dayjs.Dayjs): boolean { + isLongSeries(weekStartDate: dayjs.Dayjs): boolean { // current 18-week schedule has 2 week series for any game week that falls // on the week of Thanksgiving or Christmas return Math.abs(weekStartDate.diff(THANKSGIVING, 'days')) < 6