Compare commits

...

10 Commits

Author SHA1 Message Date
Peter
5768b9f7d2 Site to season 13 2025-11-19 14:39:41 -06:00
Peter
1cf70a9c88 Sort by game id 2025-10-29 09:08:07 -05:00
Peter
642dc6e673 Cutover to new API for local development and fix standings season issue 2025-10-21 08:43:58 -05:00
Cal Corum
16e6099fc3 Import Updates
Updating two type imports caught by build process
2025-07-17 14:30:10 -05:00
Peter
c8e70217f6 Merge branch 'main' of https://github.com/pgiro/sba 2025-07-17 14:00:28 -05:00
Peter
a13ad94558 Fix navbar 2025-07-17 14:00:25 -05:00
Cal Corum
65d7c7c8a1 Update .gitignore
Excluding local build files and Claude directory
2025-07-17 13:32:06 -05:00
Peter
1e0afd634b Add archive to standings page 2025-07-15 16:42:02 -05:00
Peter
4f939e5f08 Add ids to schedule to verify sort 2025-06-30 09:48:06 -05:00
Peter
e12e207e23 Roll site to season 12 2025-05-23 08:43:32 -05:00
23 changed files with 126 additions and 79 deletions

11
.gitignore vendored
View File

@ -26,3 +26,14 @@ coverage
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
CLAUDE.md
.claude/*
*docker*
Dockerfile*
*.py
nginx.conf
scripts/*
public/cards*
.env.prod

View File

@ -5,13 +5,13 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<meta property="og:title" content="SBa Season 11" /> <meta property="og:title" content="SBa Season 13" />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:url" content="https://sba.manticorum.com" /> <meta property="og:url" content="https://sba.manticorum.com" />
<meta property="og:image" content="https://sba.manticorum.com/sba-network.png" /> <meta property="og:image" content="https://sba.manticorum.com/sba-network.png" />
<meta property="og:description" content="The home of the Strat-o-matic Baseball Association" /> <meta property="og:description" content="The home of the Strat-o-matic Baseball Association" />
<meta name="theme-color" content="#A6CE39"> <meta name="theme-color" content="#A6CE39">
<title>SBa Season 11</title> <title>SBa Season 13</title>
</head> </head>
<body> <body>

View File

@ -72,7 +72,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { type Game } from '@/services/apiResponseTypes' import type { Game } from '@/services/apiResponseTypes'
import { fetchPitchingStatsForLastTwoWeeksByTeam, type PitchingStat } from '@/services/pitchingStatsService' import { fetchPitchingStatsForLastTwoWeeksByTeam, type PitchingStat } from '@/services/pitchingStatsService'
import { fetchPlayersByTeam, type Player } from '@/services/playersService' import { fetchPlayersByTeam, type Player } from '@/services/playersService'

View File

@ -26,7 +26,7 @@
<tr v-for="(team, index) in getSortedStandings(division.teamStandings)" :key="index"> <tr v-for="(team, index) in getSortedStandings(division.teamStandings)" :key="index">
<td> <td>
<RouterLink <RouterLink
:to="{ name: 'team', params: { seasonNumber: seasonNumber(), teamAbbreviation: team.teamAbbreviation } }"> :to="{ name: 'team', params: { seasonNumber: team.season, teamAbbreviation: team.teamAbbreviation } }">
{{ team.teamName }} {{ team.teamName }}
</RouterLink> </RouterLink>
</td> </td>
@ -54,7 +54,6 @@
<script lang="ts"> <script lang="ts">
import type { TeamStanding } from '@/services/standingsService' import type { TeamStanding } from '@/services/standingsService'
import { CURRENT_SEASON } from '@/services/utilities'
interface DivisionStub { interface DivisionStub {
name: string name: string
@ -94,9 +93,6 @@ export default {
record(teamStanding: TeamStanding): string { record(teamStanding: TeamStanding): string {
return `${teamStanding.wins}-${teamStanding.losses}` return `${teamStanding.wins}-${teamStanding.losses}`
}, },
seasonNumber(): number {
return CURRENT_SEASON
},
getSortedStandings(teamStandings: TeamStanding[]): TeamStanding[] { getSortedStandings(teamStandings: TeamStanding[]): TeamStanding[] {
if (!teamStandings) return [] if (!teamStandings) return []
return teamStandings.slice() return teamStandings.slice()

View File

@ -1,6 +1,7 @@
<template> <template>
<nav class="navbar navbar-expand-md" style="margin-bottom: 1rem"> <nav class="navbar navbar-expand-md" style="margin-bottom: 1rem">
<RouterLink class="navbar-brand nav-link" style="padding-left: 0;" to="/">SBa Season {{ seasonNumber() }}</RouterLink> <RouterLink class="navbar-brand nav-link" style="padding-left: 0;" to="/">SBa Season {{ seasonNumber() }}
</RouterLink>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#top-navbar-collapse" <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#top-navbar-collapse"
aria-controls="top-navbar-collapse" aria-expanded="false" aria-label="Toggle navigation" aria-controls="top-navbar-collapse" aria-expanded="false" aria-label="Toggle navigation"
@click="setMobileNavBarState(!isMobileNavBarExpanded)"> @click="setMobileNavBarState(!isMobileNavBarExpanded)">
@ -15,7 +16,8 @@
<RouterLink class="nav-link" to="/schedule">Schedule</RouterLink> <RouterLink class="nav-link" to="/schedule">Schedule</RouterLink>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<RouterLink class="nav-link" to="/standings">Standings</RouterLink> <RouterLink class="nav-link" :to="{ name: 'standings', params: { seasonNumber: seasonNumber() } }">Standings
</RouterLink>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<RouterLink class="nav-link" to="/leaderboards">Leaders</RouterLink> <RouterLink class="nav-link" to="/leaderboards">Leaders</RouterLink>
@ -50,7 +52,8 @@
<button class="nav-link" @click="clearCookie">Clear Cookie</button> <button class="nav-link" @click="clearCookie">Clear Cookie</button>
</li> </li>
<li v-if="isAuthenticated && userTeam" class="nav-item"> <li v-if="isAuthenticated && userTeam" class="nav-item">
<RouterLink :to="{ name: 'team', params: { seasonNumber: seasonNumber(), teamAbbreviation: userTeam.abbrev } }"> <RouterLink
:to="{ name: 'team', params: { seasonNumber: seasonNumber(), teamAbbreviation: userTeam.abbrev } }">
<img id="thumbnail" style="max-height: 35px; vertical-align: middle;" :src=userTeam?.thumbnail> <img id="thumbnail" style="max-height: 35px; vertical-align: middle;" :src=userTeam?.thumbnail>
</RouterLink> </RouterLink>
</li> </li>

View File

@ -68,7 +68,8 @@ export default {
return `${teamStanding.wins}-${teamStanding.losses}` return `${teamStanding.wins}-${teamStanding.losses}`
}, },
seasonNumber(): number { seasonNumber(): number {
return CURRENT_SEASON if (!this.teams) return CURRENT_SEASON
return this.teams[0].season
} }
} }
} }

View File

@ -27,9 +27,10 @@ export const routes: RouteRecordRaw[] = [
props: castPlayersRouteParams props: castPlayersRouteParams
}, },
{ {
path: '/standings', path: '/standings/:seasonNumber',
name: 'standings', name: 'standings',
component: () => import('../views/StandingsView.vue') component: () => import('../views/StandingsView.vue'),
props: castStandingsRouteParams
}, },
{ {
path: '/leaderboards', path: '/leaderboards',
@ -86,6 +87,12 @@ function castPlayersRouteParams(route: { params: { playerName: string, seasonNum
} }
} }
function castStandingsRouteParams(route: { params: { seasonNumber: string } }) {
return {
seasonNumber: Number.isNaN(Number.parseInt(route.params.seasonNumber)) ? undefined : Number(route.params.seasonNumber)
}
}
function castScheduleRouteParams(route: { params: { seasonNumber: string, weekNumber: string } }) { function castScheduleRouteParams(route: { params: { seasonNumber: string, weekNumber: string } }) {
return { return {
seasonNumber: Number.isNaN(Number.parseInt(route.params.seasonNumber)) ? undefined : Number(route.params.seasonNumber), seasonNumber: Number.isNaN(Number.parseInt(route.params.seasonNumber)) ? undefined : Number(route.params.seasonNumber),

View File

@ -1,6 +1,6 @@
import type { Manager, Team } from './apiResponseTypes' import type { Manager, Team } from './apiResponseTypes'
import type { Player } from './playersService' import type { Player } from './playersService'
import { SITE_URL } from './utilities' import { API_URL } from './utilities'
export interface Award { export interface Award {
id: number, id: number,
@ -15,7 +15,7 @@ export interface Award {
} }
export async function fetchAwardsByPlayerName(playerName: string): Promise<Award[]> { export async function fetchAwardsByPlayerName(playerName: string): Promise<Award[]> {
const response = await fetch(`${SITE_URL}/api/v3/awards?player_name=${playerName}&timing=off-season`) const response = await fetch(`${API_URL}/awards?player_name=${playerName}&timing=off-season`)
const awardsResponse: { const awardsResponse: {
count: number count: number
@ -26,7 +26,7 @@ export async function fetchAwardsByPlayerName(playerName: string): Promise<Award
} }
export async function fetchAwardsByManagerId(managerId: number): Promise<Award[]> { export async function fetchAwardsByManagerId(managerId: number): Promise<Award[]> {
const response = await fetch(`${SITE_URL}/api/v3/awards?manager_id=${managerId}`) const response = await fetch(`${API_URL}/awards?manager_id=${managerId}`)
const awardsResponse: { const awardsResponse: {
count: number count: number

View File

@ -1,6 +1,6 @@
import type { Game, Team } from './apiResponseTypes' import type { Game, Team } from './apiResponseTypes'
import type { Player } from './playersService' import type { Player } from './playersService'
import { MODERN_STAT_ERA_START, SITE_URL, avg, obp, ops, slg, woba } from './utilities' import { MODERN_STAT_ERA_START, API_URL, avg, obp, ops, slg, woba } from './utilities'
// TODO make a stats object that has properties for current regular season, current post season, // TODO make a stats object that has properties for current regular season, current post season,
// last 4 games, historical seasons, career totals // last 4 games, historical seasons, career totals
@ -71,7 +71,7 @@ export async function fetchBattingStatsBySeason(seasonNumber: number, isRegularS
return [] return []
} }
const response = await fetch(`${SITE_URL}/api/v3/plays/batting?season=${seasonNumber}&group_by=player&limit=1000&s_type=${isRegularSeason ? 'regular' : 'post'}`) const response = await fetch(`${API_URL}/plays/batting?season=${seasonNumber}&group_by=player&limit=1000&s_type=${isRegularSeason ? 'regular' : 'post'}`)
const battingStatsResponse: { const battingStatsResponse: {
count: number count: number
@ -89,7 +89,7 @@ export async function fetchBattingStatsBySeasonAndPlayerId(seasonNumber: number,
return await fetchLegacyBattingStatsBySeasonAndPlayerId(seasonNumber, playerId, isRegularSeason) return await fetchLegacyBattingStatsBySeasonAndPlayerId(seasonNumber, playerId, isRegularSeason)
} }
const response = await fetch(`${SITE_URL}/api/v3/plays/batting?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`) const response = await fetch(`${API_URL}/plays/batting?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`)
const battingStatsResponse: { const battingStatsResponse: {
count: number count: number
@ -111,7 +111,7 @@ export async function fetchBattingStatsBySeasonAndTeamId(seasonNumber: number, t
return [] return []
} }
const response = await fetch(`${SITE_URL}/api/v3/plays/batting?season=${seasonNumber}&team_id=${teamId}&group_by=playerteam&s_type=${isRegularSeason ? 'regular' : 'post'}`) const response = await fetch(`${API_URL}/plays/batting?season=${seasonNumber}&team_id=${teamId}&group_by=playerteam&s_type=${isRegularSeason ? 'regular' : 'post'}`)
const battingStatsResponse: { const battingStatsResponse: {
count: number count: number
@ -130,7 +130,7 @@ export async function fetchTeamBattingStatsBySeason(seasonNumber: number): Promi
return [] return []
} }
const response = await fetch(`${SITE_URL}/api/v3/plays/batting?season=${seasonNumber}&group_by=team&s_type=regular`) const response = await fetch(`${API_URL}/plays/batting?season=${seasonNumber}&group_by=team&s_type=regular`)
const battingStatsResponse: { const battingStatsResponse: {
count: number count: number
@ -143,7 +143,7 @@ export async function fetchTeamBattingStatsBySeason(seasonNumber: number): Promi
} }
async function fetchLegacyBattingStatsBySeasonAndPlayerId(seasonNumber: number, playerId: number, isRegularSeason: boolean): Promise<BattingStat | undefined> { async function fetchLegacyBattingStatsBySeasonAndPlayerId(seasonNumber: number, playerId: number, isRegularSeason: boolean): Promise<BattingStat | undefined> {
const response = await fetch(`${SITE_URL}/api/v3/battingstats/totals?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`) const response = await fetch(`${API_URL}/battingstats/totals?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`)
const legacyBattingStatsResponse: { const legacyBattingStatsResponse: {
count: number count: number
@ -160,7 +160,7 @@ async function fetchLegacyBattingStatsBySeasonAndPlayerId(seasonNumber: number,
} }
export async function fetchBattingStatsForLastFourGamesBySeasonAndPlayerId(seasonNumber: number, playerId: number): Promise<BattingStat[]> { export async function fetchBattingStatsForLastFourGamesBySeasonAndPlayerId(seasonNumber: number, playerId: number): Promise<BattingStat[]> {
const response = await fetch(`${SITE_URL}/api/v3/plays/batting?season=${seasonNumber}&player_id=${playerId}&group_by=playergame&limit=4&s_type=regular&sort=newest`) const response = await fetch(`${API_URL}/plays/batting?season=${seasonNumber}&player_id=${playerId}&group_by=playergame&limit=4&s_type=regular&sort=newest`)
const battingStatsResponse: { const battingStatsResponse: {
count: number count: number
@ -180,7 +180,7 @@ export async function fetchBattingStatsBySeries(seasonNumber: number, weekNumber
return [] 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 response = await fetch(`${API_URL}/plays/batting?season=${seasonNumber}&week=${weekNumber}&team_id=${homeTeamId}&team_id=${awayTeamId}&group_by=playergame`)
const battingStatsResponse: { const battingStatsResponse: {
count: number count: number

View File

@ -1,4 +1,4 @@
import { SITE_URL } from './utilities' import { API_URL } from './utilities'
export interface LeagueInfo { export interface LeagueInfo {
id: number, id: number,
@ -17,7 +17,7 @@ export interface LeagueInfo {
} }
export async function fetchCurrentLeagueInfo(): Promise<LeagueInfo> { export async function fetchCurrentLeagueInfo(): Promise<LeagueInfo> {
const response = await fetch(`${SITE_URL}/api/v3/current`) const response = await fetch(`${API_URL}/current`)
const leagueInfoResponse: LeagueInfo = await response.json() const leagueInfoResponse: LeagueInfo = await response.json()

View File

@ -1,6 +1,6 @@
import type { Game } from './apiResponseTypes' import type { Game } from './apiResponseTypes'
import type { Player } from './playersService' import type { Player } from './playersService'
import { SITE_URL } from './utilities' import { API_URL } from './utilities'
export interface Decision { export interface Decision {
id: number, id: number,
@ -22,7 +22,7 @@ export interface Decision {
} }
export async function fetchLast2DecisionsByPlayerId(seasonNumber: number, playerId: number): Promise<Decision[]> { export async function fetchLast2DecisionsByPlayerId(seasonNumber: number, playerId: number): Promise<Decision[]> {
const response = await fetch(`${SITE_URL}/api/v3/decisions?season=${seasonNumber}&player_id=${playerId}&limit=2`) const response = await fetch(`${API_URL}/decisions?season=${seasonNumber}&player_id=${playerId}&limit=2`)
const decisionsResponse: { const decisionsResponse: {
count: number count: number

View File

@ -1,6 +1,6 @@
import type { Game, Team } from './apiResponseTypes' import type { Game, Team } from './apiResponseTypes'
import type { Player } from './playersService' import type { Player } from './playersService'
import { MODERN_STAT_ERA_START, SITE_URL, isNotUndefined } from './utilities' import { MODERN_STAT_ERA_START, API_URL, isNotUndefined } from './utilities'
// TODO make a stats object that has properties for current regular season, current post season, // TODO make a stats object that has properties for current regular season, current post season,
// last 4 games, historical seasons, career totals // last 4 games, historical seasons, career totals
@ -58,7 +58,7 @@ export async function fetchFieldingStatsBySeasonAndPlayerId(seasonNumber: number
return await fetchLegacyFieldingStatsBySeasonAndPlayerId(seasonNumber, playerId, isRegularSeason) return await fetchLegacyFieldingStatsBySeasonAndPlayerId(seasonNumber, playerId, isRegularSeason)
} }
const response = await fetch(`${SITE_URL}/api/v3/plays/fielding?season=${seasonNumber}&player_id=${playerId}&group_by=playerposition&s_type=${isRegularSeason ? 'regular' : 'post'}`) const response = await fetch(`${API_URL}/plays/fielding?season=${seasonNumber}&player_id=${playerId}&group_by=playerposition&s_type=${isRegularSeason ? 'regular' : 'post'}`)
const fieldingStatsResponse: { const fieldingStatsResponse: {
count: number count: number
@ -77,7 +77,7 @@ export async function fetchFieldingStatsBySeasonAndTeamId(seasonNumber: number,
} }
// TODO might want to make this playerpositionteam grouping (currently does not exist) // TODO might want to make this playerpositionteam grouping (currently does not exist)
const response = await fetch(`${SITE_URL}/api/v3/plays/fielding?season=${seasonNumber}&team_id=${teamId}&group_by=playerposition&s_type=${isRegularSeason ? 'regular' : 'post'}`) const response = await fetch(`${API_URL}/plays/fielding?season=${seasonNumber}&team_id=${teamId}&group_by=playerposition&s_type=${isRegularSeason ? 'regular' : 'post'}`)
const fieldingStatsResponse: { const fieldingStatsResponse: {
count: number count: number
@ -96,7 +96,7 @@ export async function fetchTeamFieldingStatsBySeason(seasonNumber: number): Prom
} }
// TODO might want to make this playerpositionteam grouping (currently does not exist) // TODO might want to make this playerpositionteam grouping (currently does not exist)
const response = await fetch(`${SITE_URL}/api/v3/plays/fielding?season=${seasonNumber}&group_by=team&s_type=regular`) const response = await fetch(`${API_URL}/plays/fielding?season=${seasonNumber}&group_by=team&s_type=regular`)
const fieldingStatsResponse: { const fieldingStatsResponse: {
count: number count: number
@ -114,7 +114,7 @@ export async function fetchFieldingStatsBySeason(seasonNumber: number, isRegular
return [] return []
} }
const response = await fetch(`${SITE_URL}/api/v3/plays/fielding?season=${seasonNumber}&limit=10000&group_by=playerposition&s_type=${isRegularSeason ? 'regular' : 'post'}`) const response = await fetch(`${API_URL}/plays/fielding?season=${seasonNumber}&limit=10000&group_by=playerposition&s_type=${isRegularSeason ? 'regular' : 'post'}`)
const fieldingStatsResponse: { const fieldingStatsResponse: {
count: number count: number
@ -127,7 +127,7 @@ export async function fetchFieldingStatsBySeason(seasonNumber: number, isRegular
} }
async function fetchLegacyFieldingStatsBySeasonAndPlayerId(seasonNumber: number, playerId: number, isRegularSeason: boolean): Promise<FieldingStat[]> { async function fetchLegacyFieldingStatsBySeasonAndPlayerId(seasonNumber: number, playerId: number, isRegularSeason: boolean): Promise<FieldingStat[]> {
const response = await fetch(`${SITE_URL}/api/v3/fieldingstats/totals?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`) const response = await fetch(`${API_URL}/fieldingstats/totals?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`)
const legacyFieldingStatsResponse: { const legacyFieldingStatsResponse: {
count: number count: number
@ -142,7 +142,7 @@ async function fetchLegacyFieldingStatsBySeasonAndPlayerId(seasonNumber: number,
} }
export async function fetchFieldingStatsForLastFourGamesBySeasonAndPlayerId(seasonNumber: number, playerId: number): Promise<FieldingStat[]> { export async function fetchFieldingStatsForLastFourGamesBySeasonAndPlayerId(seasonNumber: number, playerId: number): Promise<FieldingStat[]> {
const response = await fetch(`${SITE_URL}/api/v3/plays/fielding?season=${seasonNumber}&player_id=${playerId}&group_by=playerpositiongame&limit=4&s_type=regular&sort=newest`) const response = await fetch(`${API_URL}/plays/fielding?season=${seasonNumber}&player_id=${playerId}&group_by=playerpositiongame&limit=4&s_type=regular&sort=newest`)
const fieldingStatsResponse: { const fieldingStatsResponse: {
count: number count: number
@ -162,7 +162,7 @@ export async function fetchFieldingStatsBySeries(seasonNumber: number, weekNumbe
return [] 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 response = await fetch(`${API_URL}/plays/fielding?season=${seasonNumber}&week=${weekNumber}&team_id=${homeTeamId}&team_id=${awayTeamId}&group_by=playerpositiongame`)
const fieldingStatsResponse: { const fieldingStatsResponse: {
count: number count: number

View File

@ -1,5 +1,5 @@
import type { Game } from './apiResponseTypes' import type { Game } from './apiResponseTypes'
import { MODERN_STAT_ERA_START, SITE_URL } from './utilities' import { MODERN_STAT_ERA_START, API_URL } from './utilities'
export async function fetchGamesBySeasonAndTeamId(seasonNumber: number, teamId: number): Promise<Game[]> { export async function fetchGamesBySeasonAndTeamId(seasonNumber: number, teamId: number): Promise<Game[]> {
if (seasonNumber < MODERN_STAT_ERA_START) { if (seasonNumber < MODERN_STAT_ERA_START) {
@ -7,7 +7,7 @@ export async function fetchGamesBySeasonAndTeamId(seasonNumber: number, teamId:
return [] return []
} }
const response = await fetch(`${SITE_URL}/api/v3/games?season=${seasonNumber}&team1_id=${teamId}&team2_id=${teamId}&season_type=regular`) const response = await fetch(`${API_URL}/games?season=${seasonNumber}&team1_id=${teamId}&team2_id=${teamId}&season_type=regular`)
const gamesResponse: { const gamesResponse: {
count: number count: number
@ -23,7 +23,7 @@ export async function fetchGamesBySeasonAndWeek(seasonNumber: number, weekNumber
return [] return []
} }
const response = await fetch(`${SITE_URL}/api/v3/games?season=${seasonNumber}&week=${weekNumber}`) const response = await fetch(`${API_URL}/games?season=${seasonNumber}&week=${weekNumber}`)
const gamesResponse: { const gamesResponse: {
count: number count: number
@ -39,7 +39,7 @@ export async function fetchSingleGame(seasonNumber: number, weekNumber: number,
return undefined 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 response = await fetch(`${API_URL}/games?season=${seasonNumber}&week=${weekNumber}&game_num=${gameNumber}&team1_id=${homeTeamId}&team2_id=${awayTeamId}`)
const gamesResponse: { const gamesResponse: {
count: number count: number

View File

@ -1,5 +1,5 @@
import type { Manager } from './apiResponseTypes' import type { Manager } from './apiResponseTypes'
import { SITE_URL } from './utilities' import { API_URL } from './utilities'
export async function fetchActiveManagers(): Promise<Manager[]> { export async function fetchActiveManagers(): Promise<Manager[]> {
return await fetchManagers(true) return await fetchManagers(true)
@ -10,7 +10,7 @@ export async function fetchRetiredManagers(): Promise<Manager[]> {
} }
async function fetchManagers(active: boolean): Promise<Manager[]> { async function fetchManagers(active: boolean): Promise<Manager[]> {
const response = await fetch(`${SITE_URL}/api/v3/managers?active=${active}&short_output=true`) const response = await fetch(`${API_URL}/managers?active=${active}&short_output=true`)
const managersResponse: { const managersResponse: {
count: number count: number

View File

@ -1,6 +1,6 @@
import type { Game, Team } from './apiResponseTypes' import type { Game, Team } from './apiResponseTypes'
import type { Player } from './playersService' import type { Player } from './playersService'
import { MODERN_STAT_ERA_START, SITE_URL, avg, slg, woba } from './utilities' import { MODERN_STAT_ERA_START, API_URL, avg, slg, woba } from './utilities'
// TODO make a stats object that has properties for current regular season, current post season, // TODO make a stats object that has properties for current regular season, current post season,
// last 4 games, historical seasons, career totals // last 4 games, historical seasons, career totals
@ -138,7 +138,7 @@ export async function fetchPitchingStatsBySeasonAndPlayerId(seasonNumber: number
return await fetchLegacyPitchingStatsBySeasonAndPlayerId(seasonNumber, playerId, isRegularSeason) return await fetchLegacyPitchingStatsBySeasonAndPlayerId(seasonNumber, playerId, isRegularSeason)
} }
const response = await fetch(`${SITE_URL}/api/v3/plays/pitching?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`) const response = await fetch(`${API_URL}/plays/pitching?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`)
const pitchingStatsResponse: { const pitchingStatsResponse: {
count: number count: number
@ -160,7 +160,7 @@ export async function fetchPitchingStatsBySeasonAndTeamId(seasonNumber: number,
return [] return []
} }
const response = await fetch(`${SITE_URL}/api/v3/plays/pitching?season=${seasonNumber}&team_id=${teamId}&group_by=playerteam&s_type=${isRegularSeason ? 'regular' : 'post'}`) const response = await fetch(`${API_URL}/plays/pitching?season=${seasonNumber}&team_id=${teamId}&group_by=playerteam&s_type=${isRegularSeason ? 'regular' : 'post'}`)
const pitchingStatsResponse: { const pitchingStatsResponse: {
count: number count: number
@ -178,7 +178,7 @@ export async function fetchTeamPitchingStatsBySeason(seasonNumber: number): Prom
return [] return []
} }
const response = await fetch(`${SITE_URL}/api/v3/plays/pitching?season=${seasonNumber}&group_by=team&s_type=regular`) const response = await fetch(`${API_URL}/plays/pitching?season=${seasonNumber}&group_by=team&s_type=regular`)
const pitchingStatsResponse: { const pitchingStatsResponse: {
count: number count: number
@ -197,7 +197,7 @@ export async function fetchPitchingStatsBySeason(seasonNumber: number, isRegular
return [] return []
} }
const response = await fetch(`${SITE_URL}/api/v3/plays/pitching?season=${seasonNumber}&group_by=player&limit=1000&s_type=${isRegularSeason ? 'regular' : 'post'}`) const response = await fetch(`${API_URL}/plays/pitching?season=${seasonNumber}&group_by=player&limit=1000&s_type=${isRegularSeason ? 'regular' : 'post'}`)
const pitchingStatsResponse: { const pitchingStatsResponse: {
count: number count: number
@ -210,7 +210,7 @@ export async function fetchPitchingStatsBySeason(seasonNumber: number, isRegular
} }
async function fetchLegacyPitchingStatsBySeasonAndPlayerId(seasonNumber: number, playerId: number, isRegularSeason: boolean): Promise<PitchingStat | undefined> { async function fetchLegacyPitchingStatsBySeasonAndPlayerId(seasonNumber: number, playerId: number, isRegularSeason: boolean): Promise<PitchingStat | undefined> {
const response = await fetch(`${SITE_URL}/api/v3/pitchingstats/totals?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`) const response = await fetch(`${API_URL}/pitchingstats/totals?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`)
const legacyPitchingStatsResponse: { const legacyPitchingStatsResponse: {
count: number count: number
@ -227,7 +227,7 @@ async function fetchLegacyPitchingStatsBySeasonAndPlayerId(seasonNumber: number,
} }
export async function fetchPitchingStatsForLastFourGamesBySeasonAndPlayerId(seasonNumber: number, playerId: number): Promise<PitchingStat[]> { export async function fetchPitchingStatsForLastFourGamesBySeasonAndPlayerId(seasonNumber: number, playerId: number): Promise<PitchingStat[]> {
const response = await fetch(`${SITE_URL}/api/v3/plays/pitching?season=${seasonNumber}&player_id=${playerId}&group_by=playergame&limit=4&s_type=regular&sort=newest`) const response = await fetch(`${API_URL}/plays/pitching?season=${seasonNumber}&player_id=${playerId}&group_by=playergame&limit=4&s_type=regular&sort=newest`)
const pitchingStatsResponse: { const pitchingStatsResponse: {
count: number count: number
@ -247,7 +247,7 @@ export async function fetchPitchingStatsForLastTwoWeeksByTeam(seasonNumber: numb
return [] return []
} }
const response = await fetch(`${SITE_URL}/api/v3/plays/pitching?season=${seasonNumber}&week_start=${weekNumber - 1}&week_end=${weekNumber}&team_id=${teamId}&group_by=playergame`) const response = await fetch(`${API_URL}/plays/pitching?season=${seasonNumber}&week_start=${weekNumber - 1}&week_end=${weekNumber}&team_id=${teamId}&group_by=playergame`)
const pitchingStatsResponse: { const pitchingStatsResponse: {
count: number count: number
@ -263,7 +263,7 @@ export async function fetchPitchingStatsBySeries(seasonNumber: number, weekNumbe
return [] 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 response = await fetch(`${API_URL}/plays/pitching?season=${seasonNumber}&week=${weekNumber}&team_id=${homeTeamId}&team_id=${awayTeamId}&group_by=playergame`)
const pitchingStatsResponse: { const pitchingStatsResponse: {
count: number count: number

View File

@ -1,5 +1,5 @@
import type { Team } from './apiResponseTypes' import type { Team } from './apiResponseTypes'
import { SITE_URL } from './utilities' import { API_URL } from './utilities'
export interface Player { export interface Player {
bbref_id: string bbref_id: string
@ -30,7 +30,7 @@ export interface Player {
} }
export async function fetchPlayers(seasonNumber: number): Promise<Player[]> { export async function fetchPlayers(seasonNumber: number): Promise<Player[]> {
const response = await fetch(`${SITE_URL}/api/v3/players?season=${seasonNumber}`) const response = await fetch(`${API_URL}/players?season=${seasonNumber}`)
const playersResponse: { const playersResponse: {
count: number count: number
@ -42,7 +42,7 @@ export async function fetchPlayers(seasonNumber: number): Promise<Player[]> {
// TODO should/can this use team abbrev instead of id? // TODO should/can this use team abbrev instead of id?
export async function fetchPlayersByTeam(seasonNumber: number, teamId: number): Promise<Player[]> { export async function fetchPlayersByTeam(seasonNumber: number, teamId: number): Promise<Player[]> {
const response = await fetch(`${SITE_URL}/api/v3/players?season=${seasonNumber}&team_id=${teamId}`) const response = await fetch(`${API_URL}/players?season=${seasonNumber}&team_id=${teamId}`)
const playersResponse: { const playersResponse: {
count: number count: number
@ -53,7 +53,7 @@ export async function fetchPlayersByTeam(seasonNumber: number, teamId: number):
} }
export async function fetchPlayerByName(seasonNumber: number, playerName: string): Promise<Player | undefined> { export async function fetchPlayerByName(seasonNumber: number, playerName: string): Promise<Player | undefined> {
const response = await fetch(`${SITE_URL}/api/v3/players?season=${seasonNumber}&name=${playerName}`) const response = await fetch(`${API_URL}/players?season=${seasonNumber}&name=${playerName}`)
const playersResponse: { const playersResponse: {
count: number count: number

View File

@ -1,5 +1,5 @@
import type { Team } from './apiResponseTypes' import type { Team } from './apiResponseTypes'
import { SITE_URL } from './utilities' import { API_URL } from './utilities'
interface TeamStandingRaw { interface TeamStandingRaw {
away_losses: number away_losses: number
@ -62,7 +62,7 @@ export interface TeamStanding {
} }
export async function fetchStandings(seasonNumber: number): Promise<TeamStanding[]> { export async function fetchStandings(seasonNumber: number): Promise<TeamStanding[]> {
const response = await fetch(`${SITE_URL}/api/v3/standings?season=${seasonNumber}`) const response = await fetch(`${API_URL}/standings?season=${seasonNumber}`)
const standingsResponse: { const standingsResponse: {
count: number count: number
@ -74,7 +74,7 @@ export async function fetchStandings(seasonNumber: number): Promise<TeamStanding
} }
export async function fetchStandingByTeam(team: Team): Promise<TeamStanding | undefined> { export async function fetchStandingByTeam(team: Team): Promise<TeamStanding | undefined> {
const response = await fetch(`${SITE_URL}/api/v3/standings?season=${team.season}`) const response = await fetch(`${API_URL}/standings?season=${team.season}`)
const standingsResponse: { const standingsResponse: {
count: number count: number

View File

@ -1,8 +1,8 @@
import type { Team } from './apiResponseTypes' import type { Team } from './apiResponseTypes'
import { CURRENT_SEASON, SITE_URL } from './utilities' import { CURRENT_SEASON, API_URL } from './utilities'
export async function fetchTeam(seasonNumber: number, teamAbbreviation: string): Promise<Team> { export async function fetchTeam(seasonNumber: number, teamAbbreviation: string): Promise<Team> {
const response = await fetch(`${SITE_URL}/api/v3/teams?season=${seasonNumber}&team_abbrev=${teamAbbreviation}`) const response = await fetch(`${API_URL}/teams?season=${seasonNumber}&team_abbrev=${teamAbbreviation}`)
const teamResponse: { const teamResponse: {
count: number count: number
@ -17,7 +17,7 @@ export async function fetchTeam(seasonNumber: number, teamAbbreviation: string):
} }
export async function fetchTeamsByManagerId(managerId: number): Promise<Team[]> { export async function fetchTeamsByManagerId(managerId: number): Promise<Team[]> {
const response = await fetch(`${SITE_URL}/api/v3/teams?manager_id=${managerId}`) const response = await fetch(`${API_URL}/teams?manager_id=${managerId}`)
const teamResponse: { const teamResponse: {
count: number count: number
@ -29,7 +29,7 @@ export async function fetchTeamsByManagerId(managerId: number): Promise<Team[]>
export async function fetchActiveTeamByOwnerId(ownerId: string): Promise<Team | undefined> { export async function fetchActiveTeamByOwnerId(ownerId: string): Promise<Team | undefined> {
const response = await fetch(`${SITE_URL}/api/v3/teams?season=${CURRENT_SEASON}&active_only=True&owner_id=${ownerId}`) const response = await fetch(`${API_URL}/teams?season=${CURRENT_SEASON}&active_only=True&owner_id=${ownerId}`)
const teamResponse: { const teamResponse: {
count: number count: number
@ -45,7 +45,7 @@ export async function fetchActiveTeamByOwnerId(ownerId: string): Promise<Team |
} }
export async function fetchTeamsBySeason(season: number): Promise<Team[]> { export async function fetchTeamsBySeason(season: number): Promise<Team[]> {
const response = await fetch(`${SITE_URL}/api/v3/teams?season=${season}&short_output=False`) const response = await fetch(`${API_URL}/teams?season=${season}&short_output=False`)
const teamResponse: { const teamResponse: {
count: number count: number

View File

@ -1,6 +1,6 @@
import type { Team } from './apiResponseTypes' import type { Team } from './apiResponseTypes'
import type { Player } from './playersService' import type { Player } from './playersService'
import { CURRENT_SEASON, SITE_URL } from './utilities' import { CURRENT_SEASON, API_URL } from './utilities'
export interface Transaction { export interface Transaction {
id: number id: number
@ -15,7 +15,7 @@ export interface Transaction {
} }
export async function fetchTransactionsByTeamAndWeek(seasonNumber: number, teamAbbreviation: string, weekNumber: number): Promise<Transaction[]> { export async function fetchTransactionsByTeamAndWeek(seasonNumber: number, teamAbbreviation: string, weekNumber: number): Promise<Transaction[]> {
const response = await fetch(`${SITE_URL}/api/v3/transactions?season=${seasonNumber}&team_abbrev=${teamAbbreviation}&week_start=${weekNumber}&week_end=${weekNumber}`) const response = await fetch(`${API_URL}/transactions?season=${seasonNumber}&team_abbrev=${teamAbbreviation}&week_start=${weekNumber}&week_end=${weekNumber}`)
const transactionsResponse: { const transactionsResponse: {
count: number count: number
@ -26,7 +26,7 @@ export async function fetchTransactionsByTeamAndWeek(seasonNumber: number, teamA
} }
export async function fetchTransactionsByWeek(seasonNumber: number, weekNumber: number): Promise<Transaction[]> { export async function fetchTransactionsByWeek(seasonNumber: number, weekNumber: number): Promise<Transaction[]> {
const response = await fetch(`${SITE_URL}/api/v3/transactions?season=${seasonNumber}&week_start=${weekNumber}&week_end=${weekNumber}`) const response = await fetch(`${API_URL}/transactions?season=${seasonNumber}&week_start=${weekNumber}&week_end=${weekNumber}`)
const transactionsResponse: { const transactionsResponse: {
count: number count: number
@ -37,7 +37,7 @@ export async function fetchTransactionsByWeek(seasonNumber: number, weekNumber:
} }
export async function fetchTransactionsForCurrentSeasonByPlayerName(playerName: string): Promise<Transaction[]> { export async function fetchTransactionsForCurrentSeasonByPlayerName(playerName: string): Promise<Transaction[]> {
const response = await fetch(`${SITE_URL}/api/v3/transactions?season=${CURRENT_SEASON}&player_name=${playerName}`) const response = await fetch(`${API_URL}/transactions?season=${CURRENT_SEASON}&player_name=${playerName}`)
const transactionsResponse: { const transactionsResponse: {
count: number count: number

View File

@ -4,7 +4,9 @@ dayjs.extend(customParseFormat)
export const SITE_URL = 'https://sba.manticorum.com' export const SITE_URL = 'https://sba.manticorum.com'
export const CURRENT_SEASON = 11 export const API_URL = 'https://api.sba.manticorum.com'
export const CURRENT_SEASON = 13
export const MODERN_STAT_ERA_START = 8 export const MODERN_STAT_ERA_START = 8
@ -15,10 +17,9 @@ export const WEEKS_PER_SEASON = 18
export const GAMES_PER_SEASON = GAMES_PER_WEEK * WEEKS_PER_SEASON export const GAMES_PER_SEASON = GAMES_PER_WEEK * WEEKS_PER_SEASON
// TODO: Annually update this start date and holidays with two week series or get it from the DB // TODO: Annually update this start date and holidays with two week series or get it from the DB
export const SEASON_START_DATE: dayjs.Dayjs = dayjs('12-16-2024', 'MM/DD/YYYY') export const SEASON_START_DATE: dayjs.Dayjs = dayjs('2025-12-15')
export const THANKSGIVING: dayjs.Dayjs = dayjs('11-27-2025', 'MM/DD/YYYY') export const THANKSGIVING: dayjs.Dayjs = dayjs('2026-11-26')
export const CHRISTMAS: dayjs.Dayjs = dayjs('12-25-2024', 'MM/DD/YYYY') export const CHRISTMAS: dayjs.Dayjs = dayjs('2025-12-25')
export const POS_MAP = { export const POS_MAP = {
'P': 1, 'P': 1,

View File

@ -24,8 +24,9 @@
<th style="width: 3rem">Home</th> <th style="width: 3rem">Home</th>
</tr> </tr>
</thead> </thead>
<tbody id="matchup-1"> <tbody :id="`matchup-${index}`">
<tr v-for="game in matchup" :key="game.id"> <tr v-for="game in matchup.sort((g1, g2) => g1.id - g2.id)" :key="game.id"
:id="`game-id-${game.id}`">
<td> <td>
<RouterLink <RouterLink
:to="{ name: 'team', params: { seasonNumber: seasonNumber, teamAbbreviation: game.away_team.abbrev } }" :to="{ name: 'team', params: { seasonNumber: seasonNumber, teamAbbreviation: game.away_team.abbrev } }"

View File

@ -8,7 +8,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="col-sm-12">
<h2 id="week-num">{{ weekNumber ? `Week ${weekNumber}` : '' }}</h2> <h2 v-if="isCurrentSeason" id="week-num">{{ weekNumber ? `Week ${weekNumber}` : '' }}</h2>
</div> </div>
</div> </div>
@ -37,6 +37,18 @@
<ExtendedStandingsTable :teamsByDivision="standingsByDivision" /> <ExtendedStandingsTable :teamsByDivision="standingsByDivision" />
</div> </div>
</div> </div>
<h3>
Standings Archive
</h3>
<span v-for="season in currentSeason" :key="season" style="padding-right: 1ch;">
<RouterLink v-if="season != seasonNumber" :to="{ name: 'standings', params: { seasonNumber: season } }">
S{{ season }}
</RouterLink>
<template v-else>
S{{ season }}
</template>
</span>
<div style="padding-bottom: 1em;"></div>
</div> </div>
</main> </main>
</template> </template>
@ -56,22 +68,37 @@ export default {
}, },
data() { data() {
return { return {
seasonNumber: CURRENT_SEASON as number, currentSeason: CURRENT_SEASON,
weekNumber: undefined as number | undefined, weekNumber: undefined as number | undefined,
teamStandings: [] as TeamStanding[], teamStandings: [] as TeamStanding[],
wildcardTeams: [] as TeamStanding[], wildcardTeams: [] as TeamStanding[],
standingsByDivision: [[]] as TeamStanding[][] standingsByDivision: [[]] as TeamStanding[][]
} }
}, },
props: {
seasonNumber: { type: Number, default: CURRENT_SEASON }
},
created() { created() {
this.fetchData() this.fetchData()
}, },
computed: {
isCurrentSeason(): boolean {
return this.seasonNumber == CURRENT_SEASON
}
},
watch: {
seasonNumber(newValue, oldValue) {
if (newValue !== oldValue) {
this.fetchData()
}
}
},
methods: { methods: {
async fetchData(): Promise<void> { async fetchData(): Promise<void> {
const leagueInfo: LeagueInfo = await fetchCurrentLeagueInfo() const leagueInfo: LeagueInfo = await fetchCurrentLeagueInfo()
this.weekNumber = leagueInfo.week this.weekNumber = leagueInfo.week
this.teamStandings = await fetchStandings(CURRENT_SEASON) this.teamStandings = await fetchStandings(this.seasonNumber)
this.wildcardTeams = this.teamStandings.filter(ts => ts.isWildcardTeam) this.wildcardTeams = this.teamStandings.filter(ts => ts.isWildcardTeam)
const teamStandingsByDivisionAbbreviation: { [key: string]: TeamStanding[] } = {} const teamStandingsByDivisionAbbreviation: { [key: string]: TeamStanding[] } = {}

View File

@ -106,7 +106,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { type Team } from '@/services/apiResponseTypes' import type { Team } from '@/services/apiResponseTypes'
import { type LeagueInfo, fetchCurrentLeagueInfo } from '@/services/currentService' import { type LeagueInfo, fetchCurrentLeagueInfo } from '@/services/currentService'
import { fetchTransactionsByWeek, type Transaction } from '@/services/transactionsService' import { fetchTransactionsByWeek, type Transaction } from '@/services/transactionsService'
import { CURRENT_SEASON } from '@/services/utilities' import { CURRENT_SEASON } from '@/services/utilities'