Skip to content

feat(rewards): campaign end winner UX — gap fixes for RWDS-1168#29027

Closed
VGR-GIT wants to merge 11 commits into
mainfrom
RWDS-1168-show-a-persistent-toast-to-users-who-participated-at-end-of-campaign-1
Closed

feat(rewards): campaign end winner UX — gap fixes for RWDS-1168#29027
VGR-GIT wants to merge 11 commits into
mainfrom
RWDS-1168-show-a-persistent-toast-to-users-who-participated-at-end-of-campaign-1

Conversation

@VGR-GIT
Copy link
Copy Markdown
Contributor

@VGR-GIT VGR-GIT commented Apr 20, 2026

Context

Builds on top of #29017 (feat(rewards): Add ondo campaign winning toast). Makes it so the scope of the piece of work for this & the targeting pr branch is only about the winning view that can be navigated to from a card/banner shown in stats section on details page OR on dedicated stats page.

Changelog

CHANGELOG entry: null

Screenshots

Winning page, auto opened when qualified and user visits detail page. Skip for now or X at top right closes/navigates back to detail page.

image

Primary CTA opens mail and has the winning code in subject

image

Details page showing banner that you won; tapping it navigates back to winning page

image

Stats page also showing the winning banner. If user skips or taps the x at top right it closes/navigates back to stats page

image

If for some reason the position isn't available and not loading

image

If for some reason the position isn't available and we are loading it

image

If for some reason the winning code isn't available and we had an error fetching it

image

If for some reason the winning code isn't available and we're loading it

image

Note there's a animated border effect on the winning banner just like in the figma design. It loops in an interval.
The winning code hook/controller/service function is right now just a placeholder until the backend implements an api endpoint for it.


Note

Medium Risk
Introduces a new navigation route and winner auto-redirect logic plus a new authenticated rewards API call path; regressions would mainly affect rewards UX/flow rather than core wallet security.

Overview
Adds a new Ondo campaign winner experience: a RewardsOndoCampaignWinning screen with hero UI that shows rank/return, fetches a per-user winning code, supports copy-to-clipboard + analytics, and opens a prefilled mailto: to claim the prize (with loading/error/retry handling).

Updates Ondo campaign details/stats flows to detect top-5 qualified winners (isOndoCampaignWinner), show an animated OndoWinnerBanner, and deep-link/navigate into the winning screen (including passing campaignName in nav params); details view also auto-navigates to the winning screen on focus when a completed campaign winner is detected.

Extends the Rewards engine surface area with a new controller + data-service action getOndoCampaignWinnerCode (plain-text endpoint, no caching, errors propagated), adds new toast presets (campaignWon/campaignEnded) and i18n strings/assets, and refactors Rewards stack side-effect hooks into a RewardsSubscriber mounted only when not version-blocked.

Reviewed by Cursor Bugbot for commit a83843c. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions
Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbotv2 metamaskbotv2 Bot added the team-rewards Rewards team label Apr 20, 2026
- Add useOndoCampaignWinnerCode hook (subscription-scoped, returns claim
  code + loading state) replacing direct useSelector calls in the winning view
- Remove misleading prizeDisplay (currentUsdValue is portfolio value, not
  a prize amount); winning view now shows: You won → rank → rate of return
- Fix mailto subject to include the claim code:
  "Ondo campaign prize claim - {code}"
- useMaybeShowCampaignEndToast: winner path no longer dispatches
  markCampaignEndToastShown so the campaignWon toast re-appears on every
  app open (session-only dismissal); loser path unchanged (persisted)
- OndoCampaignDetailsView: add useFocusEffect auto-navigation to
  OndoCampaignWinningView for winners on every campaign page session open
- Fix test mocks for OndoCampaignWinningView and useMaybeShowCampaignEndToast
  to break transitive Engine import chains that prevented tests from running

Co-authored-by: VGR-GIT <vangulckrik@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
@VGR-GIT VGR-GIT force-pushed the RWDS-1168-show-a-persistent-toast-to-users-who-participated-at-end-of-campaign-1 branch from a1b5d22 to 1b37ec5 Compare April 21, 2026 12:46
@github-actions github-actions Bot added size-L and removed size-M labels Apr 21, 2026
@VGR-GIT VGR-GIT marked this pull request as ready for review April 21, 2026 12:50
@VGR-GIT VGR-GIT requested a review from a team as a code owner April 21, 2026 12:50
@metamaskbotv2 metamaskbotv2 Bot added the INVALID-PR-TEMPLATE PR's body doesn't match template label Apr 21, 2026
Comment thread app/components/UI/Rewards/hooks/useOndoCampaignWinnerCode.ts Outdated
…innerCode

