OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
 
master @ 185 LINES
 
[ HISTORY ]  [ UP ]
 

---
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>

---
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