Skip to content

feat(predict): Implement Predict Bet Slip PRED-707 cp-7.74.0#28779

Merged
MarioAslau merged 38 commits into
mainfrom
feat/pred-707
Apr 16, 2026
Merged

feat(predict): Implement Predict Bet Slip PRED-707 cp-7.74.0#28779
MarioAslau merged 38 commits into
mainfrom
feat/pred-707

Conversation

@MarioAslau
Copy link
Copy Markdown
Contributor

@MarioAslau MarioAslau commented Apr 13, 2026

Description

Migrate the Predict Buy and Sell preview screens from full-screen stack navigation into BottomSheet wrappers, gated behind the predictBottomSheet LaunchDarkly feature flag. When the flag is OFF, the existing full-screen navigation flow is preserved with zero behavioral changes.

What changed

New: PredictPreviewSheet wrapper component

  • Generic BottomSheet wrapper that renders buy/sell preview content as children.
  • Uses BottomSheet, BottomSheetHeader, and BottomSheetHeaderVariant from @metamask/design-system-react-native (not the deprecated component-library version).
  • Supports renderHeader prop for custom header content (sell sheet uses it for rich cashout info); falls back to default icon+title+subtitle layout (buy sheet).
  • isFullscreen prop controls sheet height: content-fitted for both buy and sell sheets (auto-sizes to content).
  • Title and subtitle elements expose testID props (preview-sheet-title, preview-sheet-subtitle) for testID-based assertions.
  • Unit tests for the wrapper component.

New: PredictPreviewSheetContext (central sheet state manager)

  • Context provider manages both buy and sell sheet refs, params, and open/close lifecycle.
  • Exposes openBuySheet() / openSellSheet() methods consumed by all card components.
  • Feature flag check determines whether to navigate (old flow) or open a sheet (new flow).
  • SellSheetHeader extracted as a standalone component within the context for the rich header.
  • Graceful fallback: usePredictPreviewSheet() returns navigation-based routing when used outside the provider (e.g. home carousel, trending feed) instead of throwing, with memoized references to prevent unnecessary re-renders.
  • Nonce-based re-open mechanism to handle identical params across consecutive sheet opens.
  • Unit tests for the context provider.

New: predictBottomSheet feature flag

  • Registered in feature-flag-registry.ts as a remote, version-gated flag (default: disabled).
  • New selector selectPredictBottomSheetEnabledFlag in selectors/featureFlags/index.ts.

New: PredictQuickAmounts component (with haptic feedback)

  • Standalone quick-pick buttons ($20, $50, $100, $250) displayed in the bottom content area of the buy sheet.
  • Uses expo-haptics (impactAsync with ImpactFeedbackStyle.Light) for tactile feedback on button press. impactAsync is properly awaited with error swallowing for unsupported devices.
  • Quick amounts set the input to whole numbers (e.g. "20" not "20.00") for easier editing.
  • Disabled buttons are verified non-functional in tests.
  • Uses design-system Box component instead of raw View.
  • Unit tests including haptic feedback verification and async handler coverage.

New: usePredictCashOut hook (shared cashout logic)

  • Encapsulates the guarded cashout action flow: find outcome by position.outcomeId, call openSellSheet, and handle errors with Logger.error + toast notification.
  • Accepts market and callerName parameters; callerName is included in error metadata for production diagnostics.
  • Consumed by both PredictPicks and PredictPositionDetail, eliminating ~40 lines of identical code from each.
  • Exported from hooks/index.ts.
  • Unit tests covering guarded action invocation, openSellSheet params, error/toast on missing outcome, and callerName in metadata.

