Skip to content

Conversation

@jigar-arc10
Copy link
Contributor

@jigar-arc10 jigar-arc10 commented Nov 11, 2025

Summary by CodeRabbit

  • New Features

    • Added dropdown-driven wallet status display showing wallet name, icon, and USD balance.
    • Introduced wallet details popup with address, AKT/USDC balances displayed in USD.
  • Improvements

    • Integrated live market pricing data for accurate AKT price updates.
    • Enhanced wallet balance display with real-time USD value conversion.

@jigar-arc10 jigar-arc10 requested a review from a team as a code owner November 11, 2025 17:41
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 11, 2025

Walkthrough

This PR refactors wallet UI presentation from a detailed WalletInfo component to a compact dropdown-driven WalletStatus interface, introduces a new WalletPopup component for wallet details display, and updates market data fetching to retrieve live CoinGecko pricing with enhanced error handling and a dedicated AKT price hook.

Changes

Cohort / File(s) Summary
Wallet UI Refactoring
apps/provider-console/src/components/layout/WalletStatus.tsx
Replaces WalletInfo with a new dropdown-driven presentation; adds local state for DropdownMenu visibility; shows wallet icon, name (with truncation), and USD balance; delegates detailed wallet information to WalletPopup; adds getSplitText helper for name truncation; replaces spinner size from small to medium; maintains ConnectWalletButton display when not connected.
New Wallet Popup Component
apps/provider-console/src/components/wallet/WalletPopup.tsx
New React component displaying wallet address, AKT and USDC balances with USD conversion; integrates WalletProvider for address/logout and PricingProvider for pricing; shows blockchain unavailability message when walletBalances is null; includes disconnect wallet button.
Market Data Hook Updates
apps/provider-console/src/queries/useMarketData.ts
Updates getMarketData to fetch live CoinGecko data with type-safe MarketData return; adds error handling with fallback to zeroed data; introduces new getAKTPrice() function returning Coinbase USD price as string; adds useAKTData hook with 5-minute refetch interval for AKT price queries.

Sequence Diagram

sequenceDiagram
    participant User
    participant WalletStatus
    participant DropdownMenu
    participant WalletPopup
    participant WalletProvider
    participant PricingProvider

    User->>WalletStatus: Click wallet header
    WalletStatus->>DropdownMenu: Toggle open state
    DropdownMenu->>WalletPopup: Render in dropdown
    WalletPopup->>WalletProvider: Get wallet address
    WalletPopup->>PricingProvider: Fetch AKT price
    PricingProvider-->>WalletPopup: Return pricing data
    WalletPopup->>WalletPopup: Calculate balances & conversions
    WalletPopup-->>User: Display wallet details

    User->>WalletPopup: Click disconnect
    WalletPopup->>WalletProvider: Trigger logout
    WalletProvider-->>WalletStatus: Clear connection
    WalletStatus-->>User: Show ConnectWalletButton
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • WalletStatus.tsx: Structural UI refactoring with new state management and dropdown integration requires attention to user interaction flow and edge cases
  • WalletPopup.tsx: New component structure with wallet provider integration and balance calculations should be verified for correctness
  • useMarketData.ts: API integration changes and error handling paths need validation; verify CoinGecko endpoint behavior and fallback logic

Suggested reviewers

  • devalpatel67
  • stalniy

Poem

🐰 A dropdown twirl, a balance so bright,
Wallets now compact, yet full of delight!
From CoinGecko's live data, prices align,
New popups and hooks make the UI shine!
Connected or not, the UX is just right!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title mentions 'AKT dropdown popup design change' which reflects the main WalletStatus UI refactor from a detailed panel to a compact dropdown presentation, aligning with the primary changes across the affected components.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/provider-console/new-wallet-info-popup

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.

@codecov
Copy link

codecov bot commented Nov 11, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 46.85%. Comparing base (f784754) to head (7c706bc).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2202      +/-   ##
==========================================
- Coverage   47.19%   46.85%   -0.35%     
==========================================
  Files        1023     1013      -10     
  Lines       29078    28729     -349     
  Branches     7584     7543      -41     
