Skip to content

feat(predict): implement featured carousel#28102

Merged
matallui merged 20 commits intomainfrom
PRED-533-feature-carousel
Apr 6, 2026
Merged

feat(predict): implement featured carousel#28102
matallui merged 20 commits intomainfrom
PRED-533-feature-carousel

Conversation

@ghgoodreau
Copy link
Copy Markdown
Contributor

@ghgoodreau ghgoodreau commented Mar 30, 2026

Description

Adds a horizontally-scrollable featured carousel to the top of the Predict feed. The carousel is populated from Polymarket's homepage carousel API (polymarket.com/api/homepage/carousel), which returns their curated high-engagement markets — politics, sports, crypto, etc.

Two card variants:

  • Standard markets (politics, crypto, etc.): Single market icon above title, two outcomes side-by-side with payout prices ($100 → $159.98), percentage CTA buttons, and a footer with remaining outcomes count + end date + volume.
  • Sport markets (NBA, UCL, NFL): League name + live indicator header, team logos flanking scores, team names with payout prices, percentage/draw buttons (draw only for isDrawCapableLeague), and footer with time remaining + volume.

The carousel is gated behind a predictFeaturedCarousel remote feature flag (version-gated, defaults to false). When enabled, it renders between the balance header and the tab bar in the Predict feed.

The carousel API returns outcomes, outcomePrices, and clobTokenIds as native arrays (unlike the gamma API which returns them as JSON strings), so the fetch layer normalizes them to strings before passing to the existing parsePolymarketEvents parser.

Data flow follows existing patterns: useFeaturedCarouselDataPredictController.getCarouselMarkets()PolymarketProvider.getCarouselMarkets()fetchCarouselFromPolymarketApi() with full team loading, TeamsCache, and GameCache.overlayOnMarkets().

Changelog

CHANGELOG entry: Added featured carousel to the top of the Predict feed showing curated markets from Polymarket

Related issues

Fixes: https://consensyssoftware.atlassian.net/browse/PRED-533

Manual testing steps

Feature: Featured Carousel on Predict Feed

  Scenario: carousel renders with live market data
    Given the predictFeaturedCarousel feature flag is enabled
    And the user navigates to the Predict feed

    When the feed loads
    Then a horizontal carousel appears between the balance header and the tab bar
    And it contains cards populated from the Polymarket homepage carousel API
    And pagination dots appear below the carousel matching the number of cards

  Scenario: user swipes through carousel cards
    Given the carousel is visible with multiple cards

    When the user swipes left on the carousel
    Then the next card snaps into view
    And the active pagination dot updates to reflect the current card

  Scenario: standard market card displays correctly
    Given a non-sport market card is visible (e.g. "US forces enter Iran by..?")

    Then the card shows a single market icon above the title
    And two outcomes are displayed side-by-side with names and payout prices
    And each outcome has a percentage CTA button (e.g. "47%", "45%")
    And the footer shows remaining outcomes count and volume

  Scenario: sport market card displays correctly
    Given a sport market card is visible (e.g. an NBA or UCL match)

    Then the card shows the league name and live indicator in the header
    And team logos appear on the left and right with scores between them
    And team names and payout prices appear below the logos
    And percentage buttons appear for each team
    And a Draw button appears between team buttons for UCL matches only
    And the footer shows time remaining and volume

  Scenario: tapping a carousel card opens market details
    Given any carousel card is visible

    When the user taps the card
    Then the app navigates to the full market detail screen for that market

  Scenario: tapping a buy button opens the buy preview
    Given a carousel card with percentage CTA buttons is visible

    When the user taps a percentage button on a standard card
    Then the buy preview screen opens for that outcome

  Scenario: carousel is hidden when feature flag is disabled
    Given the predictFeaturedCarousel feature flag is not set or disabled

    When the user navigates to the Predict feed
    Then no carousel is visible
    And the feed renders as before with just the balance header and tabs

Screenshots/Recordings

Before

After

Screenshot 2026-04-01 at 3 29 38 PM Screenshot 2026-04-01 at 3 29 46 PM Screenshot 2026-04-01 at 3 30 01 PM
demopredictcarousel.mov

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Medium Risk
Adds a new feed surface plus a new provider/controller fetch path hitting an external endpoint and normalizing/deriving sports data, which could impact feed performance and correctness if API responses change. Feature-flag gating and extensive tests reduce rollout risk.

Overview
Adds a new featured carousel section to the top of the Predict feed (behind the remote flag predictTabFeaturedCarousel), rendering a horizontally snapping list with pagination dots and skeleton loading.

Introduces two new card variants (FeaturedCarouselCard and FeaturedCarouselSportCard) with buy CTAs that route through existing guarded navigation to market details and buy preview, plus shared footer/payout formatting utilities.

Wires a new data path useFeaturedCarouselData → React Query featuredCarousel query → PredictController.getCarouselMarkets() → provider getCarouselMarkets(); implements Polymarket support by calling the homepage carousel endpoint, normalizing array fields (outcomes, outcomePrices, clobTokenIds) to the parser’s expected format, filtering invalid markets, and reusing Teams/Game cache overlays when live sports is enabled. Adds comprehensive unit tests across UI, hooks, controller, provider, and utils.

Reviewed by Cursor Bugbot for commit a15d264. 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.