Navigation migration (10 components updated)
All components that previously called navigateToBuyPreview() / navigate(Routes.PREDICT.MODALS.SELL_PREVIEW) now call openBuySheet() / openSellSheet() from usePredictPreviewSheet:

  • PredictMarketDetails - outcome buy actions
  • PredictMarketSingle - Yes/No buy buttons
  • PredictMarketMultiple - outcome buy buttons
  • PredictMarketOutcome - price buttons
  • PredictSportCardFooter - feed card buy actions
  • FeaturedCarouselCard - carousel card outcome buy buttons
  • FeaturedCarouselSportCard - sport carousel card buy buttons
  • PredictPicks - cashout from picks list via shared usePredictCashOut hook
  • PredictPositionDetail - cashout from position detail via shared usePredictCashOut hook
  • Removed direct dependency on usePredictNavigation from all these components.

Routes (routes/index.tsx)

  • Wrapped the stack navigator with PredictPreviewSheetProvider so sheets are available throughout the Predict navigation tree.

Buy sheet (PredictBuyWithAnyToken)

  • Uses discriminated union props (mode: 'sheet' | 'screen') for type-safe sheet vs navigation mode, replacing Partial<ContentProps> with as casts.
  • Sheet mode layout: header hidden (provided by PredictPreviewSheet), PredictQuickAmounts in bottom content, PredictPayWithRow in compact variant="row" mode with balance display, keypad moved below bottom content with hideHeader, border hidden, action button displays "Confirm".
  • Uses Box wrapper instead of SafeAreaView in sheet mode.
  • PredictPayWithAnyTokenInfo receives isInputFocused: false in sheet mode to ensure mm_pay relay configuration runs immediately (prevents underfunded deposit).
  • Sheet cleanup: unmount runs onReject + clearActiveOrderTransactionId (matches beforeRemove behavior in old flow).
  • Approval request recovery: when approvalRequest is missing during handleConfirm in PAY_WITH_ANY_TOKEN state, attempts re-initialization via initPayWithAnyToken() (clears batchIdRef, rejects pending transactions, re-creates the approval) before returning PLACE_ORDER_FAILED. This gives the user a chance to retry with a fresh approval rather than silently failing.

Buy sheet (PredictBuyPreview - legacy non-pay-with-any-token)

  • Same discriminated union props / isSheetMode pattern for BottomSheet compatibility.
  • Header and back button hidden in sheet mode; close action routed to onClose().
  • Uses ScrollView from react-native-gesture-handler (aliased as GHScrollView) in sheet mode to cooperate with the BottomSheet's PanGestureHandler; standard React Native ScrollView preserved for the full-screen path.

Sell sheet (PredictSellPreview)

  • Same discriminated union props pattern; isSheetMode drives conditional layout: icon+title row hidden in sheet mode (rendered by SellSheetHeader in the sheet header instead), price/shares/PnL section relocated to the bottom area.
  • Sheet mode uses inline Tailwind tw.style('flex-col') instead of StyleSheet.create() for the container.
  • Extracted getCashoutInfoText helper into utils/format.ts to DRY up the localized cashout info string.

PredictController (batch transaction fix)

  • Added gasFeeToken: MATIC_CONTRACTS.collateral to the initPayWithAnyToken batch submission, matching other batch calls. This ensures mm_pay configures the relay step to bridge funds when the Safe has insufficient USDC balance.

PredictKeypad

  • New hideHeader prop to suppress the quick-amount row + Done button when rendered inside the buy sheet (avoids duplication with PredictQuickAmounts).

PredictPayWithRow

  • New variant="row" mode: compact single-row layout showing token icon, symbol, balance, and right chevron for the sheet.
  • New availableBalance prop for displaying balance in row mode.

PredictBuyAmountSection

  • New hideAvailableBalance prop to suppress the "Available: $X.XX" text in sheet mode.

PredictBuyBottomContent

  • New hideBorder prop to remove the top border separator in sheet mode.
  • Restored inline text wrapping for the disclaimer + "Learn more" link (nested Text instead of sibling flex items).

PredictBuyActionButton

  • New isSheetMode prop: when true, displays "Confirm" label instead of "{outcome} · {price}".

PredictFeeSummary

  • Removed "incl. fees" subtitle text; moved info icon inline next to "Total" on the same line.
  • Total amount typography changed from HeadingMd/Bold to BodyMd/Medium to match Pay With row.

Bug fixes

  • usePredictBuyConditions: Auto-revert effect that switched back to Predict balance now requires totalPayForPredictBalance > 0, preventing immediate revert when the amount is 0 (which always caused the payment method selection to snap back in sheet mode).
  • usePredictBuyConditions: shouldWaitForPayFees now also requires currentValue > 0.
  • usePredictBuyActions: When approvalRequest is missing during handleConfirm in PAY_WITH_ANY_TOKEN state, attempts re-initialization (initPayWithAnyToken()) before returning early with error, giving the user a retry path rather than silently failing. Removed dead fallback branch that was unreachable (transactionId derived from the same approvalRequest).
  • usePredictBuyActions: batchIdRef cleared at the start of doInit() to prevent stale values between transaction attempts.
  • usePredictBuyActions: Sheet unmount cleanup mirrors beforeRemove behavior from the old flow.
  • usePredictBuyActions: DEPOSITING and SUCCESS state effects check isSheetMode to call onClose() instead of StackActions.pop().
  • usePredictBuyError: Removed isInputFocused from the blockingPayAlertMessage gate. The flag was permanently suppressing insufficient-funds errors in sheet mode because isInputFocused initialized to true and never transitioned to false when using quick-amount buttons. The isPayFeesLoading check already handles stale-data concerns.
  • PredictPicks / PredictPositionDetail: Cashout logic (outcome lookup, openSellSheet, error handling with Logger.error + toast) extracted into shared usePredictCashOut hook to eliminate duplication.
  • PredictPayWithAnyTokenInfo: isInputFocused overridden to false in sheet mode so updatePendingAmount and setPayToken run immediately, ensuring mm_pay relay step is configured before confirmation.
  • PredictController: Added gasFeeToken to initPayWithAnyToken batch to fix missing mm_pay relay step that caused "Insufficient USDC balance in Safe" errors.
  • PredictPreviewSheetContext: Stabilized onDismiss callbacks with useCallback to prevent unstable closeSheet/onClose references from causing repeated SUCCESS/DEPOSITING effect re-fires.

Code quality

  • Extracted shared usePredictCashOut hook to deduplicate identical onCashOut logic (~40 lines each) from PredictPicks and PredictPositionDetail. Both components now use a single hook call instead of duplicating the guarded action, outcome lookup, openSellSheet call, and error handling with Logger.error + toast. The callerName parameter preserves per-component error metadata.
  • Replaced raw View with design-system Box in PredictQuickAmounts.
  • Removed stale comments from usePredictBottomSheet.
  • Discriminated union types (PredictBuyPreviewProps, PredictSellPreviewProps) replace Partial<ContentProps> with as casts, providing compile-time safety for sheet vs navigation mode.
  • New test IDs: BUY_PREVIEW_SHEET, SELL_PREVIEW_SHEET.
  • Memoized fallback return value in usePredictPreviewSheet to prevent unstable function references.
  • Memoized BuyComponent selection in PredictPreviewSheetContext with useMemo to prevent unnecessary unmount/remount cycles.
  • Added index.ts barrel export for PredictPreviewSheet component (file organization standard).
  • Restored slide-from-right cardStyleInterpolator on BUY_PREVIEW and SELL_PREVIEW stack screens for the flag-OFF full-screen path.
  • Replaced require() with jest.requireActual() in all test mock factories.
  • Fixed module-level shared mutable state (navigationRef) in routes/index.test.tsx — moved to beforeEach.
  • Strengthened test assertions in PredictMarketDetails.test.tsx to verify exact call parameters with expect.objectContaining().
  • Removed dead/unused predict.order.buy i18n key and its stale test mock reference.
  • Migrated PredictPreviewSheet from deprecated component-library BottomSheet to @metamask/design-system-react-native BottomSheet/BottomSheetHeader (DS-first UI rule). Updated usePredictBottomSheet hook to import BottomSheetRef from DS.
  • Replaced shouldNavigateBack={false} with DS equivalent (omit goBack prop); changed header style prop to twClassName.
  • PredictBuyPreview: Uses gesture-handler-aware ScrollView from react-native-gesture-handler in sheet mode to prevent scroll/dismiss conflicts with the BottomSheet's PanGestureHandler on Android.
  • Replaced all toBeNull() assertions with not.toBeOnTheScreen() in test files per unit-test guidelines.
  • Replaced text-based queries (getByText, queryByText) with testID-based assertions (getByTestId + toHaveTextContent) in PredictPreviewSheet.test.tsx and PredictPreviewSheetContext.test.tsx.
  • Changed synchronous act() to await act(async () => { ... }) in routes/index.test.tsx to flush async navigator state updates and eliminate act() warnings.

Localization

  • Added predict.odds key ("Odds").
  • Added predict.order.confirm key ("Confirm") for the sheet action button.
  • Removed unused predict.order.buy key ("Buy {{outcome}}").

Documentation

  • Added comprehensive Predictions architecture guide (docs/predict/predictions-comprehensive-guide.md).
  • Added ticket documentation (docs/predict/tickets/buy-sell-bottomsheet-migration.md).

Changelog

CHANGELOG entry: null

Related issues

Refs: PRED-707

Manual testing steps

Feature: Predict Buy/Sell BottomSheet Migration

  Scenario: Buy prediction via bottom sheet (flag ON)
    Given the predictBottomSheet feature flag is enabled
    And the user is on a prediction market details page

    When user taps a "Yes" or "No" outcome button
    Then a bottom sheet opens with the buy preview content
    And the sheet header shows the outcome icon, "Yes/No · Outcome Name" title, and odds subtitle
    And quick amount buttons ($20, $50, $100, $250) are visible with haptic feedback
    And the user can enter an amount, select payment method, and tap "Confirm"
    And the order is placed successfully
    And the sheet closes after the deposit is initiated

  Scenario: Sell position via bottom sheet (flag ON)
    Given the predictBottomSheet feature flag is enabled
    And the user has an active position on a market

    When user taps "Cash out" on their position
    Then a content-fitted bottom sheet opens (not fullscreen)
    And the sheet header shows the position icon, title, and cashout info
    And the body shows the current value, shares, PnL, and Cash out button
    And tapping "Cash out" places the sell order and closes the sheet

  Scenario: Buy prediction via full-screen navigation (flag OFF)
    Given the predictBottomSheet feature flag is disabled
    And the user is on a prediction market details page

    When user taps a "Yes" or "No" outcome button
    Then the app navigates to the full-screen BuyPreview screen
    And the existing layout and behavior are unchanged

  Scenario: Sell position via full-screen navigation (flag OFF)
    Given the predictBottomSheet feature flag is disabled
    And the user has an active position on a market

    When user taps "Cash out" on their position
    Then the app navigates to the full-screen SellPreview screen
    And the existing layout and behavior are unchanged

  Scenario: Change payment method in buy sheet (flag ON)
    Given the predictBottomSheet feature flag is enabled
    And the buy bottom sheet is open

    When user taps the Pay with row and selects a different token (e.g. USDC)
    Then the payment method updates and stays selected
    And the fee summary and total update accordingly

  Scenario: Buy from feed cards and carousel (flag ON)
    Given the predictBottomSheet feature flag is enabled
    And the user is on the Predict feed or homepage carousel

    When user taps a Yes/No button on any market card
    Then the bottom sheet opens with the correct market/outcome pre-filled
    And the flow works identically to opening from market details

  Scenario: Components outside PredictScreenStack (flag ON)
    Given the predictBottomSheet feature flag is enabled
    And a Predict card is rendered on the homepage carousel (outside PredictScreenStack)

    When user taps a Yes/No button
    Then the app navigates via React Navigation (fallback behavior)
    And no crash occurs from missing PredictPreviewSheetProvider

  Scenario: Quick amount haptic feedback (flag ON)
    Given the buy bottom sheet is open

    When user taps a quick amount button ($20, $50, $100, or $250)
    Then haptic feedback fires (Light impact)
    And the amount input updates to the selected value
    And the input unfocuses

Screenshots/Recordings

Before

Full-screen buy/sell preview navigation (flag OFF) - no visual changes to this flow.

After

newDemoPRedict.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
Touches Predict trade entry points and preview/cash-out flows, plus introduces a new feature-flagged UI layer; regressions could affect order preview UX or sheet/navigation behavior, though the legacy route path remains as fallback.

Overview
Adds a new feature-flagged bet slip flow for Predict by introducing PredictPreviewSheet + PredictPreviewSheetProvider/usePredictPreviewSheet, allowing buy/sell previews to open in BottomSheets (with navigation fallback when the provider/flag isn’t available).

Updates multiple Predict entry points (feed cards, carousel cards, market single/multiple/outcome components, and sport footer) to call openBuySheet instead of navigating to the buy preview, and refactors cash-out handling into a shared usePredictCashOut hook that opens the sell sheet and handles missing-outcome errors via logging + toast.

Extends buy preview screens (PredictBuyPreview, PredictBuyWithAnyToken) to support a new mode: 'sheet' rendering path (layout tweaks, keypad/header behavior, confirm CTA), adds new test IDs/feature-flag selectors (predictBottomSheet), and adjusts provider order result shape and assorted tests to match the new behavior.

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

@MarioAslau MarioAslau self-assigned this Apr 13, 2026
@MarioAslau MarioAslau added the team-predict Predict team label Apr 13, 2026
@MarioAslau MarioAslau requested review from caieu and matallui April 13, 2026 23:16
@MarioAslau MarioAslau marked this pull request as ready for review April 14, 2026 00:50
@MarioAslau MarioAslau requested a review from a team as a code owner April 14, 2026 00:50
@MarioAslau MarioAslau requested a review from ghgoodreau April 14, 2026 00:52
Comment thread app/components/UI/Predict/contexts/PredictPreviewSheetContext.tsx Outdated
Comment thread app/components/UI/Predict/views/PredictBuyPreview/PredictBuyPreview.tsx Outdated
@github-actions github-actions Bot added the risk-high Extensive testing required · High bug introduction risk label Apr 14, 2026
Comment thread app/components/UI/Predict/views/PredictSellPreview/PredictSellPreview.tsx Outdated
Comment thread app/components/UI/Predict/routes/index.tsx
@github-actions github-actions Bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-high Extensive testing required · High bug introduction risk labels Apr 14, 2026
Comment thread app/components/UI/Predict/components/PredictPicks/PredictPicks.tsx Outdated
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 14, 2026

Codecov Report

❌ Patch coverage is 92.98246% with 20 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.24%. Comparing base (37b1dcf) to head (07d3a0b).
⚠️ Report is 10 commits behind head on main.

Files with missing lines Patch % Lines
...edictBuyWithAnyToken/hooks/usePredictBuyActions.ts 87.23% 4 Missing and 2 partials ⚠️
...UI/Predict/contexts/PredictPreviewSheetContext.tsx 92.42% 1 Missing and 4 partials ⚠️
...ithAnyToken/hooks/usePredictDefaultPaymentToken.ts 40.00% 2 Missing and 1 partial ⚠️
...ct/views/PredictSellPreview/PredictSellPreview.tsx 90.00% 1 Missing and 1 partial ⚠️
...Predict/providers/polymarket/PolymarketProvider.ts 94.44% 0 Missing and 1 partial ⚠️
...dict/views/PredictBuyPreview/PredictBuyPreview.tsx 92.30% 0 Missing and 1 partial ⚠️
...redictBuyBottomContent/PredictBuyBottomContent.tsx 50.00% 0 Missing and 1 partial ⚠️
...iews/PredictMarketDetails/PredictMarketDetails.tsx 75.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #28779      +/-   ##
==========================================
+ Coverage   82.19%   82.24%   +0.05%     
==========================================
  Files        5043     5048       +5     
  Lines      132426   132759     +333     
  Branches    29571    29698     +127     