==========================================
- Hits        13724    13461     -263     
+ Misses      14961    14884      -77     
+ Partials      393      384       -9     
Flag Coverage Δ *Carryforward flag
api 81.94% <ø> (ø) Carriedforward from f784754
deploy-web 25.96% <ø> (ø) Carriedforward from f784754
log-collector ?
notifications 87.94% <ø> (ø) Carriedforward from f784754
provider-console 81.48% <ø> (ø)
provider-proxy 85.28% <ø> (ø) Carriedforward from f784754

*This pull request uses carry forward flags. Click here to find out more.
see 10 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f784754 and 7c706bc.

📒 Files selected for processing (3)
  • apps/provider-console/src/components/layout/WalletStatus.tsx (1 hunks)
  • apps/provider-console/src/components/wallet/WalletPopup.tsx (1 hunks)
  • apps/provider-console/src/queries/useMarketData.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/provider-console/src/components/layout/WalletStatus.tsx
  • apps/provider-console/src/components/wallet/WalletPopup.tsx
  • apps/provider-console/src/queries/useMarketData.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/provider-console/src/components/layout/WalletStatus.tsx
  • apps/provider-console/src/components/wallet/WalletPopup.tsx
  • apps/provider-console/src/queries/useMarketData.ts
🧠 Learnings (1)
📚 Learning: 2025-10-15T16:39:55.348Z
Learnt from: jzsfkzm
Repo: akash-network/console PR: 2039
File: apps/deploy-web/tests/ui/change-wallets.spec.ts:4-10
Timestamp: 2025-10-15T16:39:55.348Z
Learning: In the Akash Console E2E tests using the context-with-extension fixture, the first wallet is automatically created during fixture setup via `importWalletToLeap` in `apps/deploy-web/tests/ui/fixture/wallet-setup.ts`, so tests that call `frontPage.createWallet()` are creating a second wallet to test wallet switching functionality.

Applied to files:

  • apps/provider-console/src/components/wallet/WalletPopup.tsx
🧬 Code graph analysis (3)
apps/provider-console/src/components/layout/WalletStatus.tsx (6)
apps/provider-console/src/context/WalletProvider/WalletProvider.tsx (1)
  • useWallet (340-342)
apps/provider-console/src/hooks/useWalletBalance.ts (1)
  • useTotalWalletBalance (11-26)
apps/provider-console/src/utils/styleUtils.ts (1)
  • cn (4-6)
apps/provider-console/src/components/wallet/WalletPopup.tsx (1)
  • WalletPopup (16-67)
apps/provider-console/src/components/wallet/ConnectWalletButton.tsx (1)
  • ConnectWalletButton (16-24)
packages/ui/components/spinner.tsx (1)
  • Spinner (10-39)
apps/provider-console/src/components/wallet/WalletPopup.tsx (2)
apps/provider-console/src/utils/constants.ts (1)
  • uAktDenom (23-23)
packages/ui/components/custom/address.tsx (1)
  • Address (25-57)
apps/provider-console/src/queries/useMarketData.ts (1)
apps/provider-console/src/types/dashboard.ts (1)
  • MarketData (100-107)
⏰ 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: test-build
🔇 Additional comments (1)
apps/provider-console/src/components/wallet/WalletPopup.tsx (1)

33-54: Nice resilience message path.

Thanks for keeping the blockchain-unavailable fallback inside the balance panel; it preserves context for the user.

Comment on lines +30 to +78
<DropdownMenu modal={false} open={open}>
<DropdownMenuTrigger asChild>
<div
className={cn("bg-background text-foreground flex items-center justify-center rounded-md border px-4 py-2 text-sm")}
onMouseOver={() => setOpen(true)}
>
<div className="flex items-center space-x-2" aria-label="Connected wallet name and balance">
<Wallet className="text-xs" />
{walletName?.length > 20 ? (
<span className="text-xs">{getSplitText(walletName, 4, 4)}</span>
) : (
<span className="text-xs">{walletName}</span>
)}
</div>

{walletBalance > 0 && <div className="px-2">|</div>}

