sba-website/src/views/TeamView.vue

336 lines
12 KiB
Vue

<template>
<div class="team-view centerDiv">
<div class="row">
<div class="col-sm">
<h1 id="team-record">{{ teamName }} {{ teamRecord }}</h1>
<h2 id="standings"></h2>
<h2 id="streak">Last 8: {{ lastEight }} / Streak: {{ streak }}</h2>
</div>
<div class="col-sm">
<h2 id="manager">
Manager{{ hasMultipleManagers ? 's' : '' }}:
<RouterLink v-if="manager1Name" :to="{ name: 'manager', params: { managerName: manager1Name } }">
{{ manager1Name }}
</RouterLink>
{{ hasMultipleManagers ? ' & ' : '' }}
<RouterLink v-if="hasMultipleManagers && manager2Name"
:to="{ name: 'manager', params: { managerName: manager2Name } }">
{{ manager2Name }}
</RouterLink>
</h2>
<h2 id="abbrev">Abbrev: {{ teamAbbreviation }}</h2>
</div>
<div class="col-sm-1">
<!-- TODO move thumbnail to computed and fallback on default pic? -->
<img id="thumbnail" height="125" style="float:right; vertical-align:middle" :src=team?.thumbnail>
</div>
</div>
<!-- Team Rosters -->
<div class="row">
<!-- Left Column -->
<div class="col-sm-6">
<h3 id="active-roster-count">({{ rosterCount }}/26) Active Roster ({{ swarTotal(players).toFixed(2) }})</h3>
<div class="table-responsive-xl">
<table class="table table-sm table-striped" id="table-active-roster">
<thead class="thead-dark">
<tr>
<th>Pos</th>
<th>Name</th>
<th>sWAR</th>
<th>Injury</th>
<th>Positions</th>
</tr>
</thead>
<tbody id="active-roster">
<tr v-for="player in sortedPlayers(players)" :key="player.id">
<td>{{ player.pos_1 }}</td>
<td :title="player.il_return ? `Injured until ${player.il_return}` : ''">
{{ player.il_return ? '🏥' : '' }}
<RouterLink :to="{ name: 'player', params: { seasonNumber: seasonNumber, playerName: player.name } }">
{{ player.name }}
</RouterLink>
{{ player.il_return ? '🏥' : '' }}
</td>
<td>{{ player.wara.toFixed(2) }}</td>
<td>{{ player.injury_rating }}</td>
<td>{{ allPositions(player) }}</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>Pos</th>
<th>Name</th>
<th>sWAR</th>
<th>Injury</th>
<th>Positions</th>
</tr>
</tfoot>
</table>
</div>
</div>
<!-- Right Column -->
<div v-if="!isFreeAgentTeam" class="col-sm-6">
<h3 id="minors-header">({{ minorsRosterCount }}/6) {{ minorsTeamName }} ({{ swarTotal(playersMinors).toFixed(2)
}})</h3>
<div class="table-responsive-xl">
<table class="table table-sm table-striped" id="table-minors-roster">
<thead class="thead-dark">
<tr>
<th>Pos</th>
<th>Name</th>
<th>sWAR</th>
<th>Inj Return</th>
<th>Positions</th>
</tr>
</thead>
<tbody id="minors-roster">
<tr v-for="player in sortedPlayers(playersMinors)" :key="player.id">
<td>{{ player.pos_1 }}</td>
<td>
<RouterLink :to="{ name: 'player', params: { seasonNumber: seasonNumber, playerName: player.name } }">
{{ player.name }}
</RouterLink>
</td>
<td>{{ player.wara.toFixed(2) }}</td>
<td>{{ player.il_return }}</td>
<td>{{ allPositions(player) }}</td>
</tr>
</tbody>
</table>
</div>
<h3 id="short-il-header">Injured List ({{ swarTotal(playersInjuredList).toFixed(2) }})</h3>
<div class="table-responsive-xl">
<table class="table table-sm table-striped" id="table-shortil-roster">
<thead class="thead-dark">
<tr>
<th>Pos</th>
<th>Name</th>
<th>sWAR</th>
<th>Inj Return</th>
<th>Positions</th>
</tr>
</thead>
<tbody id="short-il-roster">
<tr v-for="player in sortedPlayers(playersInjuredList)" :key="player.id">
<td>{{ player.pos_1 }}</td>
<td>
<RouterLink :to="{ name: 'player', params: { seasonNumber: seasonNumber, playerName: player.name } }">
{{ player.name }}
</RouterLink>
</td>
<td>{{ player.wara.toFixed(2) }}</td>
<td>{{ player.il_return }}</td>
<td>{{ allPositions(player) }}</td>
</tr>
</tbody>
</table>
</div>
<template v-if="currentSeasonNumber === seasonNumber">
<h3 id="transactions-header">Week {{ transactionsWeekNumber }} Transactions ({{ transactionsWar.toFixed(2) }})
</h3>
<div class="table-responsive-xl">
<table class="table table-sm table-striped" id="table-transactions">
<thead class="thead-dark">
<tr>
<th>Week</th>
<th>Player</th>
<th>Old Team</th>
<th>New Team</th>
</tr>
</thead>
<tbody id="transactions-body"></tbody>
<tr v-for="row in transactionRows" :key="row.week">
<td>{{ row.week }}</td>
<td>{{ row.playerName }}</td>
<td>{{ row.oldTeam }}</td>
<td>{{ row.newTeam }}</td>
</tr>
</table>
</div>
</template>
</div>
</div>
<BullpenTable
v-if="currentSeasonNumber === seasonNumber && weekNumber && team?.id"
:season-number="seasonNumber"
:week-number="weekNumber"
:team-id="team.id"
/>
<!-- Schedule -->
<TeamScheduleTable v-if="!isFreeAgentTeam && team" :season-number="seasonNumber" :team-id="team.id" />
<!-- Team Pitching -->
<TeamPitchingTable v-if="!isFreeAgentTeam && team" :is-regular-season="true" :season-number="seasonNumber"
:team-id="team.id" />
<TeamPitchingTable v-if="!isFreeAgentTeam && team" :is-regular-season="false" :season-number="seasonNumber"
:team-id="team.id" />
<!-- Team Batting -->
<TeamBattingTable v-if="!isFreeAgentTeam && team" :is-regular-season="true" :season-number="seasonNumber"
:team-id="team.id" />
<TeamBattingTable v-if="!isFreeAgentTeam && team" :is-regular-season="false" :season-number="seasonNumber"
:team-id="team.id" />
<!-- Team Fielding -->
<div class="row">
<TeamFieldingTable v-if="!isFreeAgentTeam && team" :is-regular-season="true" :season-number="seasonNumber"
:team-id="team.id" />
<TeamFieldingTable v-if="!isFreeAgentTeam && team" :is-regular-season="false" :season-number="seasonNumber"
:team-id="team.id" />
</div>
</div>
</template>
<script lang="ts">
import type { Team } from '@/services/apiResponseTypes'
import { fetchCurrentLeagueInfo, type LeagueInfo } from '@/services/currentService'
import { fetchPlayersByTeam, type Player } from '@/services/playersService'
import { fetchStandings, type TeamStanding } from '@/services/standingsService'
import { fetchTeam } from '@/services/teamsService'
import { fetchTransactionsByTeamAndWeek, type Transaction } from '@/services/transactionsService'
import TeamScheduleTable from '@/components/TeamScheduleTable.vue'
import TeamPitchingTable from '@/components/TeamPitchingTable.vue'
import TeamBattingTable from '@/components/TeamBattingTable.vue'
import TeamFieldingTable from '@/components/TeamFieldingTable.vue'
import BullpenTable from '@/components/BullpenTable.vue'
export default {
name: 'TeamView',
components: {
BullpenTable,
TeamScheduleTable,
TeamPitchingTable,
TeamBattingTable,
TeamFieldingTable
},
data() {
return {
team: undefined as Team | undefined,
teamMinors: undefined as Team | undefined,
teamInjuredList: undefined as Team | undefined,
teamStanding: undefined as TeamStanding | undefined,
players: [] as Player[],
playersMinors: [] as Player[],
playersInjuredList: [] as Player[],
transactions: [] as Transaction[],
weekNumber: undefined as number | undefined,
currentSeasonNumber: undefined as number | undefined
}
},
props: {
seasonNumber: { type: Number, required: true },
teamAbbreviation: { type: String, required: true },
},
computed: {
isFreeAgentTeam(): boolean {
return this.teamAbbreviation === 'FA'
},
manager1Name(): string | undefined {
return this.team?.manager1?.name
},
manager2Name(): string | undefined {
return this.team?.manager2?.name
},
hasMultipleManagers(): boolean {
return !!(this.manager1Name && this.manager2Name)
},
teamName(): string | undefined {
return this.team?.lname
},
teamRecord(): string | undefined {
if (!this.teamStanding) return undefined
return `(${this.teamStanding?.wins}-${this.teamStanding.losses})`
},
minorsTeamName(): string | undefined {
return this.teamMinors?.sname
},
lastEight(): string | undefined {
return this.teamStanding?.last8Record
},
streak(): string | undefined {
return this.teamStanding?.streak
},
rosterCount(): number {
return this.players.length
},
minorsRosterCount(): number {
return this.playersMinors.length
},
transactionsWeekNumber(): number | undefined {
if (this.weekNumber === undefined) return undefined
return this.weekNumber + 1
},
transactionsWar(): number {
const teamsWar = this.swarTotal(this.players)
if (!this.transactions.length) return teamsWar
const playersOut = this.transactions.filter(t => t.oldteam.abbrev === this.teamAbbreviation).map(t => t.player)
const playersIn = this.transactions.filter(t => t.newteam.abbrev === this.teamAbbreviation).map(t => t.player)
const swarOut = this.swarTotal(playersOut)
const swarIn = this.swarTotal(playersIn)
return teamsWar - swarOut + swarIn
},
transactionRows(): { week: number, playerName: string, oldTeam: string, newTeam: string }[] {
return this.transactions.map(t => {
return { week: t.week, playerName: t.player.name, oldTeam: t.oldteam.sname, newTeam: t.newteam.sname }
})
}
},
created() {
this.fetchData()
},
watch: {
seasonNumber(newValue, oldValue) {
if (newValue !== oldValue)
this.fetchData()
},
teamAbbreviation(newName, oldName) {
if (newName !== oldName)
this.fetchData()
}
},
methods: {
async fetchData(): Promise<void> {
this.team = await fetchTeam(this.seasonNumber, this.teamAbbreviation)
if (!this.isFreeAgentTeam) {
this.teamMinors = await fetchTeam(this.seasonNumber, `${this.teamAbbreviation}MiL`)
this.teamInjuredList = await fetchTeam(this.seasonNumber, `${this.teamAbbreviation}IL`)
}
this.teamStanding = (await fetchStandings(this.seasonNumber)).find(ts => ts.teamName === this.team?.sname)
const leagueInfo: LeagueInfo = await fetchCurrentLeagueInfo()
this.currentSeasonNumber = leagueInfo.season
this.weekNumber = leagueInfo.week
this.players = await fetchPlayersByTeam(this.seasonNumber, this.team?.id)
if (!this.isFreeAgentTeam) {
this.playersMinors = await fetchPlayersByTeam(this.seasonNumber, this.teamMinors!.id)
this.playersInjuredList = await fetchPlayersByTeam(this.seasonNumber, this.teamInjuredList!.id)
}
this.transactions = (await fetchTransactionsByTeamAndWeek(this.seasonNumber, this.teamAbbreviation, this.transactionsWeekNumber!))
},
allPositions(player: Player): string {
let positions = []
positions.push(player.pos_1, player.pos_2, player.pos_3, player.pos_4, player.pos_5, player.pos_6, player.pos_7)
return positions.filter(p => p).join(' ')
},
swarTotal(players: Player[]): number {
return players.map(p => p.wara).reduce((prev, curr) => prev + curr, 0)
},
sortedPlayers(players: Player[]): Player[] {
return players.sort((a, b) => b.wara - a.wara)
}
}
}
</script>