package seasonsview import "git.haelnorr.com/h/oslstats/internal/db" import "git.haelnorr.com/h/oslstats/internal/permissions" import "git.haelnorr.com/h/oslstats/internal/contexts" import "git.haelnorr.com/h/oslstats/internal/view/baseview" import "git.haelnorr.com/h/oslstats/internal/view/component/links" import "fmt" import "sort" import "time" templ SeasonLeagueTeamDetailPage(twr *db.TeamWithRoster, fixtures []*db.Fixture, available []*db.Player, scheduleMap map[int]*db.FixtureSchedule, resultMap map[int]*db.FixtureResult, record *db.TeamRecord, playerStats []*db.AggregatedPlayerStats, position int, totalTeams int) { {{ team := twr.Team season := twr.Season league := twr.League }} @baseview.Layout(fmt.Sprintf("%s - %s - %s", team.Name, league.Name, season.Name)) {
if team.Color != "" {
}

{ team.Name }

{ team.ShortName } { team.AltShortName } { season.Name } — { league.Name }
{{ // Split fixtures into upcoming and completed var upcoming []*db.Fixture var completed []*db.Fixture for _, f := range fixtures { if _, hasResult := resultMap[f.ID]; hasResult { completed = append(completed, f) } else { upcoming = append(upcoming, f) } } // Sort completed by scheduled time descending (most recent first) sort.Slice(completed, func(i, j int) bool { ti := time.Time{} tj := time.Time{} if si, ok := scheduleMap[completed[i].ID]; ok && si.ScheduledTime != nil { ti = *si.ScheduledTime } if sj, ok := scheduleMap[completed[j].ID]; ok && sj.ScheduledTime != nil { tj = *sj.ScheduledTime } return ti.After(tj) }) // Limit to 5 most recent results recentResults := completed if len(recentResults) > 5 { recentResults = recentResults[:5] } }}
@teamRecordCard(record, position, totalTeams) @teamResultsSection(twr.Team, recentResults, resultMap) @TeamRosterSection(twr, available) @teamUpcomingSection(twr.Team, upcoming, scheduleMap)
@playerStatsSection(playerStats)
} } // TeamRosterSection renders the roster section — exported so it can be used for HTMX swaps templ TeamRosterSection(twr *db.TeamWithRoster, available []*db.Player) { {{ permCache := contexts.Permissions(ctx) canManagePlayers := permCache.HasPermission(permissions.TeamsManagePlayers) // Build the non-manager player list for display rosterPlayers := []*db.Player{} for _, p := range twr.Players { if p != nil && (twr.Manager == nil || p.ID != twr.Manager.ID) { rosterPlayers = append(rosterPlayers, p) } } hasRoster := twr.Manager != nil || len(rosterPlayers) > 0 }}

Roster

if canManagePlayers { }
if !hasRoster {

No players on this roster yet.

if canManagePlayers {

Click "Manage Players" to add players to this team.

}
} else {
if twr.Manager != nil {
@links.PlayerLink(twr.Manager) ★ Manager
} for _, player := range rosterPlayers {
@links.PlayerLink(player)
}
} if canManagePlayers { @manageRosterModal(twr, available, rosterPlayers) }
} templ manageRosterModal(twr *db.TeamWithRoster, available []*db.Player, rosterPlayers []*db.Player) { } templ teamResultsSection(team *db.Team, recentResults []*db.Fixture, resultMap map[int]*db.FixtureResult) {

Results (last 5)

if len(recentResults) == 0 {

No results yet.

Match results will appear here once games are played.

} else {
for _, fixture := range recentResults { @teamResultRow(team, fixture, resultMap) }
}
} templ teamUpcomingSection(team *db.Team, upcoming []*db.Fixture, scheduleMap map[int]*db.FixtureSchedule) {

Upcoming

if len(upcoming) == 0 {

No upcoming fixtures.

} else {
for _, fixture := range upcoming { @teamFixtureRow(team, fixture, scheduleMap) }
}
} templ teamFixtureRow(team *db.Team, fixture *db.Fixture, scheduleMap map[int]*db.FixtureSchedule) { {{ isHome := fixture.HomeTeamID == team.ID var opponent string if isHome { opponent = fixture.AwayTeam.Name } else { opponent = fixture.HomeTeam.Name } sched, hasSchedule := scheduleMap[fixture.ID] _ = sched }}
GW{ fmt.Sprint(*fixture.GameWeek) } if isHome { HOME } else { AWAY } vs { opponent }
if hasSchedule && sched.ScheduledTime != nil { @localtime(sched.ScheduledTime, "short") } else { TBD }
} templ teamResultRow(team *db.Team, fixture *db.Fixture, resultMap map[int]*db.FixtureResult) { {{ isHome := fixture.HomeTeamID == team.ID var opponent string if isHome { opponent = fixture.AwayTeam.Name } else { opponent = fixture.HomeTeam.Name } res := resultMap[fixture.ID] won := (isHome && res.Winner == "home") || (!isHome && res.Winner == "away") lost := (isHome && res.Winner == "away") || (!isHome && res.Winner == "home") _ = lost isForfeit := res.IsForfeit isMutualForfeit := isForfeit && res.ForfeitType != nil && *res.ForfeitType == "mutual" }}
if isMutualForfeit { FF } else if won { W } else if lost { L } else { D } GW{ fmt.Sprint(*fixture.GameWeek) } if isHome { HOME } else { AWAY } vs { opponent }
if isForfeit { if isMutualForfeit { Mutual Forfeit } else { Forfeit } } else { if res.Winner == "home" { { fmt.Sprint(res.HomeScore) } { fmt.Sprint(res.AwayScore) } } else if res.Winner == "away" { { fmt.Sprint(res.HomeScore) } { fmt.Sprint(res.AwayScore) } } else { { fmt.Sprint(res.HomeScore) } { fmt.Sprint(res.AwayScore) } } }
} templ teamRecordCard(record *db.TeamRecord, position int, totalTeams int) {

Standing

if record.Played == 0 {

No games played yet.

} else {
{ ordinal(position) }

Position

of { fmt.Sprint(totalTeams) } teams

Points

{ fmt.Sprint(record.Points) }

@statCell("W", fmt.Sprint(record.Wins), "text-green") @statCell("OTW", fmt.Sprint(record.OvertimeWins), "text-teal") @statCell("OTL", fmt.Sprint(record.OvertimeLosses), "text-peach") @statCell("L", fmt.Sprint(record.Losses), "text-red")
@statCell("Played", fmt.Sprint(record.Played), "") @statCell("GF", fmt.Sprint(record.GoalsFor), "") @statCell("GA", fmt.Sprint(record.GoalsAgainst), "")
}
} templ playerStatsSection(playerStats []*db.AggregatedPlayerStats) {

Player Stats

if len(playerStats) == 0 {

No player stats yet.

Player statistics will appear here once games are played.

} else {
for _, ps := range playerStats { }
Player GP PP SC G A SV SH BL PA
@links.PlayerLinkFromStats(ps.PlayerID, ps.PlayerName) { fmt.Sprint(ps.GamesPlayed) } { fmt.Sprint(ps.PeriodsPlayed) } { fmt.Sprint(ps.Score) } { fmt.Sprint(ps.Goals) } { fmt.Sprint(ps.Assists) } { fmt.Sprint(ps.Saves) } { fmt.Sprint(ps.Shots) } { fmt.Sprint(ps.Blocks) } { fmt.Sprint(ps.Passes) }
}
} templ statCell(label string, value string, valueColor string) {

{ label }

{ value }

}