<div className="text-xs">
{walletBalance > 0 && (
<FormattedNumber
value={walletBalance}
// eslint-disable-next-line react/style-prop-object
style="currency"
currency="USD"
/>
)}
</div>

<div>
<NavArrowDown className="ml-2 text-xs" />
</div>
</div>
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
onMouseLeave={() => {
setOpen(false);
}}
>
<ClickAwayListener
onClickAway={() => {
setOpen(false);
}}
>
<div>
<WalletPopup walletBalances={walletBalances} />
</div>
</ClickAwayListener>
</DropdownMenuContent>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Restore an accessible trigger for the dropdown.

With the trigger now being a plain <div> that only sets open on onMouseOver, touch users can’t open the wallet menu at all and keyboard users can’t focus/activate it, so they lose the ability to see balances or disconnect. Please use a focusable button (or let the Radix trigger manage state) and wire onOpenChange so pointer, keyboard, and touch interactions all work.

-              <DropdownMenu modal={false} open={open}>
+              <DropdownMenu modal={false} open={open} onOpenChange={setOpen}>
                 <DropdownMenuTrigger asChild>
-                  <div
-                    className={cn("bg-background text-foreground flex items-center justify-center rounded-md border px-4 py-2 text-sm")}
-                    onMouseOver={() => setOpen(true)}
-                  >
+                  <button
+                    type="button"
+                    className={cn("bg-background text-foreground flex items-center justify-center rounded-md border px-4 py-2 text-sm")}
+                    onMouseEnter={() => setOpen(true)}
+                    onFocus={() => setOpen(true)}
+                    onClick={() => setOpen((prev) => !prev)}
+                  >
 ...
-                  </div>
+                  </button>
                 </DropdownMenuTrigger>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<DropdownMenu modal={false} open={open}>
<DropdownMenuTrigger asChild>
<div
className={cn("bg-background text-foreground flex items-center justify-center rounded-md border px-4 py-2 text-sm")}
onMouseOver={() => setOpen(true)}
>
<div className="flex items-center space-x-2" aria-label="Connected wallet name and balance">
<Wallet className="text-xs" />
{walletName?.length > 20 ? (
<span className="text-xs">{getSplitText(walletName, 4, 4)}</span>
) : (
<span className="text-xs">{walletName}</span>
)}
</div>
{walletBalance > 0 && <div className="px-2">|</div>}
<div className="text-xs">
{walletBalance > 0 && (
<FormattedNumber
value={walletBalance}
// eslint-disable-next-line react/style-prop-object
style="currency"
currency="USD"
/>
)}
</div>
<div>
<NavArrowDown className="ml-2 text-xs" />
</div>
</div>
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
onMouseLeave={() => {
setOpen(false);
}}
>
<ClickAwayListener
onClickAway={() => {
setOpen(false);
}}
>
<div>
<WalletPopup walletBalances={walletBalances} />
</div>
</ClickAwayListener>
</DropdownMenuContent>
<DropdownMenu modal={false} open={open} onOpenChange={setOpen}>
<DropdownMenuTrigger asChild>
<button
type="button"
className={cn("bg-background text-foreground flex items-center justify-center rounded-md border px-4 py-2 text-sm")}
onMouseEnter={() => setOpen(true)}
onFocus={() => setOpen(true)}
onClick={() => setOpen((prev) => !prev)}
>
<div className="flex items-center space-x-2" aria-label="Connected wallet name and balance">
<Wallet className="text-xs" />
{walletName?.length > 20 ? (
<span className="text-xs">{getSplitText(walletName, 4, 4)}</span>
) : (
<span className="text-xs">{walletName}</span>
)}
</div>
{walletBalance > 0 && <div className="px-2">|</div>}
<div className="text-xs">
{walletBalance > 0 && (
<FormattedNumber
value={walletBalance}
// eslint-disable-next-line react/style-prop-object
style="currency"
currency="USD"
/>
)}
</div>
<div>
<NavArrowDown className="ml-2 text-xs" />
</div>
</button>
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
onMouseLeave={() => {
setOpen(false);
}}
>
<ClickAwayListener
onClickAway={() => {
setOpen(false);
}}
>
<div>
<WalletPopup walletBalances={walletBalances} />
</div>
</ClickAwayListener>
</DropdownMenuContent>
🤖 Prompt for AI Agents
In apps/provider-console/src/components/layout/WalletStatus.tsx around lines 30
to 78, the dropdown trigger is a non-focusable div using onMouseOver which
breaks keyboard and touch accessibility; replace the div trigger with a
focusable element (e.g., a <button> via DropdownMenuTrigger asChild) or allow
Radix to manage state, and wire the DropdownMenu onOpenChange prop to update
local open state so pointer, keyboard (Enter/Space), and touch interactions
work; ensure the trigger remains styled the same, is focusable, and includes
appropriate aria-label/role for screen readers.

