Skip to content

feat: chainflip lending dashboard revamp#12189

Open
gomesalexandre wants to merge 19 commits intodevelopfrom
feat/chainflip-lending-dashboard-revamp
Open

feat: chainflip lending dashboard revamp#12189
gomesalexandre wants to merge 19 commits intodevelopfrom
feat/chainflip-lending-dashboard-revamp

Conversation

@gomesalexandre
Copy link
Contributor

@gomesalexandre gomesalexandre commented Mar 18, 2026

Description

Revamps the Chainflip Lending UI dashboard to be closer to the Figma designs. Takes the good ideas from product's designs and implements them properly, no fox given about the parts that are still half-baked on the Figma side.

What's new:

  • My Dashboard / Markets tabs when wallet connected
  • Init view for first-time users: hero card with "Get Started" CTA, asset constellation art (exact Figma SVGs), Lending Markets 6-column table, "Earn Yield" + "Borrow Against Collateral" info cards
  • Funded dashboard with 4 sections: Free Balance, Supplied, Collateral, Borrowed - each with contextual CTAs
  • Dashboard sidebar: Borrowing Power circular gauge + Next Steps contextual card with green/purple ring art from Figma
  • Loan Health bar: horizontal multi-segment LTV gauge (Safe/Risky/Liquidation zones) - only renders when loans exist
  • Supply modal revamp: asset selector card, Pool APY + Current Position stats, info rows (yearly earnings, pool share, auto-compounding, risk band), confirm screen with bordered card
  • All confirm screens: consistent layout - large centered asset icon + amount, info rows, side-by-side Back/Confirm buttons
  • Visual polish: exact Figma SVGs for all decorative art (orbital rings, glows, sparkles, refresh icons), filled blue action buttons, proper column headers

What's NOT in this PR (product work still WIP on Figma, no fox given):

  • Auto top-up popover/functionality
  • Top-up asset next to collateral
  • Yield 30 days (no data available)
  • Position page charts
  • Pixel-perfect Figma fidelity (designs are sloppy/AI-spewy, we took the good parts)

There'll be follow-ups whenever things evolve on product side.

Issue (if applicable)

Related to the Chainflip Lending dashboard designs shared by 0xFBL

Risk

Low. Behind VITE_FEATURE_CHAINFLIP_LENDING feature flag (dev=true, prod=false). No existing flows affected.

UI-only changes to chainflip lending pages. No transaction logic, no chain interactions, no wallet interactions modified.

Testing

Engineering

  1. Enable feature flag: VITE_FEATURE_CHAINFLIP_LENDING=true
  2. Navigate to /chainflip-lending
  3. No wallet: verify All Markets table with 6 columns, stat cards
  4. Fresh wallet (no CF positions): verify init view with hero, constellation art, info cards
  5. Funded wallet (has free balance): verify My Dashboard with sections, Next Steps sidebar
  6. Modals: test Deposit, Supply (input + confirm), Withdraw, Add Collateral from dashboard CTAs
  7. Markets tab: verify 6-column table matches landing page

Operations

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

Screenshots (if applicable)

QAbot run: 10/10 steps passed (chainflip-lending-revamp-ui fixture)

  • No-wallet landing page ✅
  • Init view (fresh wallet) ✅
  • Funded dashboard ✅
  • Deposit modal ✅
  • Supply modal + confirm ✅
  • Withdraw modal ✅
  • Add Collateral modal ✅
  • Borrowed empty state ✅
  • LoanHealth component ✅
  • Markets tab ✅

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Revamped dashboard with dedicated sections for free balance, supplied assets, collateral, and borrowed amounts
    • New Loan Health card displaying current LTV ratio and liquidation distance
    • Enhanced LTV gauge visualization with safe/risky/liquidation zones and real-time markers
    • Markets table view showcasing lending pools with APY rates and utilization metrics
    • Init view for first-time users with guided get-started experience
    • Navigation shortcuts to dashboard from all confirmation screens
    • Supply input now displays pool APY, current position, and projected yearly earnings
  • Improvements

    • Confirmation screens redesigned with back buttons and "View Dashboard" options
    • Repay input shows fiat equivalent alongside outstanding debt
    • Enhanced modal layouts with improved information density
  • Tests

    • Extended end-to-end test coverage for complete lending workflow

gomes-bot and others added 10 commits March 17, 2026 23:57
- Replace MyBalances with new Dashboard component with tabs (My Dashboard / Markets)
- Add per-section cards: Free Balance, Supplied, Collateral, Borrowed with contextual CTAs
- Add DashboardSidebar with Borrowing Power gauge and Next Steps card with decorative art
- Add InitView for first-time users with Get Started hero, Lending Markets table, info cards
- Add LoanHealth card with horizontal multi-segment LTV bar (Safe/Risky/Liquidation zones)
- Revamp all confirm screens (Deposit, Supply, Withdraw, Borrow, Repay, Collateral, Egress)
  to use centered asset icon + amount, info rows, side-by-side Back/Confirm buttons
- Add Pool APY and Current Position stats to Supply input screen
- Add Borrow APR column to Markets table, reorder columns to match Figma
- Add Lending Markets section title with description
- Fix double button issue in empty state sections
- Use outline button style with + prefix for CTAs per Figma
- Add Asset/Balance column headers to Free Balance section
- Update header to show user-specific summary cards when wallet connected
- Add ~50 new translation keys

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rewrite AssetConstellation with larger icons (52-88px), organic positions,
  no network badges (showNetworkIcon=false), subtle orbital arcs
- Rewrite InfoCard with concentric ring art on right side, proper accent
  colors, radial lines for borrow card
- Add Borrow APR column to Markets table (6 columns matching Figma)
- Reorder Markets columns: Asset, Supply APY, Total Supplied, Borrow APR,
  Total Borrowed, Utilisation
- Add Lending Markets section title with description
- Fix hero card: inline Deposit button + FLIP note, more padding,
  borderRadius 2xl
- Fix Supplied empty state CTA from "+ Supply" to "+ Deposit" per Figma

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Download and embed orbital ring SVGs from Figma MCP for hero constellation
- Download and embed concentric ring SVGs for Earn Yield and Borrow info cards
- Use sparkles-icon.svg and refresh-icon.svg from Figma for info card centers
- Remove showNetworkIcon from hero asset icons (plain icons like Figma)
- Match Figma card styling: rgba bg/border, 2xl border radius, 32px/64px padding
- Inline "Requires 2 FLIP" note next to Deposit button per Figma layout

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Pool APY stat row at top was showing alongside a duplicate APY
info row below the divider. Kept the top stat row (matches Figma)
and removed the bottom duplicate. Estimated yearly earnings still
shows when user enters an amount.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace CSS-based concentric rings with exact Figma SVG assets
for both green (supply) and purple (borrow) variants. Remove
unused Icon, TbRefresh, TbSparkles imports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All Next Steps card buttons now use height=40px, borderRadius=xl,
fontWeight=semibold matching the Figma design. The Add Collateral
button uses subtle whiteAlpha.50 bg for the outline variant.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nfirm, init markets

- SectionHeader primary action buttons now filled blue (matching Figma)
- Supplied section column header "Amount" → "Supplied"
- Collateral section now has Asset/Amount column headers when populated
- Supply confirm wraps amount in bordered card per Figma
- Supply confirm adds Asset info row + parameterized destination label
- InitView MarketsTable now shows 6 columns including Borrow APR
- InitView MarketsTable adds description text matching Markets.tsx

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Updated steps to test no-wallet, init view, funded dashboard, empty sections
- Updated modal steps to open from dashboard sections (not pool page tabs)
- Added Markets tab verification step
- Removed outdated pool page navigation steps

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gomesalexandre gomesalexandre requested a review from a team as a code owner March 18, 2026 00:57
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 18, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR introduces a comprehensive redesign of the Chainflip Lending dashboard and confirmation flow interfaces. Key updates include new dashboard components (Dashboard, InitView, DashboardSections, DashboardSidebar, LoanHealth) to display user balances and positions, restructured confirmation modals with two-button footers and back navigation, an enhanced LTV Gauge with multi-segment visuals, and expanded translation keys for lending-related UI labels. The Markets page now features tab-based navigation for dashboard and markets views, while Supply inputs gain APY and position tracking details.