@metamaskbot metamaskbot added the team-swaps-and-bridge Swaps and Bridge team label Mar 30, 2026
@ghgoodreau ghgoodreau changed the title (PRED-533) - prediction market carousel feat: (PRED-533) - prediction market carousel Mar 30, 2026
@ghgoodreau ghgoodreau force-pushed the PRED-533-feature-carousel branch from da5bd76 to 721740a Compare March 31, 2026 23:47
@github-actions github-actions bot added size-XL and removed size-M labels Mar 31, 2026
@matallui matallui changed the title feat: (PRED-533) - prediction market carousel feat(predict): implement featured carousel Apr 1, 2026
@ghgoodreau ghgoodreau marked this pull request as ready for review April 2, 2026 15:29
@ghgoodreau ghgoodreau requested a review from a team as a code owner April 2, 2026 15:29
@github-actions github-actions bot added the risk-medium Moderate testing recommended · Possible bug introduction risk label Apr 2, 2026
@github-actions github-actions bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Apr 2, 2026
@github-actions github-actions bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Apr 2, 2026
@ghgoodreau ghgoodreau added the team-predict Predict team label Apr 2, 2026
@@ -0,0 +1,21 @@
import { StyleSheet } from 'react-native';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why use StyleSheet? I believe this is against the UI guidelines.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is from bringing over some of my system prompts/skills from extension dev env. Switched to tw and removed those so it shouldn't occur again

Comment on lines +13 to +16
export const useFeaturedCarouselData = (): UseFeaturedCarouselDataResult => {
const [markets, setMarkets] = useState<PredictMarket[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's use React Query for this. We are in the process of transitioning all of our queries to RQ, so some hooks might not have it yet, but all new hooks should use it. Take a look at other queries under queries/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done! Will use from now on.

Comment on lines +427 to +438
if (liveSportsEnabled) {
const neededTeams = extractNeededTeamsFromEvents(
events,
supportedLeagues,
);

await Promise.all(
[...neededTeams.entries()].map(([league, abbreviations]) =>
TeamsCache.getInstance().ensureTeamsLoaded(league, abbreviations),
),
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I wonder if we could extract this logic out of here, since it seems we are repeating it in a few places now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done! Great suggestion, let me know what you think

Comment on lines +40 to +41
/** League logo URL for carousel/card headers. If omitted, no logo is shown. */
leagueLogo?: string;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why the need for this here? I would only add this here once we have the need to override the logo for certain leagues, otherwise we keep the default behavior (which should use the data from the API)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The Figma had some logos that I didn't recognize from the codebase, so added this here to future proof it. I agree though, I will cut it to simplify and can always add it back (or similar) later. The current code fetches from the API.

… Query, dedup team loading, remove unused leagueLogo
@github-actions github-actions bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Apr 4, 2026
@github-actions github-actions bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Apr 4, 2026
@github-actions github-actions bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Apr 6, 2026
Copy link
Copy Markdown

@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 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

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 269d36c. Configure here.

@github-actions github-actions bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Apr 6, 2026
@github-actions github-actions bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Apr 6, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 6, 2026

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokePredictions, SmokeWalletPlatform, SmokeConfirmations
  • Selected Performance tags: @PerformancePredict
  • Risk Level: medium
  • AI Confidence: 88%
click to see 🤖 AI reasoning details

E2E Test Selection:
The changes are scoped to the Predict/Polymarket feature area, introducing a new FeaturedCarousel component in the PredictFeed view. Key changes include:

  1. New FeaturedCarousel component - A horizontally scrollable FlashList-based carousel for featured prediction markets, gated behind the predictTabFeaturedCarousel feature flag (disabled by default in prod).
  2. PredictController.getCarouselMarkets() - New method to fetch carousel markets from the provider.
  3. PolymarketProvider.getCarouselMarkets() - New method + fetchCarouselFromPolymarketApi() utility + refactored #ensureTeamsLoadedForEvents() helper (clean extraction, no behavioral change to existing methods).
  4. Feature flag - predictTabFeaturedCarousel added to the registry (disabled in prod).
  5. PredictFeed - Modified to conditionally render FeaturedCarousel in the header.

SmokePredictions: Directly required - the PredictFeed view is modified with a new carousel component, PredictController is extended, and the Polymarket provider has new functionality. E2E tests should verify the Predictions feature still works correctly (positions, balance, activities).

SmokeWalletPlatform: Required per tag description - Predictions is a section inside the Trending tab, and changes to Predictions views affect Trending/SmokeWalletPlatform.

SmokeConfirmations: Required per SmokePredictions tag description - opening/closing positions are on-chain transactions requiring confirmations.

The feature flag is disabled by default in prod, so the carousel won't be visible in standard E2E tests, but the underlying PredictFeed modifications and provider changes still need validation to ensure existing flows aren't broken.

Performance Test Selection:
The PredictFeed view now includes a new FeaturedCarousel component using FlashList for horizontal scrolling of market cards. This adds a new rendering layer to the Predictions feed that could impact the performance of the Predict market list loading and display. The @PerformancePredict tag covers prediction market list loading and balance display, which is directly affected by the new carousel component in the PredictFeed header.

View GitHub Actions results

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 6, 2026

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

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 6, 2026

@matallui matallui added this pull request to the merge queue Apr 6, 2026
Merged via the queue into main with commit 2c1a56d Apr 6, 2026
100 of 101 checks passed
@matallui matallui deleted the PRED-533-feature-carousel branch April 6, 2026 17:21
@github-actions github-actions bot locked and limited conversation to collaborators Apr 6, 2026
@metamaskbot metamaskbot added the release-7.74.0 Issue or pull request that will be included in release 7.74.0 label Apr 6, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-7.74.0 Issue or pull request that will be included in release 7.74.0 risk-medium Moderate testing recommended · Possible bug introduction risk size-XL team-predict Predict team team-swaps-and-bridge Swaps and Bridge team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants