v1.6.0: leaderboard pane from the top-bar additional-panels button (ISS-115)
CI / build + unit + e2e (pull_request) Successful in 14m2s
CI / build + unit + e2e (pull_request) Successful in 14m2s
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import { formatCash } from '@/lib/format';
|
||||
import type { PlayerSummary } from '@/lib/game/state';
|
||||
|
||||
// v1.6.0 (ISS-115): leaderboard panel — every player in the world with cash, reputation and
|
||||
// plane count, rendered straight off the shared snapshot (no endpoint of its own). Sorted by
|
||||
// reputation desc; cash then username break ties deterministically so rows don't shuffle
|
||||
// between snapshots when two players share a reputation.
|
||||
export default function Leaderboard({ players }: { players: PlayerSummary[] }) {
|
||||
const sorted = [...players].sort(
|
||||
(a, b) => b.reputation - a.reputation || b.cash - a.cash || a.username.localeCompare(b.username),
|
||||
);
|
||||
return (
|
||||
<div className="leaderboard">
|
||||
<table data-testid="leaderboard-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Player</th>
|
||||
<th>Cash</th>
|
||||
<th>Reputation</th>
|
||||
<th>Planes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{sorted.map((p) => (
|
||||
<tr key={p.id} data-testid={`leaderboard-row-${p.id}`}>
|
||||
<td>{p.username}</td>
|
||||
<td>{formatCash(p.cash)}</td>
|
||||
<td>{p.reputation}</td>
|
||||
<td>{p.planeCount}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import { weatherFor } from '../lib/weather';
|
||||
import { approxLocalTime } from '../lib/localTime';
|
||||
import Modal from './Modal';
|
||||
import AdminPanel from './AdminPanel';
|
||||
import Leaderboard from './Leaderboard';
|
||||
import { sessionHeaders } from '../lib/authClient';
|
||||
|
||||
// v0.70.0 default view: null island [0,0] at zoom 2 — the world is 2048 px wide there and the
|
||||
@@ -98,6 +99,8 @@ export default function FlightMap({ state, hovered, applySnapshot, onLogout }: M
|
||||
// v0.71.0: the Admin modal (top-bar button) — unmounted while closed so it re-checks the
|
||||
// stored session on every open.
|
||||
const [adminOpen, setAdminOpen] = useState(false);
|
||||
// v1.6.0 (ISS-115): the leaderboard panel (top-bar button) — rows come from the polled snapshot.
|
||||
const [leaderboardOpen, setLeaderboardOpen] = useState(false);
|
||||
|
||||
// Push the latest planes/routes GeoJSON into whatever sources currently exist.
|
||||
// No-op until the map (and for routes: the airport index) is ready — the mount
|
||||
@@ -589,6 +592,10 @@ export default function FlightMap({ state, hovered, applySnapshot, onLogout }: M
|
||||
<span data-testid="airport-count">
|
||||
{airportCount === null ? 'loading airports…' : `${airportCount} world airports`}
|
||||
</span>
|
||||
{/* v1.6.0 (ISS-115): leaderboard panel entry point — right side of the top bar, opens a modal. */}
|
||||
<button type="button" data-testid="leaderboard-btn" className="pane-btn" onClick={() => setLeaderboardOpen(true)}>
|
||||
Leaderboard
|
||||
</button>
|
||||
{/* v0.71.0: admin panel entry point — right side of the top bar, opens a modal (no URL). */}
|
||||
<button type="button" data-testid="admin-btn" className="pane-btn" onClick={() => setAdminOpen(true)}>
|
||||
Admin
|
||||
@@ -598,6 +605,10 @@ export default function FlightMap({ state, hovered, applySnapshot, onLogout }: M
|
||||
<Modal open={adminOpen} onClose={() => setAdminOpen(false)} title="Admin">
|
||||
<AdminPanel onLogout={onLogout} />
|
||||
</Modal>
|
||||
{/* v1.6.0 (ISS-115): leaderboard — players from the shared snapshot, no extra endpoint. */}
|
||||
<Modal open={leaderboardOpen} onClose={() => setLeaderboardOpen(false)} title="Leaderboard">
|
||||
<Leaderboard players={state?.players ?? []} />
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ function snap(planes: PlaneState[], packages: PackageState[] = []): StateSnapsho
|
||||
account: { cash: 0, reputation: 0 },
|
||||
simState: { clockMs: 0 },
|
||||
planes,
|
||||
players: [], // v1.6.0 (ISS-115) — leaderboard rows; unused by the right pane
|
||||
packages,
|
||||
catalog: CATALOG,
|
||||
fuelPricePerL: 0.8,
|
||||
|
||||
Reference in New Issue
Block a user