Changes

Cohort / File(s) Summary
E2E Fixtures
e2e/fixtures/chainflip-lending-revamp-ui.yaml
Expanded test scenarios from minimal steps to comprehensive flow covering no-wallet landing, init view, funded dashboard with multiple sections, action modals, and markets view.
Translation Keys
src/assets/translations/en/main.json
Added 85+ new keys for lending UI: supply/borrow/collateral/deposit/repay/egress/withdraw descriptors, dashboard metrics (freeBalance, supplied, borrowed, borrowPercentages), pool APY, position details, and LTV labels.
Dashboard System
src/pages/ChainflipLending/components/Dashboard.tsx, DashboardSections.tsx, DashboardSidebar.tsx, InitView.tsx, LoanHealth.tsx
Introduced new dashboard module with 5 components: Dashboard (main orchestrator), DashboardSections (4 sections: FreeBalance, Supplied, Collateral, Borrowed), DashboardSidebar (BorrowingPowerCard, NextStepsCard), InitView (markets table and onboarding cards), and LoanHealth (LTV gauge display). Aggregates user balances, positions, and loans with data-driven rendering and modal integration.
Confirmation Modal Refactoring
src/pages/ChainflipLending/Pool/components/Borrow/BorrowConfirm.tsx, CollateralConfirm.tsx, RepayConfirm.tsx, Deposit/DepositConfirm.tsx, Egress/EgressConfirm.tsx, Supply/SupplyConfirm.tsx, Withdraw/WithdrawConfirm.tsx
Restructured all confirmation modals to add: two-button footer layout (close + view dashboard), useNavigate integration for dashboard navigation, back button in footers, and enhanced detail sections with asset icons, amounts, dividers, and summary rows. Consistent pattern applied across 7 modal components.
Header and Markets Navigation
src/pages/ChainflipLending/components/ChainflipLendingHeader.tsx, Markets.tsx
Refactored ChainflipLendingHeader to memo-wrapped component with tabIndex prop; displays user-specific data (free balance, supplied, collateral, borrowed) when accountId present, pools data otherwise. Markets component now uses tab-based layout switching between Dashboard and MarketsTable based on account presence; extracted MarketsTable as reusable component.
Supply Enhancements
src/pages/ChainflipLending/Pool/components/Supply/SupplyConfirm.tsx, SupplyInput.tsx
SupplyConfirm adds pool APY display and navigation to dashboard. SupplyInput replaced TradeAssetSelect picker with AssetIcon card, added pool APY, current position, estimated yearly earnings, pool share, and auto-compounding status displays; integrates chainflip lending pools and positions hooks.
LTV Gauge and Borrow Inputs
src/pages/ChainflipLending/Pool/components/Borrow/LtvGauge.tsx, BorrowInput.tsx, RepayInput.tsx
LtvGauge reworked to multi-segment design with safe/risky/liquidation zones, skull icon at hard liquidation boundary, and dashed marker for projected LTV; legend and percentage labels added. BorrowInput adds risky LTV threshold logic with color-coded projected LTV display. RepayInput wraps outstanding debt display with fiat equivalent.
Removed Component
src/pages/ChainflipLending/components/MyBalances.tsx
Deleted MyBalancesList component (262 lines), functionality consolidated into new DashboardSections.
Git Configuration
.gitignore
Added .gemini/ directory to ignored paths.

Sequence Diagram

sequenceDiagram
    participant User
    participant Dashboard as Dashboard Component
    participant Sections as DashboardSections
    participant Sidebar as DashboardSidebar
    participant Hooks as Data Hooks
    participant Modal as Modal System

    User->>Dashboard: Load /chainflip-lending
    Dashboard->>Hooks: useChainflipAccount, useChainflipFreeBalances,<br/>useChainflipSupplyPositions, useChainflipLoanAccount
    Hooks-->>Dashboard: hasFreeBalance, hasAnyPosition, funded status
    
    alt User has no positions/funding
        Dashboard->>Dashboard: showInitView = true
        Dashboard->>User: Render InitView with markets table
        User->>User: Browse available markets
    else User is funded with positions
        Dashboard->>Dashboard: showInitView = false
        Dashboard->>Sections: Render 4 sections
        Sections->>Hooks: Fetch balances & positions
        Hooks-->>Sections: Asset data with amounts, APYs, rates
        Sections-->>Dashboard: FreeBalance, Supplied, Collateral, Borrowed rows
        
        Dashboard->>Sidebar: Render sidebar components
        Sidebar->>Hooks: useChainflipLoanAccount, useChainflipLtvThresholds
        Hooks-->>Sidebar: LTV, collateral, borrowed values
        Sidebar-->>Dashboard: BorrowingPowerCard, NextStepsCard
        
        Dashboard-->>User: Full dashboard layout
    end
    
    User->>Sections: Click "Deposit" or "Supply" or "Borrow"
    Sections->>Modal: Open chainflipLending modal
    Modal-->>User: Display confirmation flow
    User->>Modal: Confirm action
    Modal->>Modal: Show success with "View Dashboard" button
    User->>Modal: Click "View Dashboard"
    Modal->>Dashboard: Navigate to /chainflip-lending
    Dashboard-->>User: Refresh and display updated data
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 A dashboard springs to life with flair,
With sections dancing here and there,
LTVs now gauged in colors bright,
From green to red, a lending light!
Five fresh components work as one,
The lending UI redesign's done! 🌙

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: chainflip lending dashboard revamp' accurately and clearly summarizes the primary change—a comprehensive revamp of the Chainflip Lending dashboard UI. It is concise, specific, and directly reflects the main objective of the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/chainflip-lending-dashboard-revamp
📝 Coding Plan
  • Generate coding plan for human review comments

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.

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: 11

Caution

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

⚠️ Outside diff range comments (2)
src/pages/ChainflipLending/Pool/components/Withdraw/WithdrawConfirm.tsx (1)

68-79: ⚠️ Potential issue | 🟠 Major

Refresh the lending queries before View Dashboard.

handleDone() invalidates the free-balance/account queries before closing, but the new dashboard CTA skips that step. After a successful withdraw, this can route the user to a dashboard that still shows the pre-withdraw values until the cached queries expire.

Suggested fix
+  const invalidateWithdrawQueries = useCallback(async () => {
+    if (scAccount) {
+      await queryClient.invalidateQueries(reactQueries.chainflipLending.freeBalances(scAccount))
+      await queryClient.invalidateQueries(reactQueries.chainflipLending.accountInfo(scAccount))
+    }
+  }, [scAccount, queryClient])
+
   const handleDone = useCallback(async () => {
-    if (scAccount) {
-      await queryClient.invalidateQueries(reactQueries.chainflipLending.freeBalances(scAccount))
-      await queryClient.invalidateQueries(reactQueries.chainflipLending.accountInfo(scAccount))
-    }
+    await invalidateWithdrawQueries()
     closeModal()
-  }, [scAccount, queryClient, closeModal])
+  }, [invalidateWithdrawQueries, closeModal])
 
-  const handleViewDashboard = useCallback(() => {
+  const handleViewDashboard = useCallback(async () => {
+    await invalidateWithdrawQueries()
     closeModal()
     navigate('/chainflip-lending')
-  }, [closeModal, navigate])
+  }, [invalidateWithdrawQueries, closeModal, navigate])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ChainflipLending/Pool/components/Withdraw/WithdrawConfirm.tsx`
around lines 68 - 79, The View Dashboard CTA bypasses the cache refresh done in
handleDone, so update handleViewDashboard to refresh the same lending queries
before closing/navigating: if scAccount is present, call
queryClient.invalidateQueries(reactQueries.chainflipLending.freeBalances(scAccount))
and
queryClient.invalidateQueries(reactQueries.chainflipLending.accountInfo(scAccount))
(or simply call handleDone() to reuse logic), then closeModal() and
navigate('/chainflip-lending'); ensure you reference scAccount, queryClient,
reactQueries.chainflipLending.freeBalances,
reactQueries.chainflipLending.accountInfo, closeModal, navigate, and handleDone
in the change.
src/pages/ChainflipLending/Pool/components/Supply/SupplyInput.tsx (1)

188-195: ⚠️ Potential issue | 🟡 Minor

Use .toFixed() instead of .toString() to avoid scientific notation in the fiat Max path.

The current code can produce scientific notation for small balances when converting BigNumber to string for setInputValue(). This breaks display in NumericFormat.

Suggested fix
  const handleMaxClick = useCallback(() => {
    if (isFiat && marketData?.price) {
-      const fiatMax = bnOrZero(availableCryptoPrecision).times(marketData.price).toString()
+      const fiatMax = bnOrZero(availableCryptoPrecision)
+        .times(marketData.price)
+        .decimalPlaces(2, 1)
+        .toFixed()
       setInputValue(fiatMax)
    } else {
       setInputValue(availableCryptoPrecision)
    }
  }, [availableCryptoPrecision, isFiat, marketData?.price])

Additionally, replace the hardcoded suffix=' / year' at line 412 with the translation key: suffix={translate('chainflipLending.dashboard.yearlyEarningsSuffix').replace('%{amount} ', '')} or extract the suffix portion differently, since the translation key "yearlyEarningsSuffix": "%{amount} / year" is already defined but not being used.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ChainflipLending/Pool/components/Supply/SupplyInput.tsx` around
lines 188 - 195, The handleMaxClick handler can produce scientific notation
because it calls .toString() on the BigNumber calculation; change the fiat
branch to use .toFixed() (e.g.,
bnOrZero(availableCryptoPrecision).times(marketData.price).toFixed()) before
calling setInputValue to ensure a non-scientific numeric string for
NumericFormat; update the dependency names handleMaxClick,
availableCryptoPrecision, marketData.price, and setInputValue when locating the
code. Also replace the hardcoded suffix=' / year' with the translated suffix by
using the translation key chainflipLending.dashboard.yearlyEarningsSuffix and
extracting/removing the %{amount} placeholder (for example:
translate('chainflipLending.dashboard.yearlyEarningsSuffix').replace('%{amount}
', '')) where the suffix is set.
🧹 Nitpick comments (3)
e2e/fixtures/chainflip-lending-revamp-ui.yaml (1)

44-75: Cover at least one confirm/success path in this fixture.

These steps stop at opening the revamped modals, but the PR also changes the confirm/success footers (Back, Close, View Dashboard). Adding one happy-path flow that reaches success and asserts the dashboard redirect would keep the new navigation path under test.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/fixtures/chainflip-lending-revamp-ui.yaml` around lines 44 - 75, The
fixture stops at opening modals and doesn't exercise the confirm/success path;
add a happy-path scenario that fills a valid amount, clicks the modal's blue
"Next" then "Confirm"/"Supply"/"Add Collateral" action to trigger the success
footer, assert the presence of the success footer buttons ("Back", "Close",
"View Dashboard"), click "View Dashboard" (or verify the dashboard
redirect/navigation), and assert the dashboard is shown (e.g., Free Balance or
Dashboard heading) to cover the new navigation path introduced by the PR.
src/pages/ChainflipLending/components/DashboardSections.tsx (2)

262-269: Duplicate poolsByAssetId computation in SuppliedSection and BorrowedSection.

Both sections compute the same poolsByAssetId lookup map. Consider extracting this to a shared hook or computing it once in a parent component if both sections are rendered together. However, given the PR's UI-focused scope, this can be deferred.

Also applies to: 485-492

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ChainflipLending/components/DashboardSections.tsx` around lines 262
- 269, The poolsByAssetId lookup is computed twice (in SuppliedSection and
BorrowedSection) using the same reduce logic; extract this into a single shared
implementation by creating a hook (e.g., usePoolsByAssetId) or computing it once
in the parent component that renders both sections and passing it down as a
prop; update both SuppliedSection and BorrowedSection to consume the shared
usePoolsByAssetId or the passed-in poolsByAssetId instead of duplicating the
reduce, keeping the existing shape (Partial<Record<AssetId,
ChainflipLendingPoolWithFiat>>) and relying on the same dependency (pools).

207-208: Hardcoded column header strings should use translation keys.

Column headers like "Asset", "Balance", "Amount", and "Supplied" are hardcoded in English. For consistency with the rest of the file (which uses translate() and Text translation= props), these should use translation keys to support i18n.

Example fix for FreeBalanceSection headers (Line 207-208)
               <Flex
                 justifyContent='space-between'
                 px={0}
                 py={1}
                 color='text.subtle'
                 fontSize='xs'
                 fontWeight='bold'
               >
-                <RawText>Asset</RawText>
-                <RawText>Balance</RawText>
+                <Text translation='chainflipLending.dashboard.asset' />
+                <Text translation='chainflipLending.dashboard.balance' />
               </Flex>

Also applies to: 326-326, 329-329, 434-435, 570-570, 573-573

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ChainflipLending/components/DashboardSections.tsx` around lines 207
- 208, Replace hardcoded column header strings in DashboardSections.tsx (e.g.,
the RawText "Asset", "Balance", "Amount", "Supplied" used in FreeBalanceSection
and other sections) with i18n translation calls to match the file's
convention—use the translate('your.translation.key') helper or the <Text
translation="..."> prop depending on surrounding code; update each RawText or
header node (refer to FreeBalanceSection and other header occurrences around the
areas noted: ~lines 207-208, 326, 329, 434-435, 570, 573) to call the
appropriate translation key (create meaningful keys like dashboard.asset,
dashboard.balance, dashboard.amount, dashboard.supplied) so strings are not
hardcoded.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/pages/ChainflipLending/components/Dashboard.tsx`:
- Around line 20-46: The init view is showing prematurely because showInitView
relies on isFunded/isLpRegistered and empty arrays while the hooks are still
loading; update the logic to wait for the hooks to finish before deciding: read
and use the loading/initialized flags returned by useChainflipAccount,
useChainflipFreeBalances, useChainflipSupplyPositions and
useChainflipLoanAccount (or add them if missing) and only compute showInitView
after those loaders are settled; reference isFunded, isLpRegistered,
freeBalances, supplyPositions, collateralWithFiat, loansWithFiat and compute
showInitView to return false while any of those hooks are loading so InitView is
not rendered until all data has resolved.

In `@src/pages/ChainflipLending/components/InitView.tsx`:
- Around line 282-284: The HelperTooltip wrapping the "Lending Markets" Heading
is using the wrong translation key
(translate('chainflipLending.utilisationTooltip')), which is intended for the
utilisation column; update the tooltip to a markets-appropriate key by replacing
utilisationTooltip with a markets-specific key (e.g.
'chainflipLending.lendingMarketsTooltip' or 'chainflipLending.marketsTooltip')
or add a new translation key and use it in the HelperTooltip that wraps the
Heading component so the tooltip context matches the "Lending Markets" heading.

In `@src/pages/ChainflipLending/components/Markets.tsx`:
- Around line 153-159: The HelperTooltip wrapped around the heading uses the
wrong translation key (translate('chainflipLending.utilisationTooltip')); update
the tooltip to either remove the HelperTooltip entirely or point it at a
title-specific key such as 'chainflipLending.lendingMarketsTooltip' (or the
correct existing title tooltip key), by editing the HelperTooltip's label prop
where HelperTooltip is used around the Text component in Markets.tsx so it
reflects the lending markets title instead of the utilisation tooltip.

In `@src/pages/ChainflipLending/Pool/components/Borrow/BorrowConfirm.tsx`:
- Around line 94-97: The view-dashboard handler currently closes the modal and
navigates directly, causing stale loan data; modify handleViewDashboard to run
the same completion path used in handleDone before navigating (either call
handleDone() from handleViewDashboard or extract the invalidation/refresh logic
from handleDone into a shared function and invoke it), then call closeModal()
and navigate('/chainflip-lending') after that refresh completes; reference the
existing functions handleViewDashboard, handleDone, closeModal, and navigate to
locate and reuse the completion/invalidation logic.

In `@src/pages/ChainflipLending/Pool/components/Borrow/LtvGauge.tsx`:
- Around line 95-111: Guard against division-by-zero when computing the inner
Flex width: detect when currentLtv or thumbPosition is 0 (or <= 0) and avoid
calculating (100 / thumbPosition) * 100; instead set the Flex width to a safe
value (e.g. '0%') in that case. Update the code that sets the Flex width
expression (the element using ${(100 / thumbPosition) * 100}% ) to compute a
conditional innerWidth = thumbPosition > 0 ? `${(100 / thumbPosition) * 100}%` :
'0%' so safeWidth, riskyWidth and liquidationWidth render without producing
"Infinity%". Ensure you reference thumbPosition/currentLtv and the Flex
containing safeWidth/riskyWidth/liquidationWidth when making the change.

In `@src/pages/ChainflipLending/Pool/components/Borrow/RepayConfirm.tsx`:
- Around line 322-325: The Badge text is hardcoded as "Full" in RepayConfirm
when isFullRepayment is true; replace that literal with a localized string (use
the component's i18n function, e.g., t('repay.full') or the existing translation
hook used in this component) or accept a translated label via props, so the
Badge (Badge component shown when isFullRepayment) displays a locale-aware label
(or remove the extra text entirely if you prefer only the visual badge).
- Around line 87-90: handleViewDashboard currently closes the modal and
navigates directly, which skips the state invalidation done by handleDone and
can leave the dashboard with stale repay data; update handleViewDashboard to
perform the same completion path as handleDone (i.e., run the state invalidation
/ refresh logic or simply call/await handleDone()) before calling closeModal()
and navigate('/chainflip-lending'), ensuring you preserve the dependency array
([closeModal, navigate]) and that any async operations are awaited so navigation
only occurs after the lending state refresh completes.

In `@src/pages/ChainflipLending/Pool/components/Deposit/DepositConfirm.tsx`:
- Around line 172-175: handleViewDashboard currently just closes the modal and
navigates away, causing stale balances; change it to run the same
completion/cleanup logic used by handleDone before navigating. Specifically,
invoke the same function or shared completion helper that handleDone uses (or
call handleDone directly) to run invalidation, state refresh and any cleanup,
then after that resolution call closeModal() and navigate('/chainflip-lending');
ensure dependencies include whatever helper or handleDone is referenced so the
callback is stable.

In `@src/pages/ChainflipLending/Pool/components/Egress/EgressConfirm.tsx`:
- Around line 85-88: handleViewDashboard currently closes the modal and
navigates away without running the same completion/invalidation steps in
handleDone, which can leave balances stale; update handleViewDashboard to
perform the same completion path as handleDone (either call handleDone()
directly or extract and invoke the shared completion/invalidation function used
by handleDone) before calling closeModal() and navigate('/chainflip-lending'),
ensuring the same invalidate/cache refresh logic runs; reference
handleViewDashboard, handleDone, closeModal, and navigate to locate and reuse
the completion logic.

In `@src/pages/ChainflipLending/Pool/components/Supply/SupplyConfirm.tsx`:
- Around line 86-89: handleViewDashboard currently closes the modal and
navigates directly, skipping the completion/cleanup logic in handleDone and
leaving supply/account caches stale; update handleViewDashboard to perform the
same completion path as handleDone before navigating — either call handleDone()
(or extract the invalidate/cleanup steps from handleDone into a shared helper
like completeSupplyFlow() and invoke that from both handleDone and
handleViewDashboard) and only after that finishes call closeModal() and
navigate('/chainflip-lending').

In `@src/pages/ChainflipLending/Pool/components/Supply/SupplyInput.tsx`:
- Around line 403-413: Replace the hardcoded suffix string in the Amount.Fiat
component with the localized translation key; specifically, in SupplyInput.tsx
where estYearlyEarningsFiat is rendered with Amount.Fiat, call
translate('chainflipLending.supply.yearlyEarningsSuffix') (or store it in a
variable) and pass that result as the suffix prop to Amount.Fiat so the suffix
is localized for all locales.

---

Outside diff comments:
In `@src/pages/ChainflipLending/Pool/components/Supply/SupplyInput.tsx`:
- Around line 188-195: The handleMaxClick handler can produce scientific
notation because it calls .toString() on the BigNumber calculation; change the
fiat branch to use .toFixed() (e.g.,
bnOrZero(availableCryptoPrecision).times(marketData.price).toFixed()) before
calling setInputValue to ensure a non-scientific numeric string for
NumericFormat; update the dependency names handleMaxClick,
availableCryptoPrecision, marketData.price, and setInputValue when locating the
code. Also replace the hardcoded suffix=' / year' with the translated suffix by
using the translation key chainflipLending.dashboard.yearlyEarningsSuffix and
extracting/removing the %{amount} placeholder (for example:
translate('chainflipLending.dashboard.yearlyEarningsSuffix').replace('%{amount}
', '')) where the suffix is set.

In `@src/pages/ChainflipLending/Pool/components/Withdraw/WithdrawConfirm.tsx`:
- Around line 68-79: The View Dashboard CTA bypasses the cache refresh done in
handleDone, so update handleViewDashboard to refresh the same lending queries
before closing/navigating: if scAccount is present, call
queryClient.invalidateQueries(reactQueries.chainflipLending.freeBalances(scAccount))
and
queryClient.invalidateQueries(reactQueries.chainflipLending.accountInfo(scAccount))
(or simply call handleDone() to reuse logic), then closeModal() and
navigate('/chainflip-lending'); ensure you reference scAccount, queryClient,
reactQueries.chainflipLending.freeBalances,
reactQueries.chainflipLending.accountInfo, closeModal, navigate, and handleDone
in the change.

---

Nitpick comments:
In `@e2e/fixtures/chainflip-lending-revamp-ui.yaml`:
- Around line 44-75: The fixture stops at opening modals and doesn't exercise
the confirm/success path; add a happy-path scenario that fills a valid amount,
clicks the modal's blue "Next" then "Confirm"/"Supply"/"Add Collateral" action
to trigger the success footer, assert the presence of the success footer buttons
("Back", "Close", "View Dashboard"), click "View Dashboard" (or verify the
dashboard redirect/navigation), and assert the dashboard is shown (e.g., Free
Balance or Dashboard heading) to cover the new navigation path introduced by the
PR.

In `@src/pages/ChainflipLending/components/DashboardSections.tsx`:
- Around line 262-269: The poolsByAssetId lookup is computed twice (in
SuppliedSection and BorrowedSection) using the same reduce logic; extract this
into a single shared implementation by creating a hook (e.g., usePoolsByAssetId)
or computing it once in the parent component that renders both sections and
passing it down as a prop; update both SuppliedSection and BorrowedSection to
consume the shared usePoolsByAssetId or the passed-in poolsByAssetId instead of
duplicating the reduce, keeping the existing shape (Partial<Record<AssetId,
ChainflipLendingPoolWithFiat>>) and relying on the same dependency (pools).
- Around line 207-208: Replace hardcoded column header strings in
DashboardSections.tsx (e.g., the RawText "Asset", "Balance", "Amount",
"Supplied" used in FreeBalanceSection and other sections) with i18n translation
calls to match the file's convention—use the translate('your.translation.key')
helper or the <Text translation="..."> prop depending on surrounding code;
update each RawText or header node (refer to FreeBalanceSection and other header
occurrences around the areas noted: ~lines 207-208, 326, 329, 434-435, 570, 573)
to call the appropriate translation key (create meaningful keys like
dashboard.asset, dashboard.balance, dashboard.amount, dashboard.supplied) so
strings are not hardcoded.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ec642382-e1cf-4028-815d-17f934aaf768

📥 Commits

Reviewing files that changed from the base of the PR and between 865d7d0 and a449e1e.

⛔ Files ignored due to path filters (18)
  • src/assets/chainflip-lending/borrow-glow.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/borrow-ring-1.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/borrow-ring-2.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/borrow-ring-3.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/borrow-ring-inner.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/earn-glow.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/earn-ring-inner.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/earn-ring-middle.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/earn-ring-outer.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/glow-btc.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/glow-eth.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/orbital-btc.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/orbital-eth.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/orbital-sol.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/orbital-tether.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/orbital-usdc.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/refresh-icon.svg is excluded by !**/*.svg
  • src/assets/chainflip-lending/sparkles-icon.svg is excluded by !**/*.svg
📒 Files selected for processing (19)
  • e2e/fixtures/chainflip-lending-revamp-ui.yaml
  • src/assets/translations/en/main.json
  • src/pages/ChainflipLending/Pool/components/Borrow/BorrowConfirm.tsx
  • src/pages/ChainflipLending/Pool/components/Borrow/CollateralConfirm.tsx
  • src/pages/ChainflipLending/Pool/components/Borrow/LtvGauge.tsx
  • src/pages/ChainflipLending/Pool/components/Borrow/RepayConfirm.tsx
  • src/pages/ChainflipLending/Pool/components/Deposit/DepositConfirm.tsx
  • src/pages/ChainflipLending/Pool/components/Egress/EgressConfirm.tsx
  • src/pages/ChainflipLending/Pool/components/Supply/SupplyConfirm.tsx
  • src/pages/ChainflipLending/Pool/components/Supply/SupplyInput.tsx
  • src/pages/ChainflipLending/Pool/components/Withdraw/WithdrawConfirm.tsx
  • src/pages/ChainflipLending/components/ChainflipLendingHeader.tsx
  • src/pages/ChainflipLending/components/Dashboard.tsx
  • src/pages/ChainflipLending/components/DashboardSections.tsx
  • src/pages/ChainflipLending/components/DashboardSidebar.tsx
  • src/pages/ChainflipLending/components/InitView.tsx
  • src/pages/ChainflipLending/components/LoanHealth.tsx
  • src/pages/ChainflipLending/components/Markets.tsx
  • src/pages/ChainflipLending/components/MyBalances.tsx
💤 Files with no reviewable changes (1)
  • src/pages/ChainflipLending/components/MyBalances.tsx

gomes-bot and others added 2 commits March 18, 2026 02:15
- handleViewDashboard now calls handleDone() for cache invalidation
  before navigating (BorrowConfirm, RepayConfirm, DepositConfirm,
  EgressConfirm, SupplyConfirm)
- Guard LtvGauge filled-track math when currentLtv is 0 (div by zero)
- Remove wrong tooltip on "Lending Markets" heading (was using
  utilisation tooltip, copy-paste slip)
- Localize hardcoded "/ year" suffix in supply yearly earnings
- Localize hardcoded "Full" badge in RepayConfirm

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ral confirms

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gomesalexandre
Copy link
Contributor Author

gomesalexandre commented Mar 18, 2026

QAbot runs:

10/10 steps passed (chainflip-lending-revamp-ui fixture):

  • No-wallet landing page ✅
  • Init view (fresh wallet) ✅
  • Funded dashboard ✅
  • Deposit modal ✅
  • Supply modal + confirm ✅
  • Withdraw modal ✅
  • Add Collateral modal ✅
  • Borrowed empty state ✅
  • LoanHealth component ✅
  • Markets tab ✅

@NeOMakinG
Copy link
Collaborator

🤖 QA Test Report - PR #12189

Tested: 2026-03-18 06:06 UTC

Test Results: ✅ PASSED

Scenario: Chainflip Lending Dashboard Revamp

Step Result Notes
Landing Page (No Wallet) ✅ Pass Stats header visible (Total Supplied, Available Liquidity, Total Borrowed)
All Markets View ✅ Pass 6-column table with USDC, USDT, BTC, ETH, SOL markets
Wallet Connection ✅ Pass Native wallet connects, account address shows
My Dashboard Tab ✅ Pass Hero card with Get Started badge, + Deposit button, asset constellation art
Markets Tab ✅ Pass Switches correctly, shows lending markets table
Info Cards ✅ Pass "Earn Yield" and "Borrow Against Collateral" cards visible at bottom

UI Verification

Header Stats (No Wallet):

  • Total Supplied: $535,395
  • Available Liquidity: $320,513
  • Total Borrowed: $214,881

Markets Table:

  • USDC: 3.17% APY, 75.40% utilization
  • USDT: 1.35% APY, 32.15% utilization
  • BTC, ETH, SOL: 0% APY (no activity)

My Dashboard (Fresh Wallet):

  • Account badge showing truncated address
  • Free Balance/Supplied/Collateral/Borrowed stats
  • "Get Started" hero with deposit CTA
  • Asset constellation artwork visible

Environment

  • Branch: feat/chainflip-lending-dashboard-revamp
  • Feature flag: VITE_FEATURE_CHAINFLIP_LENDING=true
  • Test wallet: Native (ShapeShift built-in)

Automated QA by ShapeShift QA Bot

@gomesalexandre gomesalexandre enabled auto-merge (squash) March 18, 2026 08:21
gomes-bot and others added 2 commits March 18, 2026 10:18
… spacing

- Add ↑ prefix to Withdraw buttons matching Figma
- EmptyState CTA buttons now solid (removed outline variant)
- Next Steps card spacing increased for better breathing room

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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: 1

🧹 Nitpick comments (1)
src/pages/ChainflipLending/components/Markets.tsx (1)

215-229: Consider lazy-mounting the tab panels.

Chakra Tabs mounts every TabPanel by default, so the hidden Dashboard and MarketsTable still run their hooks and queries even when only one tab is visible. If that eager prefetch isn’t intentional, isLazy with lazyBehavior='keepMounted' keeps the first paint lighter without remounting a visited tab.

♻️ Suggested change
-          <Tabs index={tabIndex} onChange={setTabIndex} variant='soft-rounded' colorScheme='blue'>
+          <Tabs
+            index={tabIndex}
+            onChange={setTabIndex}
+            variant='soft-rounded'
+            colorScheme='blue'
+            isLazy
+            lazyBehavior='keepMounted'
+          >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ChainflipLending/components/Markets.tsx` around lines 215 - 229,
The Tabs component currently mounts all TabPanel children (Dashboard and
MarketsTable) eagerly, causing their hooks/queries to run even when hidden;
update the Tabs usage (the Tabs element that controls tabIndex and setTabIndex)
to enable lazy mounting by adding isLazy and set lazyBehavior='keepMounted' so
panels mount only when first shown but stay mounted on revisit, ensuring
Dashboard and MarketsTable are not initialized until their tab is viewed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/pages/ChainflipLending/components/DashboardSidebar.tsx`:
- Around line 206-207: The current early-return hides the Next Steps card
whenever !hasFreeBalance even if some steps (e.g., borrow when hasCollateral &&
!hasLoans) are still actionable; change the condition so the card is only hidden
when the user has completed everything. Replace the line using
hasFreeBalance/hasSupply/hasCollateral/hasLoans with a single check that returns
null only when hasSupply && hasCollateral && hasLoans, so that zero free balance
alone does not suppress actionable steps like Borrow.

---

Nitpick comments:
In `@src/pages/ChainflipLending/components/Markets.tsx`:
- Around line 215-229: The Tabs component currently mounts all TabPanel children
(Dashboard and MarketsTable) eagerly, causing their hooks/queries to run even
when hidden; update the Tabs usage (the Tabs element that controls tabIndex and
setTabIndex) to enable lazy mounting by adding isLazy and set
lazyBehavior='keepMounted' so panels mount only when first shown but stay
mounted on revisit, ensuring Dashboard and MarketsTable are not initialized
until their tab is viewed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1bc230cc-5127-4c49-8747-1e0c2f28af22

📥 Commits

Reviewing files that changed from the base of the PR and between a449e1e and fae220c.

📒 Files selected for processing (14)
  • src/assets/translations/en/main.json
  • src/pages/ChainflipLending/Pool/components/Borrow/BorrowConfirm.tsx
  • src/pages/ChainflipLending/Pool/components/Borrow/CollateralConfirm.tsx
  • src/pages/ChainflipLending/Pool/components/Borrow/LtvGauge.tsx
  • src/pages/ChainflipLending/Pool/components/Borrow/RepayConfirm.tsx
  • src/pages/ChainflipLending/Pool/components/Deposit/DepositConfirm.tsx
  • src/pages/ChainflipLending/Pool/components/Egress/EgressConfirm.tsx
  • src/pages/ChainflipLending/Pool/components/Supply/SupplyConfirm.tsx
  • src/pages/ChainflipLending/Pool/components/Supply/SupplyInput.tsx
  • src/pages/ChainflipLending/Pool/components/Withdraw/WithdrawConfirm.tsx
  • src/pages/ChainflipLending/components/DashboardSections.tsx
  • src/pages/ChainflipLending/components/DashboardSidebar.tsx
  • src/pages/ChainflipLending/components/InitView.tsx
  • src/pages/ChainflipLending/components/Markets.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/pages/ChainflipLending/components/DashboardSections.tsx
  • src/assets/translations/en/main.json
  • src/pages/ChainflipLending/Pool/components/Deposit/DepositConfirm.tsx

…hite totals

- Empty section cards (Supplied, Collateral, Borrowed) now have dashed
  borders when no data, matching Figma empty state styling
- Withdraw button changed from ghost to outline variant with ↑ prefix
- Section total fiat values now white (removed text.subtle) for prominence
- Added Loan Health bar and dashed border steps to revamp-ui fixture

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

♻️ Duplicate comments (1)
src/pages/ChainflipLending/components/DashboardSidebar.tsx (1)

206-207: ⚠️ Potential issue | 🟠 Major

Early return hides Borrow CTA when user has collateral but no free balance

The !hasFreeBalance condition hides the entire card, suppressing the valid path at line 263 where hasCollateral && !hasLoans should show the Borrow button. A user who deposited all their free balance as collateral won't see the Borrow CTA.

💡 Proposed fix
-  // Hide when user has everything or no free balance
-  if (!hasFreeBalance || (hasSupply && hasCollateral && hasLoans)) return null
+  // Hide only when all tracked steps are completed
+  if (hasSupply && hasCollateral && hasLoans) return null
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ChainflipLending/components/DashboardSidebar.tsx` around lines 206
- 207, The early return currently uses "!hasFreeBalance" which hides the card
even when the user has collateral but no loans (the scenario that should show
the Borrow CTA). Update the conditional in the DashboardSidebar component so the
card is only hidden when there is no free balance AND it's not the special case
of "hasCollateral && !hasLoans"; e.g. replace the "!hasFreeBalance" check with a
combined check that allows rendering when (hasCollateral && !hasLoans), keeping
the existing full-hide condition "(hasSupply && hasCollateral && hasLoans)"
intact. Target the conditional that currently reads "if (!hasFreeBalance ||
(hasSupply && hasCollateral && hasLoans)) return null" and change it to allow
the collateral-without-loans path.
🧹 Nitpick comments (1)
src/pages/ChainflipLending/components/DashboardSidebar.tsx (1)

55-58: Consider handling negative available borrowing power

When collateral value drops (e.g., due to price movements), totalBorrowedFiat can exceed maxBorrow, resulting in a negative available value. Displaying a negative amount with green.500 color may mislead users about their actual risk status.

💡 Proposed fix to clamp and adjust color
   const available = useMemo(
-    () => bnOrZero(maxBorrow).minus(totalBorrowedFiat).toFixed(2),
+    () => {
+      const rawAvailable = bnOrZero(maxBorrow).minus(totalBorrowedFiat)
+      return rawAvailable.lt(0) ? '0' : rawAvailable.toFixed(2)
+    },
     [maxBorrow, totalBorrowedFiat],
   )

Alternatively, if showing the negative is intentional, consider changing the color to reflect the risk:

-            <Amount.Fiat value={available} fontSize='lg' fontWeight='bold' color='green.500' />
+            <Amount.Fiat
+              value={available}
+              fontSize='lg'
+              fontWeight='bold'
+              color={bnOrZero(available).lt(0) ? 'red.500' : 'green.500'}
+            />

Also applies to: 95-95

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ChainflipLending/components/DashboardSidebar.tsx` around lines 55 -
58, The computed available borrowing power (variable available inside the
useMemo using maxBorrow and totalBorrowedFiat) can go negative when collateral
falls; update the logic to clamp the displayed available value (e.g.,
Math.max(bnOrZero(maxBorrow).minus(totalBorrowedFiat), 0).toFixed(2) or similar)
and adjust the UI color based on sign (use the existing display path that
consumes available to render green for positive/zero and a warning color like
red/orange when negative), or if you prefer to show the negative value keep the
real negative figure but change the color logic to read the numeric sign from
the un-clamped bnOrZero(...) result to avoid misleading green styling for risky
negative balances.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/pages/ChainflipLending/components/DashboardSidebar.tsx`:
- Around line 206-207: The early return currently uses "!hasFreeBalance" which
hides the card even when the user has collateral but no loans (the scenario that
should show the Borrow CTA). Update the conditional in the DashboardSidebar
component so the card is only hidden when there is no free balance AND it's not
the special case of "hasCollateral && !hasLoans"; e.g. replace the
"!hasFreeBalance" check with a combined check that allows rendering when
(hasCollateral && !hasLoans), keeping the existing full-hide condition
"(hasSupply && hasCollateral && hasLoans)" intact. Target the conditional that
currently reads "if (!hasFreeBalance || (hasSupply && hasCollateral &&
hasLoans)) return null" and change it to allow the collateral-without-loans
path.

---

Nitpick comments:
In `@src/pages/ChainflipLending/components/DashboardSidebar.tsx`:
- Around line 55-58: The computed available borrowing power (variable available
inside the useMemo using maxBorrow and totalBorrowedFiat) can go negative when
collateral falls; update the logic to clamp the displayed available value (e.g.,
Math.max(bnOrZero(maxBorrow).minus(totalBorrowedFiat), 0).toFixed(2) or similar)
and adjust the UI color based on sign (use the existing display path that
consumes available to render green for positive/zero and a warning color like
red/orange when negative), or if you prefer to show the negative value keep the
real negative figure but change the color logic to read the numeric sign from
the un-clamped bnOrZero(...) result to avoid misleading green styling for risky
negative balances.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 09fe4dde-85f4-470e-b734-4e41b688efcd

📥 Commits

Reviewing files that changed from the base of the PR and between fae220c and a487b3c.

📒 Files selected for processing (1)
  • src/pages/ChainflipLending/components/DashboardSidebar.tsx

@gomesalexandre
Copy link
Contributor Author

btw @NeOMakinG did some more visual polish to make things even closer to the Figma:

  • Dashed borders on empty section cards (Supplied/Collateral/Borrowed)
  • Outline ↑ Withdraw buttons with arrow prefix
  • White bold section totals instead of subtle gray
  • Solid dark CTA buttons in empty states
  • Consistent sidebar button font sizing
  • Fixed all CodeRabbit feedback (stale state on View Dashboard, LTV gauge div/0 guard, localized strings)
  • Also fixed WithdrawConfirm + CollateralConfirm same stale-state pattern proactively

Latest QAbot run (post-polish): https://qabot-kappa.vercel.app/runs/0449d471-a1bf-47a1-adfa-b95c9ac7b4e6

All 6 steps passed. See earlier runs too:

…details

- Repay button uses ↻ prefix instead of ↑ (not a withdraw action)
- "Start Liquidation" link now has → arrow suffix matching Figma
- Secondary action prefix is now configurable per section

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@e2e/fixtures/chainflip-lending-revamp-ui.yaml`:
- Around line 32-33: Update the fixture wording to match the UI polish by
removing or replacing stale style adjectives ("ghost"/"outline") and using the
current button descriptors or neutral labels; specifically edit the sentence
containing "Blue filled \"+ Deposit\" button and ghost \"Withdraw\" button in
Free Balance header" to instead reference the current style (e.g., "Blue \"+
Deposit\" button and \"Withdraw\" button" or the new style name used in the app)
and make the same change for the similar text at the other occurrence (the block
mentioning "Supply" and "Add Collateral") so the expected strings "+ Deposit",
"Withdraw", "Supply", and "Add Collateral" match the app's latest wording and
style terminology.

In `@src/pages/ChainflipLending/components/DashboardSections.tsx`:
- Around line 207-208: The column headers rendered with RawText (e.g., the
hardcoded "Asset" and "Balance" strings and the similar literals at the other
noted locations) should be localized: import or use the existing translation
helper (e.g., useTranslation()/t or i18n.t) and replace the hardcoded RawText
contents with translated keys (e.g., t('dashboard.asset'),
t('dashboard.balance')) and add those keys to the translation files; update all
occurrences referenced (the RawText usages at the other ranges) so the dashboard
shows only translated strings.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 212924d7-4ba3-4a89-8bb8-f372fc226851

📥 Commits

Reviewing files that changed from the base of the PR and between a487b3c and a4584c3.

📒 Files selected for processing (3)
  • .gemini/settings.json
  • e2e/fixtures/chainflip-lending-revamp-ui.yaml
  • src/pages/ChainflipLending/components/DashboardSections.tsx

@gomesalexandre
Copy link
Contributor Author

btw @NeOMakinG did another round of visual polish + comprehensive testing including the full lending lifecycle (add collateral → borrow → LTV bar verification → repay flow). See comprehensive QAbot run:

https://qabot-kappa.vercel.app/runs/375d7b75-a5c2-41f1-be22-cbce7354996d

19/19 steps passed covering:

  • Funded dashboard with active loan (LTV bar, Borrowing Power gauge, all sections populated)
  • All 6 modals (Deposit, Supply, Borrow, Repay, Add Collateral, Withdraw)
  • Sidebar state transitions
  • Markets tab (6-column table)
  • No-wallet landing state
  • Visual consistency checks (dashed borders, button styles, typography)

Latest polish (pass 5):

  • Repay button uses prefix (not - it's not a withdraw)
  • "Start Liquidation →" link now has arrow suffix per Figma

@gomesalexandre
Copy link
Contributor Author

@NeOMakinG GM, I'm Gemini, Beep Boop 🤖, I'm a bot who does the UI thing, and I did a super deep thorough visual QA pass against the Figma mocks using MCP. What do you think?

Regarding your question: Yes, the debt being in token terms (USDC/USDT) is correct. In lending protocols, your debt obligation is the actual token amount you borrowed plus interest, while the fiat (user currency) value will fluctuate with the market. I've ensured the UI clearly displays both the precise crypto amount and its fiat equivalent to keep things perfectly clear for the user.

Here is a summary of the thorough visual QA pass I completed:

🛠️ What I Fixed & Improved:

  • Table Alignments: Fixed the alignment in the Borrowed section and Markets table. The headers now align perfectly with the row content (especially the crypto amounts and borrow rates), regardless of high-precision decimals.
  • Clickable Asset Rows: Transformed the asset rows in the Supplied, Collateral, and Borrowed sections into clickable buttons with proper hover states (_hover={{ bg: 'whiteAlpha.100' }}). Clicking them now navigates directly to the pool page for that specific asset.
  • Tabs Styling: Updated the "My Dashboard" and "Markets" tabs from the default soft-rounded pills to the unstyled line-based tabs, perfectly matching the Figma design.
  • Unauthenticated Layout: Fixed a layout bug where the "Connect Wallet" button on the unauthenticated dashboard was wrapping to a new line instead of sitting next to the summary cards.
  • Empty State Borders: Empty state cards (Supplied, Collateral, Borrowed) had invisible dashed borders because borderWidth wasn't set. Added borderWidth={1} so the dashed outlines display correctly.
  • Button Sizing & Colors:
    • Increased the Empty State primary CTA buttons (+ Deposit) from size='sm' to size='md'.
    • Applied colorScheme='white' to the secondary header actions (↑ Withdraw, ⟲ Repay) to match the white text in the mocks.
    • Updated the Borrow modal to dynamically change the projected LTV percentage to bold red.500 if it exceeds the risky threshold.
  • Repay Modal Alignment: Fixed the alignment of the "Outstanding debt" and "Free balance" sections in the Repay modal so the values align beautifully with the right edge of the numeric input field.

✅ What I Confirmed Looks Good Already:

  • Borrowing Power Gauge: The colors and logic perfectly map to the design's safe/risky states.
  • Loan Health Indicator: The multi-segment LTV gauge and the simple white thumb indicator accurately reflect the Figma specs.
  • Next Steps Card: The layout, button sizes (40px height), and spacing are solid.
  • InitView (Empty Dashboard): The large, centralized empty state with the full-width size='lg' button is well-proportioned and matches the zero-state mocks perfectly.

Everything is pushed and the codebase is passing pnpm run lint and pnpm run type-check.

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.

♻️ Duplicate comments (1)
src/pages/ChainflipLending/components/DashboardSidebar.tsx (1)

208-209: ⚠️ Potential issue | 🟠 Major

Next Steps card hides valid borrow action when free balance is zero.

The condition !hasFreeBalance || (hasSupply && hasCollateral && hasLoans) incorrectly hides the card when the user has no free balance but has collateral without loans. In this case, the user should still see the "Borrow" CTA (the hasCollateral && !hasLoans branch at line 265).

🐛 Proposed fix
-  // Hide when user has everything or no free balance
-  if (!hasFreeBalance || (hasSupply && hasCollateral && hasLoans)) return null
+  // Hide only when all tracked steps are completed
+  if (hasSupply && hasCollateral && hasLoans) return null
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ChainflipLending/components/DashboardSidebar.tsx` around lines 208
- 209, The sidebar currently returns null when !hasFreeBalance, which also hides
the valid "Borrow" CTA for users who have collateral and no loans; update the
condition in DashboardSidebar to only hide when the user has no free balance AND
does not have collateral-only borrow eligibility. Replace the line "if
(!hasFreeBalance || (hasSupply && hasCollateral && hasLoans)) return null" with
a condition that preserves the borrow case, e.g. return null only when
((!hasFreeBalance && !(hasCollateral && !hasLoans)) || (hasSupply &&
hasCollateral && hasLoans)), so the branch for hasCollateral && !hasLoans still
renders the Next Steps card.
🧹 Nitpick comments (3)
src/pages/ChainflipLending/Pool/components/Borrow/BorrowInput.tsx (1)

36-37: Avoid duplicating the risky LTV fallback constant across borrow components.

DEFAULT_RISKY_LTV is defined here and also in src/pages/ChainflipLending/Pool/components/Borrow/LtvGauge.tsx. Keeping it in one shared constant avoids drift between threshold logic and gauge rendering.

♻️ Suggested shared-constant extraction
-const DEFAULT_RISKY_LTV = 0.8
+import { DEFAULT_RISKY_LTV } from '@/pages/ChainflipLending/constants'
// src/pages/ChainflipLending/constants.ts
export const DEFAULT_RISKY_LTV = 0.8
-const DEFAULT_RISKY_LTV = 0.8
+import { DEFAULT_RISKY_LTV } from '@/pages/ChainflipLending/constants'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ChainflipLending/Pool/components/Borrow/BorrowInput.tsx` around
lines 36 - 37, Remove the duplicated DEFAULT_RISKY_LTV constant from BorrowInput
and LtvGauge and extract it to a single shared export (e.g., export const
DEFAULT_RISKY_LTV = 0.8) in a new shared constants module; then replace the
local definitions by importing DEFAULT_RISKY_LTV into both BorrowInput.tsx and
LtvGauge.tsx so both components reference the same symbol and avoid drift.
src/pages/ChainflipLending/components/Markets.tsx (1)

218-243: Consider extracting repeated Tab styling to reduce duplication.

Both Tab components share identical styling props. Extracting to a shared style object would reduce duplication and ease future styling changes.

💅 Proposed refactor
+const tabStyles = {
+  px: 0,
+  py: 2,
+  color: 'text.subtle',
+  fontWeight: 'bold',
+  _selected: {
+    color: 'text.base',
+    borderBottomWidth: 2,
+    borderColor: 'text.base',
+  },
+}
+
 <TabList data-testid='chainflip-lending-tabs' gap={6}>
-  <Tab
-    px={0}
-    py={2}
-    color='text.subtle'
-    fontWeight='bold'
-    _selected={{
-      color: 'text.base',
-      borderBottomWidth: 2,
-      borderColor: 'text.base',
-    }}
-  >
+  <Tab {...tabStyles}>
     {translate('chainflipLending.myDashboard')}
   </Tab>
-  <Tab
-    px={0}
-    py={2}
-    color='text.subtle'
-    fontWeight='bold'
-    _selected={{
-      color: 'text.base',
-      borderBottomWidth: 2,
-      borderColor: 'text.base',
-    }}
-  >
+  <Tab {...tabStyles}>
     {translate('chainflipLending.markets')}
   </Tab>
 </TabList>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ChainflipLending/components/Markets.tsx` around lines 218 - 243,
Both Tab components in Markets.tsx repeat identical props; extract the shared
props into a single reusable style to reduce duplication. Create a const (e.g.,
tabProps or tabStyle) or a small wrapper component (e.g., StyledTab) and use it
for both Tab instances so the shared props (px, py, color, fontWeight,
_selected) are defined in one place; update the two Tab usages to spread or use
that shared identifier to keep behavior identical.
src/pages/ChainflipLending/components/DashboardSections.tsx (1)

314-321: Duplicate poolsByAssetId logic can be extracted to a shared hook or utility.

The same reduce pattern to create a pool lookup map is duplicated in SuppliedSection (lines 314-321) and BorrowedSection (lines 592-599). Consider extracting this to a custom hook or adding a poolsByAssetId property to useChainflipLendingPools.

♻️ Option 1: Extract to hook
// In useChainflipLendingPools.ts
export const useChainflipLendingPools = () => {
  // ... existing logic ...

  const poolsByAssetId = useMemo(
    () =>
      pools.reduce<Partial<Record<AssetId, ChainflipLendingPoolWithFiat>>>((acc, pool) => {
        if (pool.assetId) acc[pool.assetId] = pool
        return acc
      }, {}),
    [pools],
  )

  return { pools, poolsByAssetId, isLoading }
}

Also applies to: 592-599

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ChainflipLending/components/DashboardSections.tsx` around lines 314
- 321, Extract the duplicated reduce logic that builds poolsByAssetId into the
shared data layer: add a memoized poolsByAssetId property to the existing
useChainflipLendingPools hook (or create a small util used by both) so
SuppliedSection and BorrowedSection can consume it directly; specifically, move
the reduce from components where poolsByAssetId is currently computed into
useChainflipLendingPools and return { pools, poolsByAssetId, ... } (or export a
helper) and update SuppliedSection and BorrowedSection to use the new property
instead of re-creating the map.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/pages/ChainflipLending/components/DashboardSidebar.tsx`:
- Around line 208-209: The sidebar currently returns null when !hasFreeBalance,
which also hides the valid "Borrow" CTA for users who have collateral and no
loans; update the condition in DashboardSidebar to only hide when the user has
no free balance AND does not have collateral-only borrow eligibility. Replace
the line "if (!hasFreeBalance || (hasSupply && hasCollateral && hasLoans))
return null" with a condition that preserves the borrow case, e.g. return null
only when ((!hasFreeBalance && !(hasCollateral && !hasLoans)) || (hasSupply &&
hasCollateral && hasLoans)), so the branch for hasCollateral && !hasLoans still
renders the Next Steps card.

---

Nitpick comments:
In `@src/pages/ChainflipLending/components/DashboardSections.tsx`:
- Around line 314-321: Extract the duplicated reduce logic that builds
poolsByAssetId into the shared data layer: add a memoized poolsByAssetId
property to the existing useChainflipLendingPools hook (or create a small util
used by both) so SuppliedSection and BorrowedSection can consume it directly;
specifically, move the reduce from components where poolsByAssetId is currently
computed into useChainflipLendingPools and return { pools, poolsByAssetId, ... }
(or export a helper) and update SuppliedSection and BorrowedSection to use the
new property instead of re-creating the map.

In `@src/pages/ChainflipLending/components/Markets.tsx`:
- Around line 218-243: Both Tab components in Markets.tsx repeat identical
props; extract the shared props into a single reusable style to reduce
duplication. Create a const (e.g., tabProps or tabStyle) or a small wrapper
component (e.g., StyledTab) and use it for both Tab instances so the shared
props (px, py, color, fontWeight, _selected) are defined in one place; update
the two Tab usages to spread or use that shared identifier to keep behavior
identical.

In `@src/pages/ChainflipLending/Pool/components/Borrow/BorrowInput.tsx`:
- Around line 36-37: Remove the duplicated DEFAULT_RISKY_LTV constant from
BorrowInput and LtvGauge and extract it to a single shared export (e.g., export
const DEFAULT_RISKY_LTV = 0.8) in a new shared constants module; then replace
the local definitions by importing DEFAULT_RISKY_LTV into both BorrowInput.tsx
and LtvGauge.tsx so both components reference the same symbol and avoid drift.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6d0d1fc5-84eb-4264-9d9c-3698a1bd60ef

📥 Commits

Reviewing files that changed from the base of the PR and between a4584c3 and 9f7d329.

📒 Files selected for processing (10)
  • .gitignore
  • src/assets/translations/en/main.json
  • src/pages/ChainflipLending/Pool/components/Borrow/BorrowInput.tsx
  • src/pages/ChainflipLending/Pool/components/Borrow/LtvGauge.tsx
  • src/pages/ChainflipLending/Pool/components/Borrow/RepayInput.tsx
  • src/pages/ChainflipLending/components/ChainflipLendingHeader.tsx
  • src/pages/ChainflipLending/components/DashboardSections.tsx
  • src/pages/ChainflipLending/components/DashboardSidebar.tsx
  • src/pages/ChainflipLending/components/LoanHealth.tsx
  • src/pages/ChainflipLending/components/Markets.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/pages/ChainflipLending/components/LoanHealth.tsx

gomes-bot and others added 2 commits March 18, 2026 14:19
- Fix Next Steps card hiding when no free balance but collateral exists
- Localize hardcoded column headers in dashboard sections
- Fix e2e fixture button style descriptions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

2 participants