Skip to content

Conversation

@premiumjibles
Copy link
Collaborator

@premiumjibles premiumjibles commented Sep 2, 2025

Description

This is part two of the mobile wallet popover PR. Here we add the new defi and activity tabs, as well as a wallet balance 24hr delta as per the designs.

Note that defi tab was not really designed for this small view, so i've done a best effort approach here for what seems reasonable that we can iterate on

Issue (if applicable)

closes #10285

Risk

High Risk PRs Require 2 approvals

What protocols, transaction types, wallets or contract interactions might be affected by this PR?

Testing

  • Test that the wallet page still behaves normally on desktop. In particular the Defi and activity tabs
  • Make sure wallet page looks ok in mobile view. Should now have a 24 hour delta on net worth
  • Test the new defi/activity tabs on the wallet popover

Engineering

Operations

  • [ x] 🏁 My feature is behind a flag and doesn't require operations testing (yet)

Screenshots (if applicable)

https://jam.dev/c/39ea3737-3c93-4fbe-971a-2057d8910e5f

Summary by CodeRabbit

  • New Features

    • Added WalletBalanceChange showing current balance and a 24-hour change.
    • Added Transaction Activity view and expanded wallet popover tabs to include DeFi and Activity.
    • Introduced compact view modes across Earn, staking tables, and transaction lists for smaller screens.
  • UI/Style

    • Simplified tab styling with dynamic color modes.
    • Responsive adjustments hide certain columns/headers in compact mode; mobile dashboard shows 24-hour change.
  • Translations

    • Added “24-hour change” and “Transaction Details.”

@premiumjibles premiumjibles requested a review from a team as a code owner September 2, 2025 01:06
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 2, 2025

📝 Walkthrough

Walkthrough

Adds a compact/mobile rendering mode across staking and earn components, introduces a WalletBalanceChange component and 24-hour change label, expands the wallet popover with DeFi and Activity tabs (TransactionActivity), and adjusts related header/dashboard tab styling and theming.

Changes

Cohort / File(s) Change summary
Translations
src/assets/translations/en/main.json
Added keys: common.walletBalanceChange24Hr, transactionRow.transactionDetails.
Compact view — Earn & Staking UI
src/components/EarnDashboard/components/PositionDetails/PositionDetails.tsx, src/components/EarnDashboard/components/PositionDetails/StakingPositionsByProvider.tsx, src/components/StakingVaults/PositionTable.tsx, src/components/StakingVaults/DeFiEarn.tsx
Introduced optional forceCompactView?: boolean; added Chakra useMediaQuery + theme breakpoints to compute compact state; hide/show columns and headers in compact mode; pass forceCompactView through PositionTable → PositionDetails → StakingPositionsByProvider; add row-click overview behavior in compact mode.
Wallet popover / Header / Dashboard
src/components/Layout/Header/NavBar/PopoverWallet.tsx, src/pages/Dashboard/Dashboard.tsx, src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx
Reworked PopoverWallet tabs to four (My Crypto, Watchlist, DeFi, Activity); replaced net-worth UI with WalletBalanceChange in mobile places; removed custom tab selected styling; adjusted dashboard header to render WalletBalanceChange on mobile and retain WalletBalance on desktop.
Transaction history / rows
src/components/TransactionHistory/TransactionActivity.tsx, src/components/TransactionHistoryRows/TransactionRow.tsx
Added TransactionActivity component (memoized) with forceCompactView prop; small whitespace-only change in TransactionRow.
New component — Wallet balance delta
src/components/WalletBalanceChange/WalletBalanceChange.tsx
New memoized component showing fiat balance and 24-hour percent/fiat change (uses selectors, history chart hook, TooltipWithTouch, Skeletons); prop showErroredAccounts?: boolean and forwards FlexProps.
Theming
src/components/Tabs/Tabs.theme.ts
Soft-rounded Tab variant: switched selected/hover colors to color-mode-aware values and adjusted tab text color logic.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Popover as PopoverWallet (UI)
  participant Tabs
  participant DeFi as DeFiEarn / PositionTable
  participant Staking as StakingPositionsByProvider
  participant Actions as DefiAction
  User->>Popover: open wallet popover
  Popover->>Tabs: render tabs (My Crypto, Watchlist, DeFi, Activity)
  User->>Tabs: select "DeFi"
  Tabs->>DeFi: mount DeFiEarn (forceCompactView if mobile)
  DeFi->>PositionTable: render with forceCompactView
  PositionTable->>Staking: render PositionDetails / StakingPositionsByProvider (compact)
  User->>Staking: click row (compact mode)
  Staking->>Actions: trigger DefiAction.Overview (open overview)
Loading
sequenceDiagram
  participant UI
  participant WalletComp as WalletBalanceChange
  participant Store as Redux selectors / hooks
  participant Tooltip
  UI->>WalletComp: mount
  WalletComp->>Store: select portfolio balance, loading, chart data
  Store-->>WalletComp: totals, loading state, history
  WalletComp->>WalletComp: calculate percentChange, fiatChange
  alt change available
    WalletComp->>Tooltip: render "24-hour change" with value (green/red)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

high risk

Suggested reviewers

  • NeOMakinG
  • gomesalexandre

Pre-merge checks (3 passed, 2 warnings)

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Linked Issues Check ⚠️ Warning Although the pull request implements the Defi and Activity tabs and the 24-hour net worth delta, it does not include feature flag integration in code, kebab menu options (connect/disconnect, manage accounts, switch provider), or the Send, Receive, Balance, and Settings tabs specified in issue #10285, so it fails to meet the full set of acceptance criteria. To comply with the linked issue, either extend this PR to add the missing feature flag code, kebab menu options, and additional tabs or adjust the issue scope to match the implemented subset of functionality.
Out of Scope Changes Check ⚠️ Warning The PR introduces broad responsive compact-view changes across multiple core components beyond the mobile wallet popover—such as PositionDetails, StakingPositionsByProvider, PositionTable, DeFiEarn, and TransactionActivity—which are not related to the drawer-based mobile wallet UX defined in the linked issue. Extract the generic compact-view feature updates into a separate PR and limit this pull request to only the code necessary for the mobile wallet popover’s Defi, Activity, and net worth delta enhancements.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly and succinctly summarizes the primary additions in this changeset—adding Defi and Activity tabs and a 24-hour net worth delta to the mobile wallet popover—and it references the specific phase (“P2”) without extraneous detail, making it both informative and focused.
Description Check ✅ Passed The description directly relates to the code changes by describing part two of the mobile wallet popover work, listing the new Defi and Activity tabs and the wallet balance delta feature, and linking to the issue it closes, which makes it relevant to the changeset.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Poem

"I hopped through code with ears held high,
A tiny change to catch the eye.
A balance delta, tabs anew,
Compact rows that snugly view.
— your rabbit dev, 🐰"

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 10285_mobile_wallet_p2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@premiumjibles premiumjibles marked this pull request as draft September 2, 2025 01:06
@premiumjibles premiumjibles changed the title feat: add defi, activity and net worth delta to mobile wallet feat: add defi, activity and net worth delta to mobile wallet (wallet popover P2) Sep 2, 2025
@premiumjibles premiumjibles force-pushed the 10285_mobile_wallet_p2 branch 6 times, most recently from 0230304 to be48783 Compare September 2, 2025 06:10
@premiumjibles premiumjibles marked this pull request as ready for review September 2, 2025 06:11
@premiumjibles premiumjibles force-pushed the 10285_mobile_wallet_p2 branch 2 times, most recently from 44c49ca to 9ac4bd1 Compare September 2, 2025 06:18
Copy link
Collaborator

@NeOMakinG NeOMakinG left a comment

Choose a reason for hiding this comment

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

Looks like working very well, the defi tab is fine as it is with your best efforts adaptation, quite happy with this one minus some nitpick comments/preferences

Base automatically changed from 10285_mobile_wallet to develop September 3, 2025 09:14
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/components/StakingVaults/PositionTable.tsx (2)

159-169: IconButton is non-functional (no onClick) and not keyboard-activatable

The expander IconButton has no handler. Add onClick (and aria-expanded) to make it operable and accessible.

         <Flex justifyContent='flex-end' width='full'>
           <IconButton
             variant='ghost'
             size='md'
             aria-label={translate('common.table.expandRow')}
             isActive={row.isExpanded}
+            onClick={() => row.toggleRowExpanded()}
+            aria-expanded={row.isExpanded}
             icon={row.isExpanded ? <ArrowUpIcon /> : <ArrowDownIcon />}
           />
         </Flex>

183-186: Case-insensitive address search compares against unnormalized input

You build search = filterValue.trim().toLowerCase() but compare to filterValue, breaking uppercase address searches. Also guard potential undefined assetReference.

-  if (isEthAddress(filterValue)) {
-    return rows.filter(
-      row => fromAssetId(row.assetId).assetReference.toLowerCase() === filterValue,
-    )
-  }
+  if (isEthAddress(filterValue)) {
+    return rows.filter(
+      row => fromAssetId(row.assetId).assetReference?.toLowerCase() === search,
+    )
+  }
♻️ Duplicate comments (4)
src/assets/translations/en/main.json (1)

643-644: Keep common.activity as a backward-compatible alias to avoid ripple effects.

Prior reviews noted existing translations for common.activity. Keeping it (in addition to navBar.activity) reduces i18n churn and avoids regressions where old keys may still be referenced.

Apply:

   "common": {
+    "activity": "Activity",

Also verify no remaining usages of the old key:

#!/bin/bash
# Find any remaining references to common.activity
rg -n "common\\.activity" -S
src/pages/History/History.tsx (1)

93-94: Activity tab label update aligns with i18n changes.

Consistent with navBar.activity shift across the app.

src/components/WalletBalanceChange/WalletBalanceChange.tsx (1)

76-85: Use Number.isFinite and consider hiding neutral (0%) changes

  • Prefer Number.isFinite to avoid coercion.
  • Design question: do we want to hide 0% deltas (consistent with PriceChangeTag behavior)? If yes, gate on non-zero.

Apply:

-        {isFinite(percentChange) && (
+        {Number.isFinite(percentChange) && percentChange !== 0 && (
           <Skeleton mt={2} isLoaded={isChangeLoaded}>
             <TooltipWithTouch label={translate('defi.walletBalanceChange24Hr')}>
               <Flex gap={1} fontSize={changeFontSize} color={color} fontWeight='medium'>
                 <Amount.Fiat value={fiatChange} /> (
-                {formattedPercentChange})
+                <Amount.Percent value={percentChange} />)
               </Flex>
             </TooltipWithTouch>
           </Skeleton>
         )}
src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx (1)

74-80: Keeping JSX constants outside component is fine

The ESLint disable is justified to avoid recreating nodes; the pattern matches prior decisions to keep perf simple without over-memoizing.

Also applies to: 257-266

🧹 Nitpick comments (11)
src/components/TransactionHistoryRows/TransactionRow.tsx (1)

93-97: Make toggleOpen stable and avoid stale state with a functional update.

Use a functional state update and drop isOpen from deps to prevent stale captures and unnecessary re-creations.

Apply:

-    const toggleOpen = useCallback(
-      () => (disableCollapse ? undefined : setIsOpen(!isOpen)),
-      [disableCollapse, isOpen],
-    )
+    const toggleOpen = useCallback(() => {
+      if (disableCollapse) return
+      setIsOpen(prev => !prev)
+    }, [disableCollapse])
src/components/WalletBalanceChange/WalletBalanceChange.tsx (3)

55-60: Delegate percent formatting to Amount.Percent

Avoid local string formatting and keep visuals consistent with the rest of the app.

Apply:

-    const formattedPercentChange = useMemo(() => {
-      return `${percentChange.toFixed(1)}%`
-    }, [percentChange])
+    // Use <Amount.Percent /> in render; no local string formatting needed

55-56: Neutral color for exactly 0%

Green for 0 can be misleading. Consider neutral on zero.

Apply:

-    const color = percentChange >= 0 ? positiveColor : negativeColor
+    const color = percentChange > 0 ? positiveColor : percentChange < 0 ? negativeColor : 'text.subtle'

61-67: Error boundary coverage

Per project guidelines, ensure this component is rendered within an error boundary (e.g., where used in PopoverWallet/Dashboard). If not already covered, wrap at the parent level with a user-friendly fallback and error toast.

src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx (1)

238-240: Placement is correct, but confirm 0% policy

If we decide to hide 0% deltas in WalletBalanceChange (see component review), mobile header will follow suit. Please confirm the intended UX.

src/components/Layout/Header/NavBar/PopoverWallet.tsx (2)

102-111: Avoid passing an empty translation key to WalletBalanceChange (label='').

Passing an empty string can trigger i18n warnings and makes intent unclear. Prefer an explicit API to hide the label.

Apply this diff here:

-        <WalletBalanceChange
-          timeframe={HistoryTimeframe.DAY}
-          balanceFontSize='4xl'
-          label=''
-          showErroredAccounts={false}
-          alignItems='center'
-          justifyContent='center'
-        />
+        <WalletBalanceChange
+          timeframe={HistoryTimeframe.DAY}
+          balanceFontSize='4xl'
+          showLabel={false}
+          showErroredAccounts={false}
+          alignItems='center'
+          justifyContent='center'
+        />

And extend WalletBalanceChange to support showLabel:

 export const WalletBalanceChange = memo(
   ({
     timeframe,
-    label = 'defi.walletBalance',
+    label = 'defi.walletBalance',
+    showLabel = true,
     balanceFontSize = '4xl',
     changeFontSize = 'md',
     showErroredAccounts = true,
     ...flexProps
   }: WalletBalanceChangeProps) => {
@@
-        <Heading as='div' color='text.subtle'>
-          <Skeleton isLoaded={isLoaded}>
-            <Text translation={label} />
-          </Skeleton>
-        </Heading>
+        {showLabel && (
+          <Heading as='div' color='text.subtle'>
+            <Skeleton isLoaded={isLoaded}>
+              <Text translation={label} />
+            </Skeleton>
+          </Heading>
+        )}

I can wire up the prop type update if helpful.


128-159: Wrap tab panels in an ErrorBoundary to prevent popover-wide crashes.

These panels render complex async/selector-driven trees (DeFiEarn, TransactionActivity). Per guidelines, wrap in an error boundary with a user-friendly fallback.

Apply this diff:

+import { ErrorBoundary } from '@/components/ErrorBoundary/ErrorBoundary'
+import { ErrorFallback } from '@/components/ErrorBoundary/ErrorFallback'
@@
-          <TabPanels flex='1' overflow='auto' maxHeight={'35vh'} className='scroll-container'>
-            <TabPanel p={0} pt={2}>
-              <AccountTable forceCompactView onRowClick={onClose} />
-            </TabPanel>
-            <TabPanel p={0} pt={2}>
-              <WatchlistTable forceCompactView onRowClick={onClose} hideExploreMore />
-            </TabPanel>
-            <TabPanel p={0} pt={2}>
-              <DeFiEarn forceCompactView />
-            </TabPanel>
-            <TabPanel p={0} pt={2}>
-              <TransactionActivity forceCompactView />
-            </TabPanel>
-          </TabPanels>
+          <ErrorBoundary FallbackComponent={ErrorFallback}>
+            <TabPanels flex='1' overflow='auto' maxHeight={'35vh'} className='scroll-container'>
+              <TabPanel p={0} pt={2}>
+                <AccountTable forceCompactView onRowClick={onClose} />
+              </TabPanel>
+              <TabPanel p={0} pt={2}>
+                <WatchlistTable forceCompactView onRowClick={onClose} hideExploreMore />
+              </TabPanel>
+              <TabPanel p={0} pt={2}>
+                <DeFiEarn forceCompactView />
+              </TabPanel>
+              <TabPanel p={0} pt={2}>
+                <TransactionActivity forceCompactView />
+              </TabPanel>
+            </TabPanels>
+          </ErrorBoundary>

If the project uses a different boundary component, swap the import accordingly.

src/components/EarnDashboard/components/PositionDetails/PositionDetails.tsx (1)

25-26: Defensive: guard against missing staking ids.

At runtime, opportunities.staking could be absent/empty; passing undefined may break child prop types. Cheap guard improves resilience.

Apply this diff:

-      <StakingPositionsByProvider ids={opportunities.staking} forceCompactView={forceCompactView} />
+      <StakingPositionsByProvider
+        ids={opportunities.staking ?? []}
+        forceCompactView={forceCompactView}
+      />
src/components/StakingVaults/DeFiEarn.tsx (1)

75-79: Forward positionTableProps to PositionTable.

Consumers can customize the table (e.g., initialState). It’s currently unused.

Apply this diff:

-        <PositionTable
-          chainId={selectedChainId}
-          searchQuery={searchQuery}
-          forceCompactView={forceCompactView}
-        />
+        <PositionTable
+          {...positionTableProps}
+          chainId={selectedChainId}
+          searchQuery={searchQuery}
+          forceCompactView={forceCompactView}
+        />
src/components/StakingVaults/PositionTable.tsx (2)

101-109: Avoid O(n) lookup and any here; use row.index

Use row.index rather than flatRows.indexOf(row), and drop the any.

-Cell: ({ row, flatRows }: { row: RowProps; flatRows: any }) => (
-  <RawText>{flatRows.indexOf(row) + 1}</RawText>
-),
+Cell: ({ row }: { row: RowProps }) => <RawText>{row.index + 1}</RawText>,

113-117: O(n) per-cell asset lookup

assets.find(...) runs per row render. Precompute a map and read in O(1).

-const asset = assets.find(a => a.assetId === row.original.assetId)
-return <AssetCell assetId={row.original.assetId} subText={asset?.symbol} />
+const asset = assetById.get(row.original.assetId)
+return <AssetCell assetId={row.original.assetId} subText={asset?.symbol} />

Add once above (outside this hunk):

const assetById = useMemo(() => new Map(assets.map(a => [a.assetId, a])), [assets])
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3940a86 and 1cbbb42.

📒 Files selected for processing (15)
  • src/assets/translations/en/main.json (3 hunks)
  • src/components/EarnDashboard/components/PositionDetails/PositionDetails.tsx (1 hunks)
  • src/components/EarnDashboard/components/PositionDetails/StakingPositionsByProvider.tsx (6 hunks)
  • src/components/Layout/Header/NavBar/PopoverWallet.tsx (4 hunks)
  • src/components/StakingVaults/DeFiEarn.tsx (2 hunks)
  • src/components/StakingVaults/PositionTable.tsx (8 hunks)
  • src/components/Tabs/Tabs.theme.ts (1 hunks)
  • src/components/TransactionHistory/TransactionActivity.tsx (1 hunks)
  • src/components/TransactionHistoryRows/TransactionRow.tsx (1 hunks)
  • src/components/WalletBalanceChange/WalletBalanceChange.tsx (1 hunks)
  • src/pages/Dashboard/Dashboard.tsx (2 hunks)
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeader.tsx (1 hunks)
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx (5 hunks)
  • src/pages/History/History.tsx (1 hunks)
  • src/pages/RFOX/components/History/History.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.{ts,tsx}: ALWAYS use Result<T, E> pattern for error handling in swappers and APIs
ALWAYS use Ok() and Err() from @sniptt/monads for monadic error handling
ALWAYS use custom error classes from @shapeshiftoss/errors
ALWAYS provide meaningful error codes for internationalization
ALWAYS include relevant details in error objects
ALWAYS wrap async operations in try-catch blocks
ALWAYS use AsyncResultOf utility for converting promises to Results
ALWAYS provide fallback error handling
ALWAYS use timeoutMonadic for API calls
ALWAYS provide appropriate timeout values for API calls
ALWAYS handle timeout errors gracefully
ALWAYS validate inputs before processing
ALWAYS provide clear validation error messages
ALWAYS use early returns for validation failures
ALWAYS log errors for debugging
ALWAYS use structured logging for errors
ALWAYS include relevant context in error logs
Throwing errors instead of using monadic patterns is an anti-pattern
Missing try-catch blocks for async operations is an anti-pattern
Generic error messages without context are an anti-pattern
Not handling specific error types is an anti-pattern
Missing timeout handling is an anti-pattern
No input validation is an anti-pattern
Poor error logging is an anti-pattern
Using any for error types is an anti-pattern
Missing error codes for internationalization is an anti-pattern
No fallback error handling is an anti-pattern
Console.error without structured logging is an anti-pattern

**/*.{ts,tsx}: ALWAYS use camelCase for variables, functions, and methods
ALWAYS use descriptive names that explain the purpose for variables and functions
ALWAYS use verb prefixes for functions that perform actions
ALWAYS use PascalCase for types, interfaces, and enums
ALWAYS use descriptive names that indicate the structure for types, interfaces, and enums
ALWAYS use suffixes like Props, State, Config, Type when appropriate for types and interfaces
ALWAYS use UPPER_SNAKE_CASE for constants and configuration values
ALWAYS use d...

Files:

  • src/components/TransactionHistoryRows/TransactionRow.tsx
  • src/pages/RFOX/components/History/History.tsx
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeader.tsx
  • src/pages/History/History.tsx
  • src/components/TransactionHistory/TransactionActivity.tsx
  • src/pages/Dashboard/Dashboard.tsx
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx
  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
  • src/components/Tabs/Tabs.theme.ts
  • src/components/EarnDashboard/components/PositionDetails/StakingPositionsByProvider.tsx
  • src/components/StakingVaults/PositionTable.tsx
  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
  • src/components/EarnDashboard/components/PositionDetails/PositionDetails.tsx
  • src/components/StakingVaults/DeFiEarn.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.tsx: ALWAYS wrap components in error boundaries
ALWAYS provide user-friendly fallback components in error boundaries
ALWAYS log errors for debugging in error boundaries
ALWAYS use useErrorToast hook for displaying errors
ALWAYS provide translated error messages in error toasts
ALWAYS handle different error types appropriately in error toasts
Missing error boundaries in React components is an anti-pattern

**/*.tsx: ALWAYS use PascalCase for React component names
ALWAYS use descriptive names that indicate the component's purpose
ALWAYS match the component name to the file name
Flag components without PascalCase
Flag default exports for components

Files:

  • src/components/TransactionHistoryRows/TransactionRow.tsx
  • src/pages/RFOX/components/History/History.tsx
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeader.tsx
  • src/pages/History/History.tsx
  • src/components/TransactionHistory/TransactionActivity.tsx
  • src/pages/Dashboard/Dashboard.tsx
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx
  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
  • src/components/EarnDashboard/components/PositionDetails/StakingPositionsByProvider.tsx
  • src/components/StakingVaults/PositionTable.tsx
  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
  • src/components/EarnDashboard/components/PositionDetails/PositionDetails.tsx
  • src/components/StakingVaults/DeFiEarn.tsx
**/*

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*: ALWAYS use appropriate file extensions
Flag files without kebab-case

Files:

  • src/components/TransactionHistoryRows/TransactionRow.tsx
  • src/pages/RFOX/components/History/History.tsx
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeader.tsx
  • src/pages/History/History.tsx
  • src/components/TransactionHistory/TransactionActivity.tsx
  • src/pages/Dashboard/Dashboard.tsx
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx
  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
  • src/components/Tabs/Tabs.theme.ts
  • src/components/EarnDashboard/components/PositionDetails/StakingPositionsByProvider.tsx
  • src/components/StakingVaults/PositionTable.tsx
  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
  • src/components/EarnDashboard/components/PositionDetails/PositionDetails.tsx
  • src/assets/translations/en/main.json
  • src/components/StakingVaults/DeFiEarn.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

**/*.{tsx,jsx}: ALWAYS use useMemo for expensive computations, object/array creations, and filtered data
ALWAYS use useMemo for derived values and computed properties
ALWAYS use useMemo for conditional values and simple transformations
ALWAYS use useCallback for event handlers and functions passed as props
ALWAYS use useCallback for any function that could be passed as a prop or dependency
ALWAYS include all dependencies in useEffect, useMemo, useCallback dependency arrays
NEVER use // eslint-disable-next-line react-hooks/exhaustive-deps unless absolutely necessary
ALWAYS explain why dependencies are excluded if using eslint disable
ALWAYS use named exports for components
NEVER use default exports for components
KEEP component files under 200 lines when possible
BREAK DOWN large components into smaller, reusable pieces
EXTRACT complex logic into custom hooks
USE local state for component-level state
LIFT state up when needed across multiple components
USE Context for avoiding prop drilling
ALWAYS wrap components in error boundaries for production
ALWAYS handle async errors properly
ALWAYS provide user-friendly error messages
ALWAYS use virtualization for lists with 100+ items
ALWAYS implement proper key props for list items
ALWAYS lazy load heavy components
ALWAYS use React.lazy for code splitting
Components receiving props are wrapped with memo

Files:

  • src/components/TransactionHistoryRows/TransactionRow.tsx
  • src/pages/RFOX/components/History/History.tsx
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeader.tsx
  • src/pages/History/History.tsx
  • src/components/TransactionHistory/TransactionActivity.tsx
  • src/pages/Dashboard/Dashboard.tsx
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx
  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
  • src/components/EarnDashboard/components/PositionDetails/StakingPositionsByProvider.tsx
  • src/components/StakingVaults/PositionTable.tsx
  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
  • src/components/EarnDashboard/components/PositionDetails/PositionDetails.tsx
  • src/components/StakingVaults/DeFiEarn.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

USE Redux only for global state shared across multiple places

Files:

  • src/components/TransactionHistoryRows/TransactionRow.tsx
  • src/pages/RFOX/components/History/History.tsx
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeader.tsx
  • src/pages/History/History.tsx
  • src/components/TransactionHistory/TransactionActivity.tsx
  • src/pages/Dashboard/Dashboard.tsx
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx
  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
  • src/components/Tabs/Tabs.theme.ts
  • src/components/EarnDashboard/components/PositionDetails/StakingPositionsByProvider.tsx
  • src/components/StakingVaults/PositionTable.tsx
  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
  • src/components/EarnDashboard/components/PositionDetails/PositionDetails.tsx
  • src/components/StakingVaults/DeFiEarn.tsx
🧠 Learnings (8)
📓 Common learnings
Learnt from: NeOMakinG
PR: shapeshift/web#10323
File: src/components/ButtonWalletPredicate/ButtonWalletPredicate.tsx:7-7
Timestamp: 2025-08-27T09:47:06.275Z
Learning: In shapeshift/web project, NeOMakinG consistently prefers to defer UI/UX improvements and refactoring work (like the Drawer.Close hack fix in ButtonWalletPredicate.tsx) to follow-up PRs rather than expanding the scope of feature PRs, even when the improvements would enhance robustness.
📚 Learning: 2025-08-22T12:59:01.210Z
Learnt from: NeOMakinG
PR: shapeshift/web#10323
File: src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx:26-29
Timestamp: 2025-08-22T12:59:01.210Z
Learning: In src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx, NeOMakinG declined wrapping the RewardDistributionActionCard component with React.memo, saying it was "too much", suggesting that like other action center components, memoization is not beneficial for this specific use case.

Applied to files:

  • src/components/TransactionHistory/TransactionActivity.tsx
  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
📚 Learning: 2025-09-04T17:26:19.399Z
Learnt from: NeOMakinG
PR: shapeshift/web#10380
File: src/components/PriceChangeTag/PriceChangeTag.tsx:25-36
Timestamp: 2025-09-04T17:26:19.399Z
Learning: In the shapeshift/web project, NeOMakinG prefers to hide 0% price changes in the PriceChangeTag component rather than displaying "0.00%", so the falsy check `if (!changePercent24Hr) return null` is intentional design behavior.

Applied to files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
📚 Learning: 2025-08-08T14:59:40.422Z
Learnt from: NeOMakinG
PR: shapeshift/web#10231
File: src/pages/Explore/ExploreCategory.tsx:231-238
Timestamp: 2025-08-08T14:59:40.422Z
Learning: In src/pages/Explore/ExploreCategory.tsx, for the PageHeader filter trigger, NeOMakinG considers changing a clickable Chakra Icon to IconButton too nitpicky for this PR and prefers to keep the current Icon-based trigger; such minor a11y/UI nitpicks should be deferred to a follow-up if needed.

Applied to files:

  • src/components/EarnDashboard/components/PositionDetails/StakingPositionsByProvider.tsx
  • src/components/StakingVaults/PositionTable.tsx
📚 Learning: 2025-08-08T15:00:49.887Z
Learnt from: NeOMakinG
PR: shapeshift/web#10231
File: src/components/AssetSearch/components/AssetList.tsx:2-2
Timestamp: 2025-08-08T15:00:49.887Z
Learning: Project shapeshift/web: NeOMakinG prefers avoiding minor a11y/UI nitpicks (e.g., adding aria-hidden to decorative icons in empty states like src/components/AssetSearch/components/AssetList.tsx) within feature PRs; defer such suggestions to a follow-up instead of blocking the PR.

Applied to files:

  • src/components/StakingVaults/PositionTable.tsx
📚 Learning: 2025-09-04T12:16:47.728Z
Learnt from: gomesalexandre
PR: shapeshift/web#10430
File: src/components/Layout/Header/NavBar/PopoverWallet.tsx:72-94
Timestamp: 2025-09-04T12:16:47.728Z
Learning: gomesalexandre declined to add error boundaries to the PopoverWallet component in src/components/Layout/Header/NavBar/PopoverWallet.tsx, stating he didn't touch this component and preferring not to expand the scope of the PR with error boundary additions.

Applied to files:

  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
📚 Learning: 2025-08-03T22:10:38.426Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/react-best-practices.mdc:0-0
Timestamp: 2025-08-03T22:10:38.426Z
Learning: Applies to **/*.{tsx,jsx} : EXTRACT complex logic into custom hooks

Applied to files:

  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
📚 Learning: 2025-08-03T22:10:38.426Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/react-best-practices.mdc:0-0
Timestamp: 2025-08-03T22:10:38.426Z
Learning: Applies to **/*.{tsx,jsx} : BREAK DOWN large components into smaller, reusable pieces

Applied to files:

  • src/components/StakingVaults/DeFiEarn.tsx
🧬 Code graph analysis (8)
src/components/TransactionHistory/TransactionActivity.tsx (3)
src/state/store.ts (1)
  • useAppSelector (143-143)
src/state/slices/txHistorySlice/selectors.ts (1)
  • selectTxIdsBasedOnSearchTermAndFilters (235-281)
src/components/TransactionHistory/TransactionHistoryList.tsx (1)
  • TransactionHistoryList (19-68)
src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx (1)
src/components/WalletBalanceChange/WalletBalanceChange.tsx (1)
  • WalletBalanceChange (28-89)
src/components/WalletBalanceChange/WalletBalanceChange.tsx (5)
src/state/store.ts (1)
  • useAppSelector (143-143)
src/state/slices/portfolioSlice/selectors.ts (2)
  • selectPortfolioTotalUserCurrencyBalance (190-199)
  • selectIsPortfolioLoading (332-338)
src/hooks/useBalanceChartData/useBalanceChartData.ts (1)
  • useBalanceChartData (324-439)
src/components/Text/Text.tsx (1)
  • Text (19-83)
src/components/TooltipWithTouch.tsx (1)
  • TooltipWithTouch (7-73)
src/components/EarnDashboard/components/PositionDetails/StakingPositionsByProvider.tsx (3)
src/theme/theme.tsx (1)
  • breakpoints (37-44)
src/components/StakingVaults/PositionTable.tsx (1)
  • RowProps (34-34)
src/components/ReactTable/ReactTable.tsx (1)
  • ReactTable (132-297)
src/components/StakingVaults/PositionTable.tsx (6)
src/state/slices/opportunitiesSlice/types.ts (1)
  • AggregatedOpportunitiesByAssetIdReturn (240-248)
src/state/store.ts (1)
  • useAppSelector (143-143)
src/state/slices/assetsSlice/selectors.ts (1)
  • selectAssetsSortedByMarketCap (57-64)
src/state/slices/opportunitiesSlice/selectors/combined.ts (1)
  • selectIsAnyOpportunitiesApiQueryPending (238-239)
src/theme/theme.tsx (1)
  • breakpoints (37-44)
src/components/EarnDashboard/components/PositionDetails/PositionDetails.tsx (1)
  • PositionDetails (12-28)
src/components/Layout/Header/NavBar/PopoverWallet.tsx (3)
src/components/WalletBalanceChange/WalletBalanceChange.tsx (1)
  • WalletBalanceChange (28-89)
src/components/StakingVaults/DeFiEarn.tsx (1)
  • DeFiEarn (31-83)
src/components/TransactionHistory/TransactionActivity.tsx (1)
  • TransactionActivity (13-37)
src/components/EarnDashboard/components/PositionDetails/PositionDetails.tsx (3)
src/state/slices/opportunitiesSlice/types.ts (1)
  • AggregatedOpportunitiesByAssetIdReturn (240-248)
src/theme/theme.tsx (1)
  • breakpoints (37-44)
src/components/EarnDashboard/components/PositionDetails/StakingPositionsByProvider.tsx (1)
  • StakingPositionsByProvider (89-364)
src/components/StakingVaults/DeFiEarn.tsx (2)
src/components/ChainDropdown/ChainDropdown.tsx (1)
  • ChainDropdown (40-107)
src/components/StakingVaults/PositionTable.tsx (1)
  • PositionTable (47-255)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Install and Cache
🔇 Additional comments (15)
src/pages/RFOX/components/History/History.tsx (1)

67-67: Translation key switch looks good.

navBar.activity aligns with the new i18n keys introduced in this PR.

src/pages/Dashboard/Dashboard.tsx (1)

95-97: LGTM on relying on themed soft-rounded tabs.

Removing custom tab styles in favor of Tabs.theme.ts keeps styling consistent across the app.

src/components/Tabs/Tabs.theme.ts (1)

89-89: Mode-aware selected/hover states look correct.

The dynamic bg/fg for _selected and hover are consistent with the app’s dark/light theming.

Also applies to: 95-99

src/components/TransactionHistory/TransactionActivity.tsx (1)

14-21: Remove unnecessary types default; null is already coerced to []
The selector selectTransactionTypesParamFromFilter uses filter?.types ?? [], so passing types: null is safe and won’t cause .length errors. No change needed.

Likely an incorrect or invalid review comment.

src/assets/translations/en/main.json (2)

548-549: New key for 24-hour change looks good.

common.walletBalanceChange24Hr added and is consistent with the feature.


2278-2279: Added transaction details key looks correct.

transactionHistory.transactionDetails matches UI additions.

src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx (1)

61-72: Mobile daily-change block: solid integration

Using WalletBalanceChange with HistoryTimeframe.DAY, hidden label, and no errored accounts fits the mobile header well.

src/components/Layout/Header/NavBar/PopoverWallet.tsx (2)

14-24: Imports and memoization look consistent with new usage.

New deps (HistoryTimeframe, DeFiEarn, TransactionActivity, WalletBalanceChange) are correctly referenced and memo usage is appropriate.


152-157: Compact DeFi and Activity panels fit the mobile popover scope.

Forwarding forceCompactView through both panels is coherent with the compact mode strategy.

src/components/EarnDashboard/components/PositionDetails/PositionDetails.tsx (2)

12-21: Compact-mode calculation is sound and SSR-safe.

useMediaQuery with { ssr: false } avoids hydration mismatches; combining with forceCompactView is correct.


1-10: Type and breakpoint wiring LGTM.

Local prop type extension and theme breakpoint import align with related table/provider components.

src/components/StakingVaults/DeFiEarn.tsx (2)

20-24: Prop addition LGTM.

forceCompactView is optional and well-scoped to drive header/table compaction.


49-73: Header-only render gating is correct for compact mode.

Hiding ChainDropdown and GlobalFilter in compact is aligned with popover constraints.

src/components/StakingVaults/PositionTable.tsx (2)

216-220: Verify PositionDetails prop shape

You spread {...original}. Ensure PositionDetailsProps accepts extra props; otherwise pass only required props.

Minimal safe alternative:

-<PositionDetails key={original.assetId} {...original} forceCompactView={forceCompactView} />
+<PositionDetails
+  key={original.assetId}
+  opportunities={original.opportunities}
+  forceCompactView={forceCompactView}
/>

252-253: Header toggle in compact mode — LGTM (after isCompactCols fix)

displayHeaders={!isCompactCols} aligns with the compact column behavior.

@premiumjibles
Copy link
Collaborator Author

@NeOMakinG actioned feedback here 831c146

@premiumjibles premiumjibles enabled auto-merge (squash) September 9, 2025 21:29
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
src/components/WalletBalanceChange/WalletBalanceChange.tsx (2)

60-68: Use Number.isFinite and drop BigNumber import

Avoid importing bn just to check finiteness; use the built-in.

-import { bn } from '@/lib/bignumber/bignumber'
@@
-        {bn(percentChange).isFinite() && (
+        {Number.isFinite(percentChange) && (

Also applies to: 10-10


19-22: Tooltip copy should not be hard-coded to 24Hr

Either lock timeframe to DAY or make the label configurable. Suggest making it configurable via prop to keep the component generic.

 type WalletBalanceChangeProps = {
   timeframe: HistoryTimeframe
   showErroredAccounts?: boolean
+  tooltipLabel?: string
 } & FlexProps
@@
-export const WalletBalanceChange = memo(
-  ({ timeframe, showErroredAccounts = true, ...flexProps }: WalletBalanceChangeProps) => {
+export const WalletBalanceChange = memo(
+  ({ timeframe, showErroredAccounts = true, tooltipLabel, ...flexProps }: WalletBalanceChangeProps) => {
@@
-            <TooltipWithTouch label={translate('defi.walletBalanceChange24Hr')}>
+            <TooltipWithTouch label={translate(tooltipLabel ?? 'defi.walletBalanceChange24Hr')}>

Follow-up: callers can pass a timeframe-appropriate i18n key; happy to wire a switch if preferred.

Also applies to: 25-25, 62-62

🧹 Nitpick comments (6)
src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx (4)

61-67: Remove snarky comment and keep the eslint-disable rationale concise

The "react-memo you're drunk" comment is unprofessional. Keep the disable but explain why succinctly.

-  // react-memo you're drunk, this is outside of component scope
-  // eslint-disable-next-line react-memo/require-usememo
+  // eslint-disable-next-line react-memo/require-usememo -- false positive: static JSX at module scope

69-75: Same here: clean up the comment tone

Mirror the concise rationale for this block too.

-  // react-memo you're drunk, this is outside of component scope
-  // eslint-disable-next-line react-memo/require-usememo
+  // eslint-disable-next-line react-memo/require-usememo -- false positive: static JSX at module scope

221-236: Optional: prefer small memoized components over static element constants

Static element objects at module scope can make future prop/theming changes harder. Consider memoized leaf components instead (MobileNetWorth/DesktopNetWorth) and render them as JSX.

-const mobileNetWorth = (
+const MobileNetWorth = memo(() => (
   <Flex alignItems='center' flexDir={containerInnerFlexDir} gap={4} gridColumn={profileGridColumn}>
     <WalletBalanceChange timeframe={HistoryTimeframe.DAY} showErroredAccounts={false} />
   </Flex>
-)
+))
 
-const desktopNetWorth = (
+const DesktopNetWorth = memo(() => (
   <Flex alignItems='center' flexDir={containerInnerFlexDir} gap={4} gridColumn={profileGridColumn}>
     <WalletBalance balanceFontSize={balanceFontSize} />
   </Flex>
-)
+))
@@
-            {mobileNetWorth}
+            <MobileNetWorth />
@@
-          {desktopNetWorth}
+          <DesktopNetWorth />

Note: Fine to defer to a follow-up PR per team preference. [learned preference acknowledged]

Also applies to: 252-262


105-106: Consider wrapping with an ErrorBoundary at the page/drawer level

Per guidelines, components should be wrapped in error boundaries with a user-friendly fallback and logging. If already handled higher up, ignore.

src/components/WalletBalanceChange/WalletBalanceChange.tsx (2)

46-48: Avoid showing “-0.0%” due to floating-point rounding

Normalize negative zero before formatting.

-    const formattedPercentChange = useMemo(() => {
-      return `${percentChange.toFixed(1)}%`
-    }, [percentChange])
+    const formattedPercentChange = useMemo(() => {
+      const normalized = Object.is(percentChange, -0) ? 0 : percentChange
+      return `${normalized.toFixed(1)}%`
+    }, [percentChange])

24-31: Optional: add an ErrorBoundary at usage sites

This component reads from multiple selectors/hooks; wrap it with an error boundary (and useErrorToast on failure) where it’s used (e.g., Dashboard header, wallet popover) to align with guidelines.

Also applies to: 50-69

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1cbbb42 and 831c146.

📒 Files selected for processing (4)
  • src/assets/translations/en/main.json (2 hunks)
  • src/components/Layout/Header/NavBar/PopoverWallet.tsx (4 hunks)
  • src/components/WalletBalanceChange/WalletBalanceChange.tsx (1 hunks)
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
  • src/assets/translations/en/main.json
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.{ts,tsx}: ALWAYS use Result<T, E> pattern for error handling in swappers and APIs
ALWAYS use Ok() and Err() from @sniptt/monads for monadic error handling
ALWAYS use custom error classes from @shapeshiftoss/errors
ALWAYS provide meaningful error codes for internationalization
ALWAYS include relevant details in error objects
ALWAYS wrap async operations in try-catch blocks
ALWAYS use AsyncResultOf utility for converting promises to Results
ALWAYS provide fallback error handling
ALWAYS use timeoutMonadic for API calls
ALWAYS provide appropriate timeout values for API calls
ALWAYS handle timeout errors gracefully
ALWAYS validate inputs before processing
ALWAYS provide clear validation error messages
ALWAYS use early returns for validation failures
ALWAYS log errors for debugging
ALWAYS use structured logging for errors
ALWAYS include relevant context in error logs
Throwing errors instead of using monadic patterns is an anti-pattern
Missing try-catch blocks for async operations is an anti-pattern
Generic error messages without context are an anti-pattern
Not handling specific error types is an anti-pattern
Missing timeout handling is an anti-pattern
No input validation is an anti-pattern
Poor error logging is an anti-pattern
Using any for error types is an anti-pattern
Missing error codes for internationalization is an anti-pattern
No fallback error handling is an anti-pattern
Console.error without structured logging is an anti-pattern

**/*.{ts,tsx}: ALWAYS use camelCase for variables, functions, and methods
ALWAYS use descriptive names that explain the purpose for variables and functions
ALWAYS use verb prefixes for functions that perform actions
ALWAYS use PascalCase for types, interfaces, and enums
ALWAYS use descriptive names that indicate the structure for types, interfaces, and enums
ALWAYS use suffixes like Props, State, Config, Type when appropriate for types and interfaces
ALWAYS use UPPER_SNAKE_CASE for constants and configuration values
ALWAYS use d...

Files:

  • src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx
  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.tsx: ALWAYS wrap components in error boundaries
ALWAYS provide user-friendly fallback components in error boundaries
ALWAYS log errors for debugging in error boundaries
ALWAYS use useErrorToast hook for displaying errors
ALWAYS provide translated error messages in error toasts
ALWAYS handle different error types appropriately in error toasts
Missing error boundaries in React components is an anti-pattern

**/*.tsx: ALWAYS use PascalCase for React component names
ALWAYS use descriptive names that indicate the component's purpose
ALWAYS match the component name to the file name
Flag components without PascalCase
Flag default exports for components

Files:

  • src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx
  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
**/*

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*: ALWAYS use appropriate file extensions
Flag files without kebab-case

Files:

  • src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx
  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

**/*.{tsx,jsx}: ALWAYS use useMemo for expensive computations, object/array creations, and filtered data
ALWAYS use useMemo for derived values and computed properties
ALWAYS use useMemo for conditional values and simple transformations
ALWAYS use useCallback for event handlers and functions passed as props
ALWAYS use useCallback for any function that could be passed as a prop or dependency
ALWAYS include all dependencies in useEffect, useMemo, useCallback dependency arrays
NEVER use // eslint-disable-next-line react-hooks/exhaustive-deps unless absolutely necessary
ALWAYS explain why dependencies are excluded if using eslint disable
ALWAYS use named exports for components
NEVER use default exports for components
KEEP component files under 200 lines when possible
BREAK DOWN large components into smaller, reusable pieces
EXTRACT complex logic into custom hooks
USE local state for component-level state
LIFT state up when needed across multiple components
USE Context for avoiding prop drilling
ALWAYS wrap components in error boundaries for production
ALWAYS handle async errors properly
ALWAYS provide user-friendly error messages
ALWAYS use virtualization for lists with 100+ items
ALWAYS implement proper key props for list items
ALWAYS lazy load heavy components
ALWAYS use React.lazy for code splitting
Components receiving props are wrapped with memo

Files:

  • src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx
  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

USE Redux only for global state shared across multiple places

Files:

  • src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx
  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
🧠 Learnings (3)
📓 Common learnings
Learnt from: NeOMakinG
PR: shapeshift/web#10323
File: src/components/ButtonWalletPredicate/ButtonWalletPredicate.tsx:7-7
Timestamp: 2025-08-27T09:47:06.275Z
Learning: In shapeshift/web project, NeOMakinG consistently prefers to defer UI/UX improvements and refactoring work (like the Drawer.Close hack fix in ButtonWalletPredicate.tsx) to follow-up PRs rather than expanding the scope of feature PRs, even when the improvements would enhance robustness.
📚 Learning: 2025-08-22T12:59:01.210Z
Learnt from: NeOMakinG
PR: shapeshift/web#10323
File: src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx:26-29
Timestamp: 2025-08-22T12:59:01.210Z
Learning: In src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx, NeOMakinG declined wrapping the RewardDistributionActionCard component with React.memo, saying it was "too much", suggesting that like other action center components, memoization is not beneficial for this specific use case.

Applied to files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
📚 Learning: 2025-09-04T17:26:19.447Z
Learnt from: NeOMakinG
PR: shapeshift/web#10380
File: src/components/PriceChangeTag/PriceChangeTag.tsx:25-36
Timestamp: 2025-09-04T17:26:19.447Z
Learning: In the shapeshift/web project, NeOMakinG prefers to hide 0% price changes in the PriceChangeTag component rather than displaying "0.00%", so the falsy check `if (!changePercent24Hr) return null` is intentional design behavior.

Applied to files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
🧬 Code graph analysis (2)
src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx (1)
src/components/WalletBalanceChange/WalletBalanceChange.tsx (1)
  • WalletBalanceChange (24-72)
src/components/WalletBalanceChange/WalletBalanceChange.tsx (3)
src/state/store.ts (1)
  • useAppSelector (143-143)
src/state/slices/portfolioSlice/selectors.ts (2)
  • selectPortfolioTotalUserCurrencyBalance (190-199)
  • selectIsPortfolioLoading (332-338)
src/hooks/useBalanceChartData/useBalanceChartData.ts (1)
  • useBalanceChartData (324-439)

@premiumjibles premiumjibles merged commit 52d5942 into develop Sep 9, 2025
3 of 4 checks passed
@premiumjibles premiumjibles deleted the 10285_mobile_wallet_p2 branch September 9, 2025 21:36
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/components/StakingVaults/PositionTable.tsx (1)

47-51: Defaulting forceCompactView fixes the undefined boolean pitfall

Thanks for adding forceCompactView = false; this prevents undefined leaking into isCompactCols.

🧹 Nitpick comments (2)
src/components/WalletBalanceChange/WalletBalanceChange.tsx (1)

59-67: Guard with Number.isFinite and compute display-only values lazily

Minor polish: avoid constructing color/formatting when the change isn’t renderable. Also prefer Number.isFinite over bn() for a plain number check.

-        {bn(percentChange).isFinite() && (
-          <Skeleton mt={2} isLoaded={isChangeLoaded}>
-            <TooltipWithTouch label={translate('defi.walletBalanceChange24Hr')}>
-              <Flex gap={1} fontSize='md' color={color} fontWeight='medium'>
-                <Amount.Fiat value={fiatChange} /> ({formattedPercentChange})
-              </Flex>
-            </TooltipWithTouch>
-          </Skeleton>
-        )}
+        {Number.isFinite(percentChange) && (
+          <Skeleton mt={2} isLoaded={isChangeLoaded}>
+            <TooltipWithTouch label={translate('defi.walletBalanceChange24Hr')}>
+              {(() => {
+                const color = percentChange >= 0 ? positiveColor : negativeColor
+                const formattedPercentChange = `${percentChange.toFixed(1)}%`
+                return (
+                  <Flex gap={1} fontSize='md' color={color} fontWeight='medium'>
+                    <Amount.Fiat value={fiatChange} /> ({formattedPercentChange})
+                  </Flex>
+                )
+              })()}
+            </TooltipWithTouch>
+          </Skeleton>
+        )}
src/components/StakingVaults/PositionTable.tsx (1)

113-117: Avoid O(n) asset lookup per row by pre-indexing

assets.find() in a cell runs per-row render. Precompute a Map once for O(1) lookups.

 import { AssetCell } from '@/components/StakingVaults/Cells'
 ...
-  const columns: Column<AggregatedOpportunitiesByAssetIdReturn>[] = useMemo(
+  const assetsById = useMemo(() => {
+    const map = new Map<string, { symbol?: string }>()
+    for (const a of assets) map.set(a.assetId, a)
+    return map
+  }, [assets])
+
+  const columns: Column<AggregatedOpportunitiesByAssetIdReturn>[] = useMemo(
     () => [
 ...
       {
         Header: translate('defi.asset'),
         accessor: 'assetId',
-        Cell: ({ row }: { row: RowProps }) => {
-          const asset = assets.find(a => a.assetId === row.original.assetId)
-          return <AssetCell assetId={row.original.assetId} subText={asset?.symbol} />
-        },
+        Cell: ({ row }: { row: RowProps }) => (
+          <AssetCell
+            assetId={row.original.assetId}
+            subText={assetsById.get(row.original.assetId)?.symbol}
+          />
+        ),
         disableSortBy: true,
       },
 ...
-    [translate, isCompactCols, assets],
+    [translate, isCompactCols, assetsById],
   )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 831c146 and da14e38.

📒 Files selected for processing (5)
  • src/assets/translations/en/main.json (2 hunks)
  • src/components/Layout/Header/NavBar/PopoverWallet.tsx (4 hunks)
  • src/components/StakingVaults/PositionTable.tsx (8 hunks)
  • src/components/WalletBalanceChange/WalletBalanceChange.tsx (1 hunks)
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/assets/translations/en/main.json
  • src/pages/Dashboard/components/DashboardHeader/DashboardHeaderTop.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.{ts,tsx}: ALWAYS use Result<T, E> pattern for error handling in swappers and APIs
ALWAYS use Ok() and Err() from @sniptt/monads for monadic error handling
ALWAYS use custom error classes from @shapeshiftoss/errors
ALWAYS provide meaningful error codes for internationalization
ALWAYS include relevant details in error objects
ALWAYS wrap async operations in try-catch blocks
ALWAYS use AsyncResultOf utility for converting promises to Results
ALWAYS provide fallback error handling
ALWAYS use timeoutMonadic for API calls
ALWAYS provide appropriate timeout values for API calls
ALWAYS handle timeout errors gracefully
ALWAYS validate inputs before processing
ALWAYS provide clear validation error messages
ALWAYS use early returns for validation failures
ALWAYS log errors for debugging
ALWAYS use structured logging for errors
ALWAYS include relevant context in error logs
Throwing errors instead of using monadic patterns is an anti-pattern
Missing try-catch blocks for async operations is an anti-pattern
Generic error messages without context are an anti-pattern
Not handling specific error types is an anti-pattern
Missing timeout handling is an anti-pattern
No input validation is an anti-pattern
Poor error logging is an anti-pattern
Using any for error types is an anti-pattern
Missing error codes for internationalization is an anti-pattern
No fallback error handling is an anti-pattern
Console.error without structured logging is an anti-pattern

**/*.{ts,tsx}: ALWAYS use camelCase for variables, functions, and methods
ALWAYS use descriptive names that explain the purpose for variables and functions
ALWAYS use verb prefixes for functions that perform actions
ALWAYS use PascalCase for types, interfaces, and enums
ALWAYS use descriptive names that indicate the structure for types, interfaces, and enums
ALWAYS use suffixes like Props, State, Config, Type when appropriate for types and interfaces
ALWAYS use UPPER_SNAKE_CASE for constants and configuration values
ALWAYS use d...

Files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
  • src/components/StakingVaults/PositionTable.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.tsx: ALWAYS wrap components in error boundaries
ALWAYS provide user-friendly fallback components in error boundaries
ALWAYS log errors for debugging in error boundaries
ALWAYS use useErrorToast hook for displaying errors
ALWAYS provide translated error messages in error toasts
ALWAYS handle different error types appropriately in error toasts
Missing error boundaries in React components is an anti-pattern

**/*.tsx: ALWAYS use PascalCase for React component names
ALWAYS use descriptive names that indicate the component's purpose
ALWAYS match the component name to the file name
Flag components without PascalCase
Flag default exports for components

Files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
  • src/components/StakingVaults/PositionTable.tsx
**/*

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*: ALWAYS use appropriate file extensions
Flag files without kebab-case

Files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
  • src/components/StakingVaults/PositionTable.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

**/*.{tsx,jsx}: ALWAYS use useMemo for expensive computations, object/array creations, and filtered data
ALWAYS use useMemo for derived values and computed properties
ALWAYS use useMemo for conditional values and simple transformations
ALWAYS use useCallback for event handlers and functions passed as props
ALWAYS use useCallback for any function that could be passed as a prop or dependency
ALWAYS include all dependencies in useEffect, useMemo, useCallback dependency arrays
NEVER use // eslint-disable-next-line react-hooks/exhaustive-deps unless absolutely necessary
ALWAYS explain why dependencies are excluded if using eslint disable
ALWAYS use named exports for components
NEVER use default exports for components
KEEP component files under 200 lines when possible
BREAK DOWN large components into smaller, reusable pieces
EXTRACT complex logic into custom hooks
USE local state for component-level state
LIFT state up when needed across multiple components
USE Context for avoiding prop drilling
ALWAYS wrap components in error boundaries for production
ALWAYS handle async errors properly
ALWAYS provide user-friendly error messages
ALWAYS use virtualization for lists with 100+ items
ALWAYS implement proper key props for list items
ALWAYS lazy load heavy components
ALWAYS use React.lazy for code splitting
Components receiving props are wrapped with memo

Files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
  • src/components/StakingVaults/PositionTable.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

USE Redux only for global state shared across multiple places

Files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
  • src/components/StakingVaults/PositionTable.tsx
🧠 Learnings (12)
📓 Common learnings
Learnt from: NeOMakinG
PR: shapeshift/web#10323
File: src/components/ButtonWalletPredicate/ButtonWalletPredicate.tsx:7-7
Timestamp: 2025-08-27T09:47:06.275Z
Learning: In shapeshift/web project, NeOMakinG consistently prefers to defer UI/UX improvements and refactoring work (like the Drawer.Close hack fix in ButtonWalletPredicate.tsx) to follow-up PRs rather than expanding the scope of feature PRs, even when the improvements would enhance robustness.
Learnt from: NeOMakinG
PR: shapeshift/web#10231
File: src/components/AssetSearch/components/AssetList.tsx:2-2
Timestamp: 2025-08-08T15:00:49.887Z
Learning: Project shapeshift/web: NeOMakinG prefers avoiding minor a11y/UI nitpicks (e.g., adding aria-hidden to decorative icons in empty states like src/components/AssetSearch/components/AssetList.tsx) within feature PRs; defer such suggestions to a follow-up instead of blocking the PR.
📚 Learning: 2025-08-22T12:59:01.210Z
Learnt from: NeOMakinG
PR: shapeshift/web#10323
File: src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx:26-29
Timestamp: 2025-08-22T12:59:01.210Z
Learning: In src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx, NeOMakinG declined wrapping the RewardDistributionActionCard component with React.memo, saying it was "too much", suggesting that like other action center components, memoization is not beneficial for this specific use case.

Applied to files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
📚 Learning: 2025-09-04T17:26:19.447Z
Learnt from: NeOMakinG
PR: shapeshift/web#10380
File: src/components/PriceChangeTag/PriceChangeTag.tsx:25-36
Timestamp: 2025-09-04T17:26:19.447Z
Learning: In the shapeshift/web project, NeOMakinG prefers to hide 0% price changes in the PriceChangeTag component rather than displaying "0.00%", so the falsy check `if (!changePercent24Hr) return null` is intentional design behavior.

Applied to files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
📚 Learning: 2025-09-08T22:00:48.005Z
Learnt from: gomesalexandre
PR: shapeshift/web#10418
File: src/plugins/walletConnectToDapps/components/header/WalletConnectToDappsHeaderButton.tsx:0-0
Timestamp: 2025-09-08T22:00:48.005Z
Learning: gomesalexandre dismissed an aria-label accessibility suggestion with "meh" in PR #10418 for WalletConnectToDappsHeaderButton.tsx, consistent with the team's pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.

Applied to files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
📚 Learning: 2025-08-08T15:00:49.887Z
Learnt from: NeOMakinG
PR: shapeshift/web#10231
File: src/components/AssetSearch/components/AssetList.tsx:2-2
Timestamp: 2025-08-08T15:00:49.887Z
Learning: Project shapeshift/web: NeOMakinG prefers avoiding minor a11y/UI nitpicks (e.g., adding aria-hidden to decorative icons in empty states like src/components/AssetSearch/components/AssetList.tsx) within feature PRs; defer such suggestions to a follow-up instead of blocking the PR.

Applied to files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
  • src/components/StakingVaults/PositionTable.tsx
📚 Learning: 2025-08-25T23:32:13.876Z
Learnt from: premiumjibles
PR: shapeshift/web#10361
File: src/pages/Markets/components/CardWithSparkline.tsx:83-92
Timestamp: 2025-08-25T23:32:13.876Z
Learning: In shapeshift/web PR #10361, premiumjibles considered the nested button accessibility issue (ChartErrorFallback retry Button inside Card rendered as Button in CardWithSparkline.tsx) out of scope for the error boundaries feature PR, consistent with deferring minor a11y improvements to follow-up PRs.

Applied to files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
  • src/components/StakingVaults/PositionTable.tsx
📚 Learning: 2025-08-27T09:47:06.275Z
Learnt from: NeOMakinG
PR: shapeshift/web#10323
File: src/components/ButtonWalletPredicate/ButtonWalletPredicate.tsx:7-7
Timestamp: 2025-08-27T09:47:06.275Z
Learning: In shapeshift/web project, NeOMakinG consistently prefers to defer UI/UX improvements and refactoring work (like the Drawer.Close hack fix in ButtonWalletPredicate.tsx) to follow-up PRs rather than expanding the scope of feature PRs, even when the improvements would enhance robustness.

Applied to files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
📚 Learning: 2025-08-08T14:59:40.422Z
Learnt from: NeOMakinG
PR: shapeshift/web#10231
File: src/pages/Explore/ExploreCategory.tsx:231-238
Timestamp: 2025-08-08T14:59:40.422Z
Learning: In src/pages/Explore/ExploreCategory.tsx, for the PageHeader filter trigger, NeOMakinG considers changing a clickable Chakra Icon to IconButton too nitpicky for this PR and prefers to keep the current Icon-based trigger; such minor a11y/UI nitpicks should be deferred to a follow-up if needed.

Applied to files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
  • src/components/StakingVaults/PositionTable.tsx
📚 Learning: 2025-08-08T15:00:22.321Z
Learnt from: NeOMakinG
PR: shapeshift/web#10231
File: src/components/MultiHopTrade/components/TradeInput/components/HighlightedTokens.tsx:14-14
Timestamp: 2025-08-08T15:00:22.321Z
Learning: In shapeshift/web reviews for NeOMakinG, avoid nitpicks to change deep-relative imports to '@/…' alias paths within feature/non-refactor PRs; defer such style-only changes to a dedicated follow-up refactor unless they fix an issue.

Applied to files:

  • src/components/WalletBalanceChange/WalletBalanceChange.tsx
📚 Learning: 2025-09-04T12:16:47.748Z
Learnt from: gomesalexandre
PR: shapeshift/web#10430
File: src/components/Layout/Header/NavBar/PopoverWallet.tsx:72-94
Timestamp: 2025-09-04T12:16:47.748Z
Learning: gomesalexandre declined to add error boundaries to the PopoverWallet component in src/components/Layout/Header/NavBar/PopoverWallet.tsx, stating he didn't touch this component and preferring not to expand the scope of the PR with error boundary additions.

Applied to files:

  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
📚 Learning: 2025-07-24T21:05:13.642Z
Learnt from: 0xApotheosis
PR: shapeshift/web#10073
File: src/components/Layout/Header/ActionCenter/components/Details/ClaimDetails.tsx:10-11
Timestamp: 2025-07-24T21:05:13.642Z
Learning: In the ShapeShift web repository, translation workflow follows a two-step process: 1) First PR adds only English translations to src/assets/translations/en/main.json, 2) Globalization team handles follow-up PRs to add keys to remaining language files (de, es, fr, id, ja, ko, pt, ru, tr, uk, zh). Don't suggest verifying all locale files simultaneously during initial feature PRs.

Applied to files:

  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
📚 Learning: 2025-08-03T22:10:38.426Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/react-best-practices.mdc:0-0
Timestamp: 2025-08-03T22:10:38.426Z
Learning: Applies to **/*.{tsx,jsx} : EXTRACT complex logic into custom hooks

Applied to files:

  • src/components/Layout/Header/NavBar/PopoverWallet.tsx
🧬 Code graph analysis (3)
src/components/WalletBalanceChange/WalletBalanceChange.tsx (4)
src/state/store.ts (1)
  • useAppSelector (143-143)
src/state/slices/portfolioSlice/selectors.ts (2)
  • selectPortfolioTotalUserCurrencyBalance (190-199)
  • selectIsPortfolioLoading (332-338)
src/hooks/useBalanceChartData/useBalanceChartData.ts (1)
  • useBalanceChartData (324-439)
src/components/TooltipWithTouch.tsx (1)
  • TooltipWithTouch (7-73)
src/components/Layout/Header/NavBar/PopoverWallet.tsx (3)
src/components/WalletBalanceChange/WalletBalanceChange.tsx (1)
  • WalletBalanceChange (23-71)
src/components/StakingVaults/DeFiEarn.tsx (1)
  • DeFiEarn (31-83)
src/components/TransactionHistory/TransactionActivity.tsx (1)
  • TransactionActivity (13-37)
src/components/StakingVaults/PositionTable.tsx (5)
src/state/slices/opportunitiesSlice/types.ts (1)
  • AggregatedOpportunitiesByAssetIdReturn (240-248)
src/state/store.ts (1)
  • useAppSelector (143-143)
src/state/slices/assetsSlice/selectors.ts (1)
  • selectAssetsSortedByMarketCap (57-64)
src/theme/theme.tsx (1)
  • breakpoints (37-44)
src/components/EarnDashboard/components/PositionDetails/PositionDetails.tsx (1)
  • PositionDetails (12-28)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Call / Static
🔇 Additional comments (7)
src/components/WalletBalanceChange/WalletBalanceChange.tsx (1)

61-61: Translation key path is correct
The key defi.walletBalanceChange24Hr exists under defi in src/assets/translations/en/main.json; no changes required.

src/components/Layout/Header/NavBar/PopoverWallet.tsx (4)

15-15: Memo import usage LGTM

Using memo on leaf components here is fine and low-risk.


101-103: Good reuse: centralizing balance UI

Replacing the bespoke net-worth block with WalletBalanceChange (errored accounts hidden) keeps consistency across surfaces.


144-149: Tabs content wiring LGTM

forceCompactView usage for DeFiEarn and TransactionActivity aligns with the popover constraints.


132-136: i18n keys verified Confirmed that dashboard.portfolio.myCrypto, watchlist.title, navBar.defi, and common.activity exist in src/assets/translations/en/main.json.

src/components/StakingVaults/PositionTable.tsx (2)

57-60: Responsive compact logic LGTM

useMediaQuery + forceCompactView cleanly drives header/column visibility.


216-220: Propagating compact view to details LGTM

Passing forceCompactView through keeps subcomponents consistent.

@coderabbitai coderabbitai bot mentioned this pull request Sep 12, 2025
1 task
@coderabbitai coderabbitai bot mentioned this pull request Nov 17, 2025
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement mobile wallet UX inside of the desktop drawer

3 participants