The hook only returned { code, isLoading }, causing hasFetched, hasError,
and retry to be undefined at runtime in OndoCampaignWinningView — breaking
auto-redirect for non-winners, hiding the error banner on fetch failures,
and making the retry button a no-op.

Co-authored-by: VGR-GIT <vangulckrik@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread app/components/UI/Rewards/hooks/useMaybeShowCampaignEndToast.ts Outdated
…, winning code retry

- Show primary CTA as loading while winning code is fetching
- Hide rank/rate section silently when position unavailable (no error UI)
- Wire retry into winning code error banner
- Full test coverage for all states

Co-authored-by: VGR-GIT <vangulckrik@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread app/core/Engine/controllers/rewards-controller/RewardsController.ts Outdated
@github-actions github-actions Bot added size-XL and removed size-L labels Apr 22, 2026
@VGR-GIT VGR-GIT changed the base branch from RWDS-1168-show-a-persistent-toast-to-users-who-participated-at-end-of-campaign to main April 22, 2026 06:42
@VGR-GIT VGR-GIT requested a review from a team as a code owner April 22, 2026 06:42
@github-actions
Copy link
Copy Markdown
Contributor

E2E Fixture Validation — Schema is up to date
12 value mismatches detected (expected — fixture represents an existing user).
View details

Comment thread app/components/UI/Rewards/Views/OndoCampaignStatsView.tsx Outdated
@github-actions github-actions Bot added the risk:medium AI analysis: medium risk label Apr 22, 2026
@codecov-commenter
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 11.59420% with 183 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.78%. Comparing base (88bb30c) to head (063cf07).
⚠️ Report is 64 commits behind head on main.

Files with missing lines Patch % Lines
...s/UI/Rewards/hooks/useMaybeShowCampaignEndToast.ts 6.25% 60 Missing ⚠️
...nents/UI/Rewards/Views/OndoCampaignWinningView.tsx 9.30% 39 Missing ⚠️
...ents/UI/Rewards/hooks/useOndoCampaignWinnerCode.ts 0.00% 19 Missing ⚠️
app/components/UI/Rewards/utils/formatUtils.ts 0.00% 12 Missing ⚠️
...ponents/UI/Rewards/Views/OndoCampaignStatsView.tsx 0.00% 10 Missing ⚠️
.../Rewards/components/Campaigns/OndoWinnerBanner.tsx 16.66% 10 Missing ⚠️
...ards/components/Campaigns/CampaignStatsSummary.tsx 0.00% 6 Missing ⚠️
...pp/components/UI/Rewards/hooks/useRewardsToast.tsx 0.00% 6 Missing ⚠️
app/components/UI/Rewards/RewardsSubscriber.tsx 16.66% 5 Missing ⚠️
...ontrollers/rewards-controller/RewardsController.ts 0.00% 5 Missing ⚠️
... and 6 more
Additional details and impacted files
@@             Coverage Diff             @@
##             main   #29027       +/-   ##
===========================================
- Coverage   82.26%   49.78%   -32.49%     
===========================================
  Files        5055     5101       +46     
  Lines      133121   134507     +1386     
  Branches    29795    30200      +405     
===========================================
- Hits       109518    66959    -42559     
- Misses      16173    61778    +45605     
+ Partials     7430     5770     -1660     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeWalletPlatform
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: low
  • AI Confidence: 78%
click to see 🤖 AI reasoning details

E2E Test Selection:
The changes in this PR are entirely self-contained within the Rewards feature (Ondo campaign winner flow). Key changes include:

  1. RewardsController (critical file): Purely additive - new getOndoCampaignWinnerCode method added. No breaking changes to existing methods or state.
  2. RewardsDataService: New action handler registered (stub implementation). Additive only.
  3. RewardsControllerMessenger: New action type added to allowed actions. Additive only.
  4. RewardsNavigator: Refactored to extract background hooks into RewardsSubscriber component, and added new OndoCampaignWinningView screen. The refactoring preserves existing behavior.
  5. OndoCampaignWinningView: Entirely new screen for winner code display.
  6. OndoCampaignStatsView/DetailsView: Added winner banner and navigation to new winning view.
  7. Routes.ts: Added new REWARDS_ONDO_CAMPAIGN_WINNING_VIEW route (additive, no existing routes modified).
  8. locales/en.json: New i18n strings added.

