master @ 185 LINES
[ HISTORY ] [ UP ]
┌─ ASTRO ────────────────────────────────────────────────────────────────────┐
│ --- │
│ import Callout from "../components/Callout/Callout.astro"; │
│ import WoWClassColors from "../components/WoWClassColors.astro"; │
│ import PlayerSearch from "../components/PlayerSearch/PlayerSearch.astro"; │
│ import PlayerHeader from "../components/PlayerProfile/PlayerHeader/PlayerHeader.as │
│ tro"; │
│ import PlayerEquipment from "../components/PlayerProfile/PlayerEquipment/PlayerEqu │
│ ipment.astro"; │
│ import PlayerBestRuns from "../components/PlayerProfile/PlayerBestRuns/PlayerBestR │
│ uns.astro"; │
│ import PageLayout from "./PageLayout.astro"; │
│ import type { PlayerProfileData, BestRun } from "../lib/types"; │
│ import "../styles/global.scss"; │
│ import "./PlayerProfileLayout.scss"; │
│ │
│ export interface Props { │
│ region?: string; │
│ realmSlug?: string; │
│ playerName?: string; │
│ playerData?: PlayerProfileData | null; │
│ requestedSeason?: string | null; │
│ error?: string | null; │
│ } │
│ │
│ const { │
│ region = "", │
│ realmSlug = "", │
│ playerName = "", │
│ playerData = null, │
│ requestedSeason = null, │
│ error = null, │
│ } = Astro.props; │
│ │
│ const pageTitle = `${playerName} - ${realmSlug} | Player Profile`; │
│ │
│ const player = playerData?.player; │
│ const equipment = playerData?.equipment || {}; │
│ │
│ let currentSeasonId: string | null = null; │
│ let currentSeasonData = null; │
│ let seasonOptions: { id: string; label: string; href: string }[] = []; │
│ const seasonRunsMap: Record<string, Record<string, BestRun>> = {}; │
│ │
│ // Build the page-level season selector URLs - default season has no segment │
│ // in the URL so /player/{r}/{realm}/{name} stays canonical for the latest. │
│ function seasonHref(seasonId: string, isDefault: boolean) { │
│ const base = `/player/${region}/${realmSlug}/${playerName}`; │
│ if (isDefault) return base; │
│ if (seasonId === "all-time") return `${base}/all-time`; │
│ return `${base}/season${seasonId}`; │
│ } │
│ │
│ function seasonLabel(id: string) { │
│ return id === "all-time" ? "All Time" : `Season ${id}`; │
│ } │
│ │
│ if (player && player.seasons) { │
│ // Numeric season ids first (highest -> lowest), then "all-time" at the end. │
│ // Default = latest numeric season, NOT all-time. │
│ const allKeys = Object.keys(player.seasons); │
│ const numericIds = allKeys │
│ .filter((k) => /^\d+$/.test(k)) │
│ .sort((a, b) => Number(b) - Number(a)); │
│ const hasAllTime = allKeys.includes("all-time"); │
│ const orderedIds = hasAllTime ? [...numericIds, "all-time"] : numericIds; │
│ const defaultSeasonId = numericIds[0]; │
│ │
│ seasonOptions = orderedIds.map((id) => ({ │
│ id, │
│ label: seasonLabel(id), │
│ href: seasonHref(id, id === defaultSeasonId), │
│ })); │
│ │
│ if (orderedIds.length > 0) { │
│ if (requestedSeason && orderedIds.includes(requestedSeason)) { │
│ currentSeasonId = requestedSeason; │
│ } else { │
│ currentSeasonId = defaultSeasonId; │
│ } │
│ currentSeasonData = currentSeasonId │
│ ? player.seasons[currentSeasonId] │
│ : null; │
│ } │
│ │
│ // Best Runs section gets all the keyed-by-season run maps, including │
│ // "all-time" so its internal switcher (if ever used again) handles it. │
│ for (const seasonId of orderedIds) { │
│ const data = player.seasons[seasonId]; │
│ seasonRunsMap[seasonId] = data?.best_runs || {}; │
│ } │
│ } │
│ │
│ const bestRuns = currentSeasonData?.best_runs || {}; │
│ --- │
│ │
│ <PageLayout title={pageTitle} description="Player profile page"> │
│ <body> │
│ <WoWClassColors /> │
│ <div class="player-profile-layout"> │
│ <PlayerSearch /> │
│ │
│ <div class="player-profile-page"> │
│ { │
│ error && ( │
│ <div class="error-state"> │
│ <div class="error-message"> │
│ <h2>Error</h2> │
│ <p>{error}</p> │
│ </div> │
│ </div> │
│ ) │
│ } │
│ │
│ { │
│ !player && !error && ( │
│ <div class="error-state"> │
│ <div class="error-message"> │
│ <h2>Player Not Found</h2> │
│ <p> │
│ Player "{playerName}" not found. Only players with complete │
│ coverage (9/9 recorded dungeons) are included. │
│ </p> │
│ </div> │
│ </div> │
│ ) │
│ } │
│ │
│ { │
│ player && currentSeasonData && ( │
│ <> │
│ {seasonOptions.length > 1 && ( │
│ <div class="profile-season-bar"> │
│ <label for="profile-season-select">Season</label> │
│ <select id="profile-season-select"> │
│ {seasonOptions.map((opt) => ( │
│ <option │
│ value={opt.id} │
│ selected={opt.id === currentSeasonId} │
│ data-url={opt.href} │
│ > │
│ {opt.label} │
│ </option> │
│ ))} │
│ </select> │
│ </div> │
│ )} │
│ <PlayerHeader │
│ player={player} │
│ seasonData={currentSeasonData} │
│ seasonId={currentSeasonId} │
│ accountSeasonData={ │
│ currentSeasonId && player.account │
│ ? player.account[currentSeasonId] │
│ : undefined │
│ } │
│ /> │
│ <PlayerEquipment equipment={equipment} /> │
│ <PlayerBestRuns │
│ bestRuns={bestRuns} │
│ showSectionWrapper={true} │
│ playerRegion={player.region} │
│ playerRealmSlug={player.realm_slug} │
│ seasonId={currentSeasonId} │
│ seasonOptions={[]} │
│ seasonRuns={seasonRunsMap} │
│ mode="full" │
│ /> │
│ </> │
│ ) │
│ } │
│ </div> │
│ </div> │
│ │
│ <script> │
│ const sel = document.getElementById( │
│ "profile-season-select", │
│ ) as HTMLSelectElement | null; │
│ if (sel) { │
│ sel.addEventListener("change", (e) => { │
│ const target = e.target as HTMLSelectElement; │
│ const url = target.options[target.selectedIndex].dataset.url; │
│ if (url) window.location.href = url; │
│ }); │
│ } │
│ </script> │
│ </body> │
│ </PageLayout> │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ASTRO ──────────────────────────────┐
│ --- │
│ import Callout from "../components/Callout/C │
│ allout.astro"; │
│ import WoWClassColors from "../components/Wo │
│ WClassColors.astro"; │
│ import PlayerSearch from "../components/Play │
│ erSearch/PlayerSearch.astro"; │
│ import PlayerHeader from "../components/Play │
│ erProfile/PlayerHeader/PlayerHeader.astro"; │
│ import PlayerEquipment from "../components/P │
│ layerProfile/PlayerEquipment/PlayerEquipment │
│ .astro"; │
│ import PlayerBestRuns from "../components/Pl │
│ ayerProfile/PlayerBestRuns/PlayerBestRuns.as │
│ tro"; │
│ import PageLayout from "./PageLayout.astro"; │
│ import type { PlayerProfileData, BestRun } f │
│ rom "../lib/types"; │
│ import "../styles/global.scss"; │
│ import "./PlayerProfileLayout.scss"; │
│ │
│ export interface Props { │
│ region?: string; │
│ realmSlug?: string; │
│ playerName?: string; │
│ playerData?: PlayerProfileData | null; │
│ requestedSeason?: string | null; │
│ error?: string | null; │
│ } │
│ │
│ const { │
│ region = "", │
│ realmSlug = "", │
│ playerName = "", │
│ playerData = null, │
│ requestedSeason = null, │
│ error = null, │
│ } = Astro.props; │
│ │
│ const pageTitle = `${playerName} - ${realmSl │
│ ug} | Player Profile`; │
│ │
│ const player = playerData?.player; │
│ const equipment = playerData?.equipment || { │
│ }; │
│ │
│ let currentSeasonId: string | null = null; │
│ let currentSeasonData = null; │
│ let seasonOptions: { id: string; label: stri │
│ ng; href: string }[] = []; │
│ const seasonRunsMap: Record<string, Record<s │
│ tring, BestRun>> = {}; │
│ │
│ // Build the page-level season selector URLs │
│ - default season has no segment │
│ // in the URL so /player/{r}/{realm}/{name} │
│ stays canonical for the latest. │
│ function seasonHref(seasonId: string, isDefa │
│ ult: boolean) { │
│ const base = `/player/${region}/${realmSlu │
│ g}/${playerName}`; │
│ if (isDefault) return base; │
│ if (seasonId === "all-time") return `${bas │
│ e}/all-time`; │
│ return `${base}/season${seasonId}`; │
│ } │
│ │
│ function seasonLabel(id: string) { │
│ return id === "all-time" ? "All Time" : `S │
│ eason ${id}`; │
│ } │
│ │
│ if (player && player.seasons) { │
│ // Numeric season ids first (highest -> lo │
│ west), then "all-time" at the end. │
│ // Default = latest numeric season, NOT al │
│ l-time. │
│ const allKeys = Object.keys(player.seasons │
│ ); │
│ const numericIds = allKeys │
│ .filter((k) => /^\d+$/.test(k)) │
│ .sort((a, b) => Number(b) - Number(a)); │
│ const hasAllTime = allKeys.includes("all-t │
│ ime"); │
│ const orderedIds = hasAllTime ? [...numeri │
│ cIds, "all-time"] : numericIds; │
│ const defaultSeasonId = numericIds[0]; │
│ │
│ seasonOptions = orderedIds.map((id) => ({ │
│ id, │
│ label: seasonLabel(id), │
│ href: seasonHref(id, id === defaultSeaso │
│ nId), │
│ })); │
│ │
│ if (orderedIds.length > 0) { │
│ if (requestedSeason && orderedIds.includ │
│ es(requestedSeason)) { │
│ currentSeasonId = requestedSeason; │
│ } else { │
│ currentSeasonId = defaultSeasonId; │
│ } │
│ currentSeasonData = currentSeasonId │
│ ? player.seasons[currentSeasonId] │
│ : null; │
│ } │
│ │
│ // Best Runs section gets all the keyed-by │
│ -season run maps, including │
│ // "all-time" so its internal switcher (if │
│ ever used again) handles it. │
│ for (const seasonId of orderedIds) { │
│ const data = player.seasons[seasonId]; │
│ seasonRunsMap[seasonId] = data?.best_run │
│ s || {}; │
│ } │
│ } │
│ │
│ const bestRuns = currentSeasonData?.best_run │
│ s || {}; │
│ --- │
│ │
│ <PageLayout title={pageTitle} description="P │
│ layer profile page"> │
│ <body> │
│ <WoWClassColors /> │
│ <div class="player-profile-layout"> │
│ <PlayerSearch /> │
│ │
│ <div class="player-profile-page"> │
│ { │
│ error && ( │
│ <div class="error-state"> │
│ <div class="error-message"> │
│ <h2>Error</h2> │
│ <p>{error}</p> │
│ </div> │
│ </div> │
│ ) │
│ } │
│ │
│ { │
│ !player && !error && ( │
│ <div class="error-state"> │
│ <div class="error-message"> │
│ <h2>Player Not Found</h2> │
│ <p> │
│ Player "{playerName}" not │
│ found. Only players with complete │
│ coverage (9/9 recorded dun │
│ geons) are included. │
│ </p> │
│ </div> │
│ </div> │
│ ) │
│ } │
│ │
│ { │
│ player && currentSeasonData && ( │
│ <> │
│ {seasonOptions.length > 1 && ( │
│ <div class="profile-season-b │
│ ar"> │
│ <label for="profile-season │
│ -select">Season</label> │
│ <select id="profile-season │
│ -select"> │
│ {seasonOptions.map((opt) │
│ => ( │
│ <option │
│ value={opt.id} │
│ selected={opt.id === │
│ currentSeasonId} │
│ data-url={opt.href} │
│ > │
│ {opt.label} │
│ </option> │
│ ))} │
│ </select> │
│ </div> │
│ )} │
│ <PlayerHeader │
│ player={player} │
│ seasonData={currentSeasonDat │
│ a} │
│ seasonId={currentSeasonId} │
│ accountSeasonData={ │
│ currentSeasonId && player. │
│ account │
│ ? player.account[current │
│ SeasonId] │
│ : undefined │
│ } │
│ /> │
│ <PlayerEquipment equipment={eq │
│ uipment} /> │
│ <PlayerBestRuns │
│ bestRuns={bestRuns} │
│ showSectionWrapper={true} │
│ playerRegion={player.region} │
│ playerRealmSlug={player.real │
│ m_slug} │
│ seasonId={currentSeasonId} │
│ seasonOptions={[]} │
│ seasonRuns={seasonRunsMap} │
│ mode="full" │
│ /> │
│ </> │
│ ) │
│ } │
│ </div> │
│ </div> │
│ │
│ <script> │
│ const sel = document.getElementById( │
│ "profile-season-select", │
│ ) as HTMLSelectElement | null; │
│ if (sel) { │
│ sel.addEventListener("change", (e) = │
│ > { │
│ const target = e.target as HTMLSel │
│ ectElement; │
│ const url = target.options[target. │
│ selectedIndex].dataset.url; │
│ if (url) window.location.href = ur │
│ l; │
│ }); │
│ } │
│ </script> │
│ </body> │
│ </PageLayout> │
└──────────────────────────────────────────────┘
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET