diff --git a/apps/web/src/app/core/api/game-api.models.ts b/apps/web/src/app/core/api/game-api.models.ts
index 02066da..d7d1a6e 100644
--- a/apps/web/src/app/core/api/game-api.models.ts
+++ b/apps/web/src/app/core/api/game-api.models.ts
@@ -430,6 +430,14 @@ export interface ExchangeResult {
capacities: LootCapacity[];
}
+/** One gate on an offer, as the server phrased it (slice 0.8.5 §5, §8). */
+export interface ShopOfferRequirement {
+ label: string;
+ current: number | null;
+ required: number | null;
+ met: boolean;
+}
+
export interface ShopOfferView {
itemKey: string;
itemName: string;
@@ -438,6 +446,13 @@ export interface ShopOfferView {
currencyType: string;
price: number;
quantity: number;
+ /**
+ * Optional so fixtures written before slice 0.8.5 (e.g. the trade-in store's
+ * own spec, out of this task's scope) keep compiling untouched. The server
+ * always sends both fields; the template treats a missing one as "none".
+ */
+ effectSummary?: string | null;
+ requirements?: ShopOfferRequirement[];
unlocked: boolean;
affordable: boolean;
}
diff --git a/apps/web/src/app/features/npc/merchant-page.component.html b/apps/web/src/app/features/npc/merchant-page.component.html
index a024c04..6da1ea0 100644
--- a/apps/web/src/app/features/npc/merchant-page.component.html
+++ b/apps/web/src/app/features/npc/merchant-page.component.html
@@ -222,6 +222,28 @@
{{
offer.itemDescription
}}
+ @if (offer.effectSummary) {
+ {{
+ offer.effectSummary
+ }}
+ }
+ @for (
+ requirement of offer.requirements ?? [];
+ track requirement.label
+ ) {
+
+ {{ requirement.label }}
+ @if (!requirement.met && requirement.current !== null) {
+ · Current: {{ requirement.current }}
+ }
+
+ }
{{ offer.price }} Silver