No existing E2E tests cover the Rewards feature directly (confirmed by searching tests/smoke//*.ts and tests/e2e//*.ts). The changes don't touch shared navigation components (TabBar, MainNavigator structure), confirmations, browser, or any other cross-cutting infrastructure.

SmokeWalletPlatform is selected conservatively because: (1) Rewards is part of the wallet platform ecosystem, (2) the Routes.ts change adds a new route, and (3) the RewardsNavigator refactoring could theoretically affect wallet platform navigation state. This provides a safety net without over-testing unrelated areas.

No other tags are warranted since: the changes don't affect confirmations, accounts, identity, networks, trade, browser, snaps, ramps, card, perps, predictions, or multichain APIs.

Performance Test Selection:
The changes are entirely within the Rewards feature (Ondo campaign winner flow). No performance-sensitive areas are affected: no account list rendering, no login/onboarding flows, no swap flows, no app startup/initialization changes, no asset loading changes. The new OndoCampaignWinningView is a simple display screen with minimal rendering complexity. The RewardsController changes are additive API method additions with no impact on app startup or critical rendering paths.

View GitHub Actions results

Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ad34f57. Configure here.

Comment thread app/components/UI/Rewards/Views/OndoCampaignStatsView.tsx
Comment thread app/components/UI/Rewards/hooks/useOndoCampaignWinnerCode.dev-mock.test.ts Outdated
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
45.6% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@github-actions
Copy link
Copy Markdown
Contributor

AI PR Analysis

🚫 Merge safe: false | 🟠 Risk: high

Merge decision: Multiple high-severity bugs flagged by automated review are unresolved: the winning view auto-dismisses immediately due to a stub returning empty string, the hook's hasFetched/hasError/retry return values are missing (making error UI unreachable), and the winner toast's hasShownToast flag is never persisted for winners. These issues make the primary new feature (OndoCampaignWinningView) non-functional in production.

  • Winning view auto-dismisses immediately: getOndoCampaignWinnerCode stub returns '' (empty string); !winningCode is true, so navigation.goBack() fires on mount — the winning view is completely unusable for any winner navigated there.
  • Hook return values mismatch: useOndoCampaignWinnerCode returns { code, isLoading, hasFetched, hasError, retry } but the cursor bot flagged that the hook was originally missing hasFetched, hasError, and retry — the view destructures all five; if the hook implementation doesn't match the interface, error UI and auto-redirect logic are broken.
  • Controller error-swallowing: getOndoCampaignWinnerCode catches all errors and returns null, so hasError in the hook is never set to true, making the RewardsErrorBanner with "Try again" dead code.
  • Winner toast not persisted: dispatch(markCampaignEndToastShown(campaignId)) was removed from onCampaignEndWinnerLinkPress but kept in the parallel ended handler — winners will see the toast on every app session.
  • Premature winner banner: isOndoCampaignWinner only checks rank <= 5 && qualified === true without verifying campaign completion status — active-campaign top-5 users see "You won" prematurely.
  • Winner navigation loses campaign name: navigateToWinningView uses campaign?.name ?? '' ignoring routeCampaignName from route params — empty name when campaign isn't in Redux store.
  • Reducer type cast: state.campaigns = action.payload as unknown as typeof state.campaigns is a workaround for TS recursion but masks potential type mismatches at runtime.
  • New route added: REWARDS_ONDO_CAMPAIGN_WINNING_VIEW added to Routes.ts — low risk but requires navigator registration (confirmed in RewardsNavigator.tsx).
  • New messenger action: RewardsDataService:getOndoCampaignWinnerCode registered and wired through the messenger chain — additive, low risk.
  • RewardsSubscriber refactor: Side-effect hooks extracted to a new component; functionally equivalent but changes mount lifecycle slightly.

View run

@github-actions github-actions Bot added risk:high AI analysis: high risk and removed risk:medium AI analysis: medium risk labels Apr 22, 2026
@VGR-GIT VGR-GIT closed this Apr 22, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 22, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

INVALID-PR-TEMPLATE PR's body doesn't match template risk:high AI analysis: high risk size-XL team-rewards Rewards team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants