Skip to content
97 changes: 63 additions & 34 deletions apps/web/src/features/game/GamePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { CombatPanel } from "./components/CombatPanel";
import { CardsPanel } from "./components/CardsPanel";
import { BattleLogPanel } from "./components/BattleLogPanel";
import { OnboardingTour, shouldShowOnboarding } from "./components/OnboardingTour";
import { formatPhaseLabel, formatTerritoryLabel } from "./utils/labels";

interface GamePageProps {
credentials: SessionCredentials;
Expand Down Expand Up @@ -56,6 +57,11 @@ export function GamePage({ credentials, onLeaveSession }: GamePageProps) {
[credentials.playerId, privateState],
);

const myPublicPlayer = useMemo(
() => publicState?.players.find((player) => player.id === credentials.playerId),
[credentials.playerId, publicState],
);

async function handleSubmitAction(action: Record<string, unknown>) {
await submitAction(credentials, action as RiskAction);
}
Expand Down Expand Up @@ -97,41 +103,63 @@ export function GamePage({ credentials, onLeaveSession }: GamePageProps) {
}

return (
<main className="game-layout">
<header className="panel row between">
<div>
<h1>Lobby {credentials.lobbyCode}</h1>
<p>
{isMyTurn ? "Your move." : "Waiting for another commander..."} ·{" "}
Phase: {privateState.currentPhase}
</p>
</div>
<div className="row gap-sm">
<button
onClick={() => {
setShowTour(true);
}}
>
Onboarding
</button>
<button
onClick={() => {
onLeaveSession();
}}
>
Exit to Lobby
</button>
</div>
</header>

<section className="game-main-grid">
<main className="war-room-layout">
<section className="war-room-overlay-stage">
<BoardMap
state={publicState}
selectedTerritoryId={selectedTerritoryId}
onSelectTerritory={setSelectedTerritoryId}
/>

<aside className="stack gap-md side-column">
<header className="panel row between war-room-topbar overlay-topbar">
<div className="stack gap-xs">
<p className="war-room-kicker">Lobby {credentials.lobbyCode}</p>
<h1>Global Command</h1>
<p>
{isMyTurn
? "Your offensive window is open."
: "Monitoring allied commanders."}{" "}
· Phase: {formatPhaseLabel(privateState.currentPhase)}
</p>
</div>
<div className="row gap-sm">
<button
onClick={() => {
setShowTour(true);
}}
>
Onboarding
</button>
<button
onClick={() => {
onLeaveSession();
}}
>
Exit to Lobby
</button>
</div>
</header>

<section className="panel stack gap-xs overlay-commander-panel">
<h2>Commander Snapshot</h2>
<p>
You control <strong>{myPublicPlayer?.territories ?? 0}</strong> territories
and hold <strong>{privateState.me.cards.length}</strong> cards.
</p>
<p>
Territory focus:{" "}
<strong>
{selectedTerritoryId
? formatTerritoryLabel(selectedTerritoryId)
: "No territory selected"}
</strong>
</p>
<p>
Reinforcements in reserve: <strong>{privateState.me.reinforcementPool}</strong>
</p>
</section>

<aside className="stack gap-md overlay-command-stack">
<TurnPanel publicState={publicState} privateState={privateState} />
<CombatPanel
state={privateState}
Expand All @@ -141,14 +169,15 @@ export function GamePage({ credentials, onLeaveSession }: GamePageProps) {
/>
<CardsPanel state={privateState} onSubmitAction={handleSubmitAction} />
</aside>
</section>

<section className="bottom-grid">
<BattleLogPanel state={publicState} />
<section className="panel stack gap-sm">
<div className="overlay-battle-log">
<BattleLogPanel state={publicState} />
</div>

<section className="panel stack gap-sm legal-intel-panel overlay-legal-intel">
<h2>Legal Action Hints</h2>
{legalActions.length === 0 ? (
<p>No legal actions right now.</p>
<p>No legal actions available for the current phase.</p>
) : (
<ul className="legal-list">
{legalActions.map((hint) => (
Expand Down
Loading