Comment on lines +11 to +13
const coinbasePrice = data.tickers.find((ticker: any) => ticker.market.name === "Coinbase Exchange");
const price = coinbasePrice ? parseFloat(coinbasePrice.converted_last.usd) : 0;

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Replace any with typed CoinGecko response.

any is disallowed here and it hides the risk of dereferencing missing fields when Coinbase data is absent. Let’s type the response and normalise the USD value before using it so we stay type-safe and avoid toFixed on undefined.

 import type { QueryKey, UseQueryOptions } from "@tanstack/react-query";
 import { useQuery } from "@tanstack/react-query";

 import type { MarketData } from "@src/types";
 import { QueryKeys } from "./queryKeys";
+
+type CoinGeckoTicker = {
+  market: { name: string };
+  converted_last: { usd: number | string };
+};
+
+type CoinGeckoResponse = {
+  tickers: CoinGeckoTicker[];
+};
+
+function extractCoinbaseUsd(tickers: CoinGeckoTicker[]): number | null {
+  const usd = tickers.find((ticker) => ticker.market.name === "Coinbase Exchange")?.converted_last.usd;
+  const numericUsd = typeof usd === "string" ? Number.parseFloat(usd) : usd;
+  return typeof numericUsd === "number" && Number.isFinite(numericUsd) ? numericUsd : null;
+}
 
 async function getMarketData(): Promise<MarketData> {
   try {
-    const response = await fetch("https://api.coingecko.com/api/v3/coins/akash-network/tickers");
-    const data = await response.json();
-    const coinbasePrice = data.tickers.find((ticker: any) => ticker.market.name === "Coinbase Exchange");
-    const price = coinbasePrice ? parseFloat(coinbasePrice.converted_last.usd) : 0;
+    const response = await fetch("https://api.coingecko.com/api/v3/coins/akash-network/tickers");
+    const data: CoinGeckoResponse = await response.json();
+    const price = extractCoinbaseUsd(data.tickers) ?? 0;
 
     return {
       price,
@@
 async function getAKTPrice(): Promise<{ aktPrice: string }> {
   const response = await fetch("https://api.coingecko.com/api/v3/coins/akash-network/tickers");
-  const data = await response.json();
-  const coinbasePrice = data.tickers.find((ticker: any) => ticker.market.name === "Coinbase Exchange");
+  const data: CoinGeckoResponse = await response.json();
+  const usdPrice = extractCoinbaseUsd(data.tickers);
   return {
-    aktPrice: coinbasePrice ? coinbasePrice.converted_last.usd.toFixed(2) : "N/A"
+    aktPrice: usdPrice !== null ? usdPrice.toFixed(2) : "N/A"
   };
 }

As per coding guidelines

Also applies to: 46-48

🤖 Prompt for AI Agents
In apps/provider-console/src/queries/useMarketData.ts around lines 11-13 (and
similarly at lines 46-48), the code uses `any` for the CoinGecko response and
directly dereferences fields which can be absent; define a proper TypeScript
interface for the CoinGecko response (ticker, market.name, converted_last.usd)
and use it instead of `any`, then safely read the USD value using optional
chaining and a default (e.g., const usd = ticker?.converted_last?.usd ?? "0"),
parse/normalize that value to a number (parseFloat or Number) before any math or
toFixed, and finally use the normalized number (or 0) so toFixed is never called
on undefined; update the other occurrences at lines 46-48 the same way.

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