==========================================
+ Hits       108848   109191     +343     
+ Misses      16172    16159      -13     
- Partials     7406     7409       +3     

☔ 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 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 14, 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 14, 2026
@matallui matallui added this pull request to the merge queue Apr 16, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Apr 16, 2026
@matallui matallui added this pull request to the merge queue Apr 16, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Apr 16, 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 16, 2026
matallui
matallui previously approved these changes Apr 16, 2026
@MarioAslau MarioAslau enabled auto-merge April 16, 2026 18:46
@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 16, 2026
transactionId:
currentState === ActiveOrderState.PAY_WITH_ANY_TOKEN
? approvalRequest?.id
: undefined,
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.

Non-awaited onApprovalConfirm falls through to handlePlaceOrder immediately

Medium Severity

When currentState is PAY_WITH_ANY_TOKEN and approvalRequest?.id exists, onApprovalConfirm is called without await at line 180-184, then execution falls through to handlePlaceOrder at line 209. The new else branch (re-init path) correctly returns early, but the existing if branch doesn't — it fires the approval asynchronously and immediately proceeds to place the order. In the new sheet mode, this race is more visible because the sheet unmount cleanup can run before the approval completes.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 5c98134. Configure here.

@MarioAslau
Copy link
Copy Markdown
Contributor Author

Added skip sonar cloud label due to it flagging other files consistently for 1 line changes that are out of scope

const route =
useRoute<RouteProp<PredictNavigationParamList, 'PredictBuyPreview'>>();

const { market, outcome, outcomeToken, entryPoint } = route.params;
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.

Sheet mode Buy component calls useRoute outside Screen context

Medium Severity

Both PredictBuyWithAnyToken and PredictBuyPreview call useRoute() unconditionally at the top of the component. When rendered in sheet mode, these components are children of PredictPreviewSheetProvider, which sits outside the Stack.Navigator's Screen components. useRoute() requires being inside a screen's route context. If the PredictScreenStack component itself isn't rendered inside a parent navigator screen (or if the nearest route context lacks params), useRoute() could throw or return unexpected params. While the result isn't accessed in sheet mode, the hook call itself is the risk point.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 642ee64. Configure here.

Comment thread app/components/UI/Predict/controllers/PredictController.ts Outdated
matallui
matallui previously approved these changes Apr 16, 2026
/>
)}
<PredictBuyBottomContent
isInputFocused={isSheetMode ? false : isInputFocused}
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.

Sheet-mode bottom content always visible hides keypad interaction

Medium Severity

In sheet mode, PredictBuyBottomContent receives isInputFocused={false} (hardcoded), making it always visible, while the PredictKeypad (rendered below the bottom content) uses the real isInputFocused value. Since isInputFocused initializes to true, both the full bottom content (quick amounts, pay row, fee summary, confirm button) and the keypad render simultaneously on first open. The keypad's hideHeader prop removes the "Done" button, so the only way to dismiss the keypad is to tap a PredictQuickAmounts button — which overwrites any custom-typed amount. There is no way for the user to confirm a manually-typed value and dismiss the keypad without losing their input.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 78efa93. Configure here.

@github-actions
Copy link
Copy Markdown
Contributor

🔍 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 PR introduces a significant UI architecture change for the Predictions (Polymarket) feature: a new predictBottomSheet feature flag that enables buy/sell preview screens to render inside a BottomSheet overlay instead of navigating to full-screen pages.

