Manager tables and record

This commit is contained in:
Peter 2024-01-04 21:07:13 -05:00
parent 01567e3aee
commit ffa76ceb99
5 changed files with 162 additions and 100 deletions

View File

@ -37,7 +37,7 @@ import { CURRENT_SEASON } from '@/services/utilities'
export default { export default {
name: "StandingsTable", name: 'StandingsTable',
props: { props: {
teams: { teams: {
type: Array<TeamStanding>, type: Array<TeamStanding>,

View File

@ -24,3 +24,14 @@ export async function fetchAwardsByPlayerName(playerName: string): Promise<Award
return awardsResponse.awards return awardsResponse.awards
} }
export async function fetchAwardsByManagerId(managerId: number): Promise<Award[]> {
const response = await fetch(`${SITE_URL}/api/v3/awards?manager_id=${managerId}`)
const awardsResponse: {
count: number
awards: Award[]
} = await response.json()
return awardsResponse.awards
}

View File

@ -34,6 +34,7 @@ interface TeamStandingRaw {
} }
export interface TeamStanding { export interface TeamStanding {
season: number
teamName: string teamName: string
teamAbbreviation: string teamAbbreviation: string
divisionAbbreviation: string divisionAbbreviation: string
@ -63,6 +64,26 @@ export async function fetchStandings(seasonNumber: number): Promise<TeamStanding
return standings.map(normalizeStanding) return standings.map(normalizeStanding)
} }
export async function fetchStandingByTeam(team: Team): Promise<TeamStanding | undefined> {
const response = await fetch(`${SITE_URL}/api/v3/standings?season=${team.season}`)
const standingsResponse: {
count: number
standings: TeamStandingRaw[]
} = await response.json()
const standings: TeamStandingRaw[] = standingsResponse.standings
const teamStanding: TeamStandingRaw | undefined = standings.find(ts => ts.team.sname === team.sname)
if (!teamStanding) {
// throw new Error('standingsService.fetchStandingByTeam - Expected one team standing, found none')
console.warn('standingsService.fetchStandingByTeam - Expected one team standing, found none')
return undefined
}
return normalizeStanding(teamStanding)
}
function normalizeStanding(standing: TeamStandingRaw): TeamStanding { function normalizeStanding(standing: TeamStandingRaw): TeamStanding {
const totalGamesPlayed = standing.wins + standing.losses const totalGamesPlayed = standing.wins + standing.losses
// round win percentage to 3 decimal places // round win percentage to 3 decimal places
@ -72,6 +93,7 @@ function normalizeStanding(standing: TeamStandingRaw): TeamStanding {
const isWildcardTeam = standing.wc_gb !== null || standing.wc_e_num !== null const isWildcardTeam = standing.wc_gb !== null || standing.wc_e_num !== null
return { return {
season: standing.team.season,
teamName: standing.team.sname, teamName: standing.team.sname,
teamAbbreviation: standing.team.abbrev, teamAbbreviation: standing.team.abbrev,
divisionAbbreviation: standing.team.division.division_abbrev, divisionAbbreviation: standing.team.division.division_abbrev,

View File

@ -16,6 +16,18 @@ export async function fetchTeam(seasonNumber: number, teamAbbreviation: string):
return teamResponse.teams[0] return teamResponse.teams[0]
} }
export async function fetchTeamsByManagerId(managerId: number): Promise<Team[]> {
const response = await fetch(`${SITE_URL}/api/v3/teams?manager_id=${managerId}`)
const teamResponse: {
count: number
teams: Team[]
} = await response.json()
return teamResponse.teams
}
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(`${SITE_URL}/api/v3/teams?season=${CURRENT_SEASON}&active_only=True&owner_id=${ownerId}`)

View File

@ -32,128 +32,133 @@
<h1 id="manager-name">{{ managerName }}</h1> <h1 id="manager-name">{{ managerName }}</h1>
</div> </div>
<div>🚧 Coming Soon 🚧</div> <div class="col-sm-12" v-if="managerModel">
</div> <!-- <h3 id="manager-record">Manager Record: {{ managerModel.managerWins }}-{{ managerModel.managerLosses }}</h3> -->
<h3 id="manager-record">Career Record: {{ managerModel.teamWins }}-{{ managerModel.teamLosses }}</h3>
</div>
<!-- <div class="col-sm-12"> <div class="row">
<h3 id="manager-record">Career Record: 294-218</h3> <div class="col-sm-4">
</div> <h3 style="text-align: center">Teams Managed</h3>
<div class="table-responsive-xl">
<table style="text-align: center" class="table table-sm table-striped" id="manager-teams-table">
<thead class="thead-dark">
<tr>
<th>Season</th>
<th>Team</th>
<th>Record</th>
</tr>
</thead>
<tbody>
<tr v-for="row in teamsManagedRows" :key="row.season">
<td>{{ row.season }}</td>
<td>
<RouterLink
:to="{ name: 'team', params: { seasonNumber: row.season, teamAbbreviation: row.teamAbbreviation } }">
{{ row.teamName }}
</RouterLink>
</td>
<td>{{ row.record }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-sm-12"> <div class="col-sm-5">
<p id="manager-headline"></p> <h3 style="text-align: center">Awards Received</h3>
</div> <div class="table-responsive-xl">
</div> <table style="text-align: center" class="table table-sm table-striped" id="manager-awards-table">
<thead class="thead-dark">
<div class="row"> <tr>
<div class="col-sm-4"> <th>Season</th>
<h3 style="text-align: center">Teams Managed</h3> <th>Award</th>
<div class="table-responsive-xl"> <th>Team</th>
<table style="text-align: center" class="table table-sm table-striped" id="manager-teams-table"> </tr>
<thead class="thead-dark"> </thead>
<tr> <tbody>
<th>Season</th> <tr v-for="award in managerAwards.slice().sort((a1, a2) => a2.season - a1.season)" :key="award.id">
<th>Team</th> <td>{{ award.season }}</td>
<th>Record</th> <td>{{ award.name }}</td>
</tr> <td>
<tr> <RouterLink
<td>7</td> :to="{ name: 'team', params: { seasonNumber: award.season, teamAbbreviation: award.team!.abbrev } }">
<td><a href="/teams?abbrev=TK&amp;season=7">Tokyo Kaiju</a></td> {{ award.team!.sname }}
<td id="season-7-record">47-41</td> </RouterLink>
</tr> </td>
<tr> </tr>
<td>6</td> </tbody>
<td><a href="/teams?abbrev=TK&amp;season=6">Tokyo Kaiju</a></td> </table>
<td id="season-6-record">51-37</td> </div>
</tr> </div>
<tr>
<td>5</td>
<td><a href="/teams?abbrev=TK&amp;season=5">Tokyo Kaiju</a></td>
<td id="season-5-record">55-33</td>
</tr>
<tr>
<td>4</td>
<td><a href="/teams?abbrev=TK&amp;season=4">Tokyo Kaiju</a></td>
<td id="season-4-record">55-33</td>
</tr>
<tr>
<td>3</td>
<td><a href="/teams?abbrev=TK&amp;season=3">Tokyo Kaiju</a></td>
<td id="season-3-record">49-39</td>
</tr>
<tr>
<td>2</td>
<td><a href="/teams?abbrev=TK&amp;season=2">Tokyo Kaiju</a></td>
<td id="season-2-record">37-35</td>
</tr>
</thead>
<tbody id="manager-teams"></tbody>
</table>
</div> </div>
</div> </div>
<div class="col-sm-5">
<h3 style="text-align: center">Awards Received</h3>
<div class="table-responsive-xl">
<table style="text-align: center" class="table table-sm table-striped" id="manager-awards-table">
<thead class="thead-dark">
<tr>
<th>Season</th>
<th>Award</th>
<th>Extras</th>
</tr>
<tr>
<td>3</td>
<td>AL Wildcard</td>
<td><a href="/teams?abbrev=TK&amp;season=3">Tokyo Kaiju</a></td>
</tr>
<tr>
<td>2</td>
<td>Most Hated Ballpark</td>
<td><a href="/teams?abbrev=TK&amp;season=2">Tokyo Kaiju</a></td>
</tr>
<tr>
<td>2</td>
<td>American League Pennant</td>
<td><a href="/teams?abbrev=TK&amp;season=2">Tokyo Kaiju</a></td>
</tr>
<tr>
<td>2</td>
<td>AL East Leader</td>
<td><a href="/teams?abbrev=TK&amp;season=2">Tokyo Kaiju</a></td>
</tr>
</thead>
<tbody id="manager-awards"></tbody>
</table>
</div>
</div> -->
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import type { Manager } from '@/services/apiResponseTypes' import type { Manager, Team } from '@/services/apiResponseTypes'
import type { Award } from '@/services/awardsService'
import { fetchActiveManagers, fetchRetiredManagers } from '@/services/managerService' import { fetchActiveManagers, fetchRetiredManagers } from '@/services/managerService'
import { fetchTeamsByManagerId } from '@/services/teamsService'
import { fetchAwardsByManagerId } from '@/services/awardsService'
import { fetchStandingByTeam, type TeamStanding } from '@/services/standingsService'
import { isNotUndefined } from '@/services/utilities'
interface ManagerModel {
managerWins: number
managerLosses: number
teamWins: number
teamLosses: number
}
export default { export default {
name: 'ManagerView', name: 'ManagerView',
data() { data() {
return { return {
activeManagers: [] as Manager[], activeManagers: [] as Manager[],
retiredManagers: [] as Manager[] retiredManagers: [] as Manager[],
managerTeams: [] as Team[],
managerTeamStandings: [] as TeamStanding[],
managerAwards: [] as Award[]
} }
}, },
props: { props: {
managerName: { type: String, default: undefined }, managerName: { type: String, default: undefined },
}, },
computed: { computed: {
zippedManagers(): { active: Manager | undefined, retired: Manager | undefined }[] { selectedManager(): Manager | undefined {
return this.activeManagers.map((mgr, idx) => { if (!this.managerName) return undefined
return this.activeManagers.find(manager => manager.name === this.managerName) ?? this.retiredManagers.find(manager => manager.name === this.managerName)
},
managerModel(): ManagerModel | undefined {
if (!this.selectedManager) return undefined
return this.managerTeamStandings.reduce((acc, val) => {
return { return {
active: mgr, managerWins: acc.managerWins + val.wins,
retired: idx < this.retiredManagers.length ? this.retiredManagers[idx] : undefined managerLosses: acc.managerLosses + val.losses,
teamWins: acc.managerWins + val.wins,
teamLosses: acc.managerLosses + val.losses
} }
}) }, {
managerWins: 0,
managerLosses: 0,
teamWins: 0,
teamLosses: 0
}
)
},
teamsManagedRows(): { season: number, teamName: string, teamAbbreviation: string, record: string }[] {
return this.managerTeams
.map(team => {
const standing = this.managerTeamStandings.find(ts => ts.season === team.season)
const record = `${standing?.wins ?? 0}-${standing?.losses ?? 0}`
return { season: team.season, teamName: team.sname, teamAbbreviation: team.abbrev, record }
})
.sort((r1, r2) => r2.season - r1.season)
} }
}, },
created() { created() {
@ -162,14 +167,26 @@ export default {
watch: { watch: {
managerName(newValue, oldValue) { managerName(newValue, oldValue) {
if (newValue !== oldValue) if (newValue !== oldValue)
this.fetchData() this.fetchManagerData()
} }
}, },
methods: { methods: {
async fetchData(): Promise<void> { async fetchData(): Promise<void> {
this.activeManagers = await fetchActiveManagers() this.activeManagers = await fetchActiveManagers()
this.retiredManagers = await fetchRetiredManagers() this.retiredManagers = await fetchRetiredManagers()
await this.fetchManagerData()
},
async fetchManagerData(): Promise<void> {
// need to fetch manager/team wins/losses and awards
// fetch all teams managed, then surface managerModel as a computed instead of data
if (!this.selectedManager) return
this.managerTeams = await fetchTeamsByManagerId(this.selectedManager.id)
this.managerTeamStandings = (await Promise.all(this.managerTeams.flatMap(team =>
fetchStandingByTeam(team)
))).filter(isNotUndefined)
this.managerAwards = await fetchAwardsByManagerId(this.selectedManager.id)
} }
} }
} }
</script> </script>