From 1a73f5b396afd76b6a346dbd141ad0eea8e277a1 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 24 Sep 2026 06:38:59 +0000 Subject: [PATCH] fix(referral): show each friend's progress against the bar they cleared The referral target moved from $75 to $150 while rewards that qualified on $75 were still in their 30-day payout delay. Their rows read "$145.63/$150 spent" next to "Qualified", which looked like a mistake and was reported as one. The referral summary now sends each row's own bar (spendTargetUsd, merchantTarget): the one a qualified friend cleared, today's for everyone else. The row uses it for the spent line, the "to go" chip and the progress bar, and falls back to the program-level target when talking to a backend that doesn't send it yet. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01C4DDGA1KnJ6ADwWHFgUX4Q --- components/Referral/ReferralFriendRow.tsx | 10 ++++++++-- lib/types.ts | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/components/Referral/ReferralFriendRow.tsx b/components/Referral/ReferralFriendRow.tsx index fc0060ff..7f7b9338 100644 --- a/components/Referral/ReferralFriendRow.tsx +++ b/components/Referral/ReferralFriendRow.tsx @@ -148,6 +148,7 @@ interface StagePresentation { interface ReferralFriendRowProps { item: ReferralRewardListItem; index: number; + /** Program-level targets, for rows the API sends without their own bar. */ spendTargetUsd: number; merchantTarget: number; /** Called when a countdown reaches zero, so the screen can re-fetch. */ @@ -157,10 +158,15 @@ interface ReferralFriendRowProps { export default function ReferralFriendRow({ item, index, - spendTargetUsd, - merchantTarget, + spendTargetUsd: programSpendTargetUsd, + merchantTarget: programMerchantTarget, onPayoutDue, }: ReferralFriendRowProps) { + // The row's own bar when the API sends one: a friend who qualified before the + // target moved is measured against the bar they cleared, not today's. + const spendTargetUsd = item.spendTargetUsd ?? programSpendTargetUsd; + const merchantTarget = item.merchantTarget ?? programMerchantTarget; + const countdown = useReferralCountdown( item.stage === ReferralFriendStage.REWARD_UNLOCKING ? item.payoutEtaAt : null, ); diff --git a/lib/types.ts b/lib/types.ts index c07cc6ea..b5528c97 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -3034,6 +3034,15 @@ export interface ReferralRewardListItem { paidAt?: string; spendUsd: number; merchantCount: number; + /** + * The bar this row is measured against. For a friend who has qualified it is + * the bar they cleared, which can be lower than today's — the target moved + * from $75 to $150 while rewards were still in their payout delay, and + * "$80/$150 spent" next to "Qualified" reads as a mistake. Absent on backends + * that predate it, where the program-level target applies. + */ + spendTargetUsd?: number; + merchantTarget?: number; hasActiveCard: boolean; rewardUsd: number; /**