From f2f719415d99289ed7c9cc622ed395c5d475b280 Mon Sep 17 00:00:00 2001 From: fireshaper Date: Sat, 3 Oct 2026 11:35:27 -0400 Subject: [PATCH] Step 10A.17: list ready goals in the away summary Co-Authored-By: Claude Opus 5.5 --- DECISIONS.md | 6 ++ apps/web/src/components/AwaySummary.tsx | 29 +++++++++ apps/web/test/away-goals.test.tsx | 85 +++++++++++++++++++++++++ apps/web/test/setup.ts | 5 +- memory-bank/progress.md | 2 +- 5 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 apps/web/test/away-goals.test.tsx diff --git a/DECISIONS.md b/DECISIONS.md index 9df2e1a..9a8f77d 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -587,3 +587,9 @@ Implementation decisions not spelled out in `memory-bank/implementation-plan.md` - **The map was already reachable during the tutorial** (its tab exists from the first screen); this step adds the lock and reachability. - **Locked locations are labelled "🔒 Name"** on the canvas (they were dimmed already), replacing the earlier "Name?". - **Reachability uses sim `checkRoute` (range and landing) from Earth at the current server time,** over `content.purchasableShipModels`, so it changes as planets move. When nothing can reach it the panel says so. + +## Step 10A.17 + +- **The summary lists every goal currently ready to claim,** not only ones that became ready since the last visit. The server does not track when a goal became ready, and an unclaimed ready goal is worth pointing out on any return. +- **"Claim on HQ" acknowledges the deliveries and navigates to `/#goals`.** +- **Web tests wait up to 3 s for elements** (`asyncUtilTimeout`); the 1 s default occasionally ran out under a fully parallel run. diff --git a/apps/web/src/components/AwaySummary.tsx b/apps/web/src/components/AwaySummary.tsx index 79db38b..e10eb4e 100644 --- a/apps/web/src/components/AwaySummary.tsx +++ b/apps/web/src/components/AwaySummary.tsx @@ -1,5 +1,6 @@ import { content } from "@deadhead/content"; import { useState } from "react"; +import { useNavigate } from "react-router"; import { formatCredits, locationName } from "../format"; import { useGameAction, useLoadedPlayer } from "../state/actions"; @@ -10,7 +11,13 @@ export function AwaySummary() { // Hide as soon as the player dismisses; the refetch clears the list for real. const [dismissed, setDismissed] = useState>(new Set()); + const navigate = useNavigate(); const summaries = state.summaries.filter((s) => !dismissed.has(s.dispatchId)); + // Goals waiting to be claimed (Step 10A.17). + const readyGoals = state.goals + .filter((g) => g.status === "ready") + .map((g) => content.onboardingGoal(g.id)) + .filter((g) => g !== undefined); if (summaries.length === 0) return null; const shipName = (shipId: string, tutorial: boolean) => @@ -68,6 +75,28 @@ export function AwaySummary() { ))} + {readyGoals.length > 0 && ( +
+

Goals ready to claim

+
    + {readyGoals.map((goal) => ( +
  • + {goal.title} +{formatCredits(goal.reward)} +
  • + ))} +
+ +
+ )}