Key changes:

  1. New predictBottomSheet feature flag in the feature flag registry - controls whether buy/sell previews use bottom sheet or full-screen navigation
  2. New PredictPreviewSheetContext - a React context provider managing bottom sheet state for buy/sell previews, with fallback to navigation-based routing for components outside PredictScreenStack
  3. New PredictPreviewSheet component - a reusable bottom sheet wrapper for buy/sell previews
  4. New usePredictCashOut hook - handles cash-out flow with error handling and toast notifications
  5. Modified PredictBuyPreview, PredictBuyWithAnyToken, PredictSellPreview - all updated to support dual mode (sheet vs full-screen navigation)
  6. Modified PredictMarketSingle, PredictMarketMultiple - switched from usePredictNavigation to usePredictPreviewSheet context
  7. Routes restructured - PredictScreenStack now wraps with PredictPreviewSheetProvider
  8. New localization strings - odds, confirm, cashout_failed

Tag selection rationale:

  • SmokePredictions: Directly impacted - the entire buy/sell/cash-out flow has been refactored to support bottom sheet mode. Position lifecycle tests (opening positions, cashing out, claiming winnings) are all affected.
  • SmokeWalletPlatform: Per tag description, Predictions is a section inside the Trending tab; changes to Predictions views (headers, lists, full views) affect Trending. The PredictMarketSingle and PredictMarketMultiple components used in Trending feeds have been modified.
  • SmokeConfirmations: Per SmokePredictions tag description, 'opening/closing positions are on-chain transactions' requiring confirmations. The Confirm component is embedded in PredictScreenStack routes, and the route restructuring could affect confirmation flows within Predict.

Performance Test Selection:
The PR introduces a new BottomSheet rendering mode for buy/sell previews in the Predictions feature. This architectural change - rendering preview content inside a BottomSheet overlay instead of navigating to full-screen pages - could impact UI rendering performance. The new PredictPreviewSheetContext adds state management overhead, and the BottomSheet component rendering with dynamic content (buy/sell previews) could affect prediction market loading and interaction performance. @PerformancePredict covers prediction market list loading, market details, deposit flows, and balance display - all of which are touched by this PR.

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.

There are 6 total unresolved issues (including 4 from previous reviews).

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 ca83caf. Configure here.

expect(getByText('Share address')).toBeOnTheScreen();
});

jest.useFakeTimers();
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.

Timer mode leak on test failure breaks isolation

Low Severity

jest.useRealTimers() is called at test start and jest.useFakeTimers() at test end, but if waitFor times out and throws, the cleanup line is skipped. Subsequent tests would then run with real timers instead of fake timers, causing hard-to-diagnose cascading failures. The cleanup belongs in a try/finally block or an afterEach to guarantee timer mode is restored regardless of test outcome.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ca83caf. Configure here.

);

expect(screen.getByText('Confirm')).toBeOnTheScreen();
expect(screen.queryByText(/· /)).toBeNull();
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.

New test assertions use toBeNull not toBeOnTheScreen

Low Severity

Newly added test assertions use .toBeNull() to check element absence (e.g., expect(screen.queryByText(...)).toBeNull()). The unit testing guidelines explicitly require not.toBeOnTheScreen() instead of toBeNull() for element presence/absence checks. The PR description itself states "Replaced all toBeNull() assertions with not.toBeOnTheScreen()" yet these new lines introduce fresh violations.

Additional Locations (1)
Fix in Cursor Fix in Web

Triggered by project rule: Unit Testing Guidelines

Reviewed by Cursor Bugbot for commit ca83caf. Configure here.

@github-actions
Copy link
Copy Markdown
Contributor

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

@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-7.75.0 Issue or pull request that will be included in release 7.75.0 risk-medium Moderate testing recommended · Possible bug introduction risk size-XL skip-sonar-cloud Only used for bypassing sonar cloud when failures are not relevant to the changes. team-predict Predict team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants