Skip to content

Create home dashboard screen#153

Open
vrickish wants to merge 4 commits intoancore-org:mainfrom
vrickish:create-home-dashboard-screen
Open

Create home dashboard screen#153
vrickish wants to merge 4 commits intoancore-org:mainfrom
vrickish:create-home-dashboard-screen

Conversation

@vrickish
Copy link
Copy Markdown

@vrickish vrickish commented Mar 25, 2026

Closes #83


Description

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📝 Documentation update
  • 🔧 Configuration change
  • ♻️ Code refactoring
  • ⚡ Performance improvement
  • ✅ Test addition/improvement

Security Impact

  • This change involves cryptographic operations
  • This change affects account validation logic
  • This change modifies smart contracts
  • This change handles user private keys
  • This change affects authorization/authentication
  • No security impact

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • E2E tests added/updated (if applicable)

Test Coverage

  • Current coverage: __%
  • New/modified code coverage: __%

Manual Testing Steps

Breaking Changes

  • This PR introduces breaking changes

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

For High-Security Changes

  • I have documented all security assumptions
  • I have considered attack vectors
  • I have added security-focused test cases
  • I have reviewed against the threat model

Related Issues

Closes #
Related to #

Additional Context

Reviewer Notes


Summary by CodeRabbit

Release Notes

  • New Features
    • Added home dashboard screen with account address display and copy-to-clipboard functionality
    • Implemented balance card showing XLM holdings with network indicator (mainnet/testnet)
    • Added quick actions menu including Send, Receive, QR Code, and Buy XLM options
    • Included balance refresh capability with visual loading indicator
    • Added recent activity section with empty state for new accounts

…n wallet components

- Added @frontend-design/, @brief.md, and .clinerules to .gitignore
- Added new HomeScreen component with dashboard layout
- Added AccountHeader, BalanceCard, and QuickActions components
- Added useAccountBalance hook
- Updated main.tsx to include new components
- Removed unused React imports from components using new JSX transform
- Removed unused useEffect and Copy imports from HomeScreen
- All components now build without TypeScript warnings
- Removed eslint-disable-line comment for react-hooks/exhaustive-deps rule
- The rule definition was not found in ESLint configuration
- This fixes the pre-push hook lint failure
- Ran pnpm format to fix code style issues
- Applied consistent formatting across the entire codebase
- This fixes the pre-push hook formatting check
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 25, 2026

📝 Walkthrough

Walkthrough

Introduces a home dashboard screen for the extension wallet application, comprising UI components for displaying account information and balance, a custom React hook for balance management with polling, and supporting documentation and design guidelines.

Changes

Cohort / File(s) Summary
UI Components
apps/extension-wallet/src/components/AccountHeader.tsx, apps/extension-wallet/src/components/BalanceCard.tsx, apps/extension-wallet/src/components/QuickActions.tsx
Three new React components: AccountHeader displays account address with copy-to-clipboard action and network badge; BalanceCard shows XLM balance with USD conversion, loading/error states, and history chart; QuickActions provides Send, Receive, QR Code, and More buttons with additional actions row and status indicators.
Custom Hook & Data Management
apps/extension-wallet/src/hooks/useAccountBalance.ts
New hook managing balance state with initial fetch, 30-second polling interval with threshold-based updates, error handling, and utility functions (formatBalance, convertToUSD, formatUSD) for currency formatting.
Screen Component
apps/extension-wallet/src/screens/HomeScreen.tsx
Main screen component orchestrating AccountHeader, BalanceCard, and QuickActions; implements refresh flow with visual indicator, clipboard copy behavior, empty-state handling for new accounts, and settings/action callbacks.
Application Entry Point
apps/extension-wallet/src/main.tsx
Updated root rendering from SettingsScreen to HomeScreen with callback props (onSettingsClick, onSendClick, onReceiveClick); added vertical scrolling support.
Documentation & Design
brief.md, frontend-design/SKILL.md, frontend-design/LICENSE.txt
Feature specification document, frontend design skill guidelines covering aesthetics and anti-patterns, and Apache License 2.0 text file.
Configuration
.gitignore
Added entries for @frontend-design/, @brief.md, and .clinerules.

Sequence Diagram

sequenceDiagram
    participant User
    participant HomeScreen
    participant useAccountBalance
    participant AccountHeader
    participant BalanceCard
    participant QuickActions
    participant API as Backend API

    User->>HomeScreen: Load HomeScreen
    HomeScreen->>useAccountBalance: Call hook (mount)
    useAccountBalance->>API: fetchBalance()
    API-->>useAccountBalance: Return balance data
    useAccountBalance-->>HomeScreen: Return {balance, isLoading, error, refreshBalance}
    
    HomeScreen->>AccountHeader: Render with address & network
    HomeScreen->>BalanceCard: Render with balance, loading, error states
    HomeScreen->>QuickActions: Render with onSendClick, onReceiveClick callbacks
    
    HomeScreen-->>User: Display dashboard UI
    
    Note over useAccountBalance: 30-second polling interval starts
    loop Polling
        useAccountBalance->>API: fetchBalance() (background)
        API-->>useAccountBalance: Return updated balance
        alt Difference > threshold
            useAccountBalance->>HomeScreen: Update balance state
            HomeScreen->>BalanceCard: Re-render with new balance
        end
    end
    
    User->>BalanceCard: Click refresh button
    BalanceCard->>HomeScreen: Call onRefresh()
    HomeScreen->>useAccountBalance: Call refreshBalance()
    HomeScreen->>HomeScreen: Set isRefreshing=true
    useAccountBalance->>API: fetchBalance()
    API-->>useAccountBalance: Return balance
    useAccountBalance-->>HomeScreen: Update balance
    HomeScreen->>HomeScreen: Set isRefreshing=false
    HomeScreen->>BalanceCard: Update with isRefreshing=false
    BalanceCard-->>User: Display refreshed balance

    User->>AccountHeader: Click copy address
    AccountHeader->>HomeScreen: Call onCopyAddress()
    HomeScreen->>HomeScreen: navigator.clipboard.writeText(address)
    HomeScreen-->>User: Icon changes to indicate copy success
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related issues

  • Create Home Dashboard Screen #83: The implementation directly addresses this issue by delivering all specified Home Dashboard features: AccountHeader with address display and copy functionality, BalanceCard with balance and network indication, QuickActions for Send/Receive, refresh mechanism via useAccountBalance hook with polling, empty state handling, and settings menu integration.

Poem

🐰 A dashboard blooms with care and grace,
Balance shown in its rightful place,
Quick actions dance in buttons bright,
Account details, header's delight,
Polling thumps at thirty-second beat,
The home screen's now complete! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Create home dashboard screen' directly and accurately describes the primary change: implementation of a new HomeScreen component with dashboard layout and supporting UI elements.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Copy link
Copy Markdown

@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: 4

🧹 Nitpick comments (8)
apps/extension-wallet/src/components/BalanceCard.tsx (2)

29-30: Duplicate hardcoded conversion rate; use the shared utility instead.

The usdRate = 0.12 is hardcoded here, but useAccountBalance.ts already exports a convertToUSD(xlmAmount, rate) utility with the same default rate. If the rate needs updating, it would need to be changed in multiple places.

Proposed fix: import and use the shared utility
 import { RefreshCw, TrendingUp, AlertCircle, Coins } from 'lucide-react';
 import { Button } from '@ancore/ui-kit';
 import { Card, CardContent, CardHeader, CardTitle } from '@ancore/ui-kit';
+import { convertToUSD, formatUSD } from '../hooks/useAccountBalance';

 // ... in component body:

-  // Calculate approximate USD value (placeholder - in real app, fetch from API)
-  const usdRate = 0.12; // Example rate: 1 XLM = $0.12
-  const usdValue = balance * usdRate;
-  const formattedUsdValue = new Intl.NumberFormat('en-US', {
-    style: 'currency',
-    currency: 'USD',
-    minimumFractionDigits: 2,
-    maximumFractionDigits: 2,
-  }).format(usdValue);
+  // Calculate approximate USD value (placeholder - in real app, fetch from API)
+  const usdValue = convertToUSD(balance);
+  const formattedUsdValue = formatUSD(usdValue);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/extension-wallet/src/components/BalanceCard.tsx` around lines 29 - 30,
Replace the hardcoded usdRate/usdValue in BalanceCard.tsx by importing and using
the shared convertToUSD utility from useAccountBalance.ts; remove the local
usdRate constant and call convertToUSD(balance) (or convertToUSD(balance, rate)
if an override is needed) to compute the USD value so the single source of truth
for the conversion rate is used.

181-189: Consider moving the CSS animation to a stylesheet.

Inline <style> tags in React components can cause style recalculation on each render and make styles harder to maintain. Consider moving the @keyframes float animation to the global CSS file (index.css) or using a CSS-in-JS solution that handles deduplication.

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

In `@apps/extension-wallet/src/components/BalanceCard.tsx` around lines 181 - 189,
The inline <style> block defining `@keyframes` float and .animate-float inside
BalanceCard.tsx should be moved to a stylesheet (e.g., index.css) or converted
to a deduplicating CSS-in-JS rule; remove the inline <style> from
BalanceCard.tsx, add the `@keyframes` float and .animate-float rules to your
global CSS (or a styled component) and keep using the .animate-float className
on the element(s) in BalanceCard so the animation behavior remains identical
while avoiding per-render style injection and duplicates.
apps/extension-wallet/src/main.tsx (1)

11-15: Placeholder callbacks need actual navigation/action implementation.

The onSettingsClick, onSendClick, and onReceiveClick callbacks currently only log to console. Before this feature is complete, these should navigate to actual screens or trigger real actions. Consider adding a TODO comment or tracking this in an issue.

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

In `@apps/extension-wallet/src/main.tsx` around lines 11 - 15, Replace the
placeholder console.log callbacks passed to HomeScreen (props onSettingsClick,
onSendClick, onReceiveClick) with real navigation or action invocations: call
the app's navigation method (or dispatch appropriate actions) to navigate to
Settings, Send, and Receive screens respectively, or wire to the real
send/receive handlers; if the screens/handlers don't yet exist, add a TODO with
an associated issue ID and leave a clear stub that calls a navigation helper
(e.g., navigateToSettings/navigateToSend/navigateToReceive) so future work can
implement them. Ensure you update the callbacks in main.tsx where HomeScreen is
rendered and reference the exact prop names onSettingsClick, onSendClick, and
onReceiveClick.
brief.md (1)

41-43: Dependencies listed but not used in implementation.

The brief lists @ancore/core-sdk and @ancore/stellar as dependencies, but the current implementation uses stubbed/simulated data in useAccountBalance.ts. This is fine for a demo but should be noted for future integration work.

Would you like me to open an issue to track the integration of actual SDK dependencies?

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

In `@brief.md` around lines 41 - 43, The dependency list in brief.md includes
`@ancore/core-sdk` and `@ancore/stellar` but the implementation in
useAccountBalance.ts uses stubbed/simulated data; update brief.md to reflect
that these SDKs are not yet integrated (add a short note or "Stubbed data — SDK
integration pending") and add a TODO or link to a new issue tracking integration
of `@ancore/core-sdk` and `@ancore/stellar` so future work knows to replace stubs in
useAccountBalance.ts with real SDK calls.
apps/extension-wallet/src/hooks/useAccountBalance.ts (2)

62-64: Missing dependency in useEffect will cause lint warning.

The refreshBalance callback is called inside this effect but not listed in the dependency array. While the intent is to run once on mount, this will trigger an exhaustive-deps lint warning.

Proposed fix: suppress lint or restructure

Option 1 - Add eslint disable comment (if intentional):

   // Initial fetch on mount
   useEffect(() => {
     refreshBalance();
+    // eslint-disable-next-line react-hooks/exhaustive-deps
   }, []);

Option 2 - Include dependency (will re-fetch if refreshBalance identity changes):

   useEffect(() => {
     refreshBalance();
-  }, []);
+  }, [refreshBalance]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/extension-wallet/src/hooks/useAccountBalance.ts` around lines 62 - 64,
The useEffect in useAccountBalance.ts calls refreshBalance but omits it from the
dependency array, triggering an exhaustive-deps lint warning; fix by either
adding refreshBalance to the dependency array of the useEffect so it reruns if
refreshBalance identity changes, or if the intent is truly to run only once on
mount, add a one-line eslint disable comment above the effect (//
eslint-disable-next-line react-hooks/exhaustive-deps) with a short
justification; reference the useEffect that invokes refreshBalance and the
refreshBalance callback when making the change.

67-88: Stale closure: polling interval captures outdated balance and error values.

The interval callback on line 72 checks isLoading and error, but these values are captured when the effect runs. Since the effect re-runs when these dependencies change, this works for the guards. However, the balance comparison on line 76 uses the closure value which may be stale relative to what setBalance has set.

Additionally, line 72's !isLoading check is redundant since the effect already returns early on line 68 when isLoading is true.

Proposed fix: use functional state update and remove redundant check
   useEffect(() => {
     if (isLoading) return;

     const interval = setInterval(() => {
-      // Only update if not currently loading and no error
-      if (!isLoading && !error) {
+      if (!error) {
         fetchBalance()
           .then((newBalance) => {
-            // Only update if balance changed significantly (> 0.001 XLM)
-            if (Math.abs(newBalance - balance) > 0.001) {
-              setBalance(newBalance);
-            }
+            setBalance((prevBalance) => {
+              // Only update if balance changed significantly (> 0.001 XLM)
+              if (Math.abs(newBalance - prevBalance) > 0.001) {
+                return newBalance;
+              }
+              return prevBalance;
+            });
           })
           .catch((err) => {
             console.debug('Background balance update failed:', err);
           });
       }
     }, 30000);

     return () => clearInterval(interval);
-  }, [balance, isLoading, error, fetchBalance]);
+  }, [isLoading, error, fetchBalance]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/extension-wallet/src/hooks/useAccountBalance.ts` around lines 67 - 88,
The polling interval callback in useAccountBalance captures a stale balance and
redundantly checks isLoading; update the interval handler to remove the
redundant !isLoading guard and use a functional updater when updating state
(call setBalance(prev => { if (Math.abs(newBalance - prev) > 0.001) return
newBalance; return prev; })) so the comparison uses the latest balance; keep the
existing error logging behavior on fetchBalance().catch and ensure fetchBalance,
setBalance, balance, error, and isLoading are referenced to locate the change.
apps/extension-wallet/src/components/QuickActions.tsx (2)

44-44: Placeholder console.log should be wired to actual handlers or removed.

The QR Code, More, and Buy XLM actions (lines 44, 53, 139) currently log to console. Consider either:

  1. Adding callback props similar to onSendClick/onReceiveClick
  2. Implementing the actual functionality
  3. Disabling these buttons until implemented
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/extension-wallet/src/components/QuickActions.tsx` at line 44, Replace
the placeholder console.log handlers for the QR Code, More, and Buy XLM buttons
with real callbacks or disable them: add new props (e.g., onQrClick,
onMoreClick, onBuyXlmClick) to the QuickActions component prop type alongside
existing onSendClick/onReceiveClick, wire the buttons' onClick to call those
props, and either require callers to pass handlers or provide safe defaults
(no-op) or render the buttons disabled when the prop is undefined; update any
usage sites to pass the new handlers or leave them disabled until implemented.

154-160: Static placeholder values in transaction status card.

The network fees (~0.00001 XLM), speed (~3-5 seconds), and the 85% progress bar are hardcoded. These should eventually be fetched from the network or made configurable via props when real transaction handling is implemented.

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

In `@apps/extension-wallet/src/components/QuickActions.tsx` around lines 154 -
160, The Transaction Ready card in QuickActions.tsx uses hardcoded values
(network fees "~0.00001 XLM", speed "~3-5 seconds", and an 85% progress bar);
update the QuickActions component to accept props like networkFee, eta, and
progress (or fetch them in useEffect via a new
getNetworkFeeEstimate/getTxSpeedEstimate helper) and replace the static strings
and progress value with those dynamic values, providing sensible defaults if
props are omitted to preserve current UI behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.gitignore:
- Around line 66-67: The .gitignore entries use an incorrect `@` prefix so they
won't match actual files; update the entries to match the real paths by
replacing `@frontend-design/` with `frontend-design/` and `@brief.md` with
`brief.md` (or remove these lines entirely if you intend to track those files)
so Git will properly ignore the intended items.

In `@apps/extension-wallet/src/components/BalanceCard.tsx`:
- Around line 45-56: The particle positions are regenerated on every render
because Math.random() is called directly inside the Array.from(...).map in the
BalanceCard component; fix by generating and memoizing a stable array of
particle position objects (left, top, animationDelay, animationDuration) once
(e.g., in a useMemo or useState initializer) and map over that memoized array
instead of calling Math.random() in the render, keeping the existing key (index)
or use an id field in the memoized objects for stable keys.

In `@apps/extension-wallet/src/screens/HomeScreen.tsx`:
- Around line 19-21: The copy flow assumes success and never updates the copied
UI: add a local copied state via useState (e.g., const [copied, setCopied] =
useState(false)), implement a robust copy handler (e.g., handleCopy) that tries
navigator.clipboard.writeText(accountAddress) with try/catch, falls back to a
document.execCommand('copy') fallback, sets setCopied(true) on success and
setCopied(false) on failure, and resets copied after a short timeout; then wire
the copied state (or setCopied) into the UI where the address/network copy
buttons are rendered (references: accountAddress, network, copied, and the copy
handler locations around the blocks you noted at lines 29-33 and 67-71).
- Around line 22-27: The handleRefresh function can leave isRefreshing true if
refreshBalance() rejects; wrap the await refreshBalance() call in a try/finally
(or try/catch/finally) so that setIsRefreshing(false) is always invoked in the
finally block (instead of only in the setTimeout after a successful await),
referencing handleRefresh, refreshBalance, and setIsRefreshing to locate the
change; keep the simulated delay by calling setTimeout inside the finally before
clearing the refreshing state.

---

Nitpick comments:
In `@apps/extension-wallet/src/components/BalanceCard.tsx`:
- Around line 29-30: Replace the hardcoded usdRate/usdValue in BalanceCard.tsx
by importing and using the shared convertToUSD utility from
useAccountBalance.ts; remove the local usdRate constant and call
convertToUSD(balance) (or convertToUSD(balance, rate) if an override is needed)
to compute the USD value so the single source of truth for the conversion rate
is used.
- Around line 181-189: The inline <style> block defining `@keyframes` float and
.animate-float inside BalanceCard.tsx should be moved to a stylesheet (e.g.,
index.css) or converted to a deduplicating CSS-in-JS rule; remove the inline
<style> from BalanceCard.tsx, add the `@keyframes` float and .animate-float rules
to your global CSS (or a styled component) and keep using the .animate-float
className on the element(s) in BalanceCard so the animation behavior remains
identical while avoiding per-render style injection and duplicates.

In `@apps/extension-wallet/src/components/QuickActions.tsx`:
- Line 44: Replace the placeholder console.log handlers for the QR Code, More,
and Buy XLM buttons with real callbacks or disable them: add new props (e.g.,
onQrClick, onMoreClick, onBuyXlmClick) to the QuickActions component prop type
alongside existing onSendClick/onReceiveClick, wire the buttons' onClick to call
those props, and either require callers to pass handlers or provide safe
defaults (no-op) or render the buttons disabled when the prop is undefined;
update any usage sites to pass the new handlers or leave them disabled until
implemented.
- Around line 154-160: The Transaction Ready card in QuickActions.tsx uses
hardcoded values (network fees "~0.00001 XLM", speed "~3-5 seconds", and an 85%
progress bar); update the QuickActions component to accept props like
networkFee, eta, and progress (or fetch them in useEffect via a new
getNetworkFeeEstimate/getTxSpeedEstimate helper) and replace the static strings
and progress value with those dynamic values, providing sensible defaults if
props are omitted to preserve current UI behavior.

In `@apps/extension-wallet/src/hooks/useAccountBalance.ts`:
- Around line 62-64: The useEffect in useAccountBalance.ts calls refreshBalance
but omits it from the dependency array, triggering an exhaustive-deps lint
warning; fix by either adding refreshBalance to the dependency array of the
useEffect so it reruns if refreshBalance identity changes, or if the intent is
truly to run only once on mount, add a one-line eslint disable comment above the
effect (// eslint-disable-next-line react-hooks/exhaustive-deps) with a short
justification; reference the useEffect that invokes refreshBalance and the
refreshBalance callback when making the change.
- Around line 67-88: The polling interval callback in useAccountBalance captures
a stale balance and redundantly checks isLoading; update the interval handler to
remove the redundant !isLoading guard and use a functional updater when updating
state (call setBalance(prev => { if (Math.abs(newBalance - prev) > 0.001) return
newBalance; return prev; })) so the comparison uses the latest balance; keep the
existing error logging behavior on fetchBalance().catch and ensure fetchBalance,
setBalance, balance, error, and isLoading are referenced to locate the change.

In `@apps/extension-wallet/src/main.tsx`:
- Around line 11-15: Replace the placeholder console.log callbacks passed to
HomeScreen (props onSettingsClick, onSendClick, onReceiveClick) with real
navigation or action invocations: call the app's navigation method (or dispatch
appropriate actions) to navigate to Settings, Send, and Receive screens
respectively, or wire to the real send/receive handlers; if the screens/handlers
don't yet exist, add a TODO with an associated issue ID and leave a clear stub
that calls a navigation helper (e.g.,
navigateToSettings/navigateToSend/navigateToReceive) so future work can
implement them. Ensure you update the callbacks in main.tsx where HomeScreen is
rendered and reference the exact prop names onSettingsClick, onSendClick, and
onReceiveClick.

In `@brief.md`:
- Around line 41-43: The dependency list in brief.md includes `@ancore/core-sdk`
and `@ancore/stellar` but the implementation in useAccountBalance.ts uses
stubbed/simulated data; update brief.md to reflect that these SDKs are not yet
integrated (add a short note or "Stubbed data — SDK integration pending") and
add a TODO or link to a new issue tracking integration of `@ancore/core-sdk` and
`@ancore/stellar` so future work knows to replace stubs in useAccountBalance.ts
with real SDK calls.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f29b6460-285d-424a-8ab5-a5d378c1b2eb

📥 Commits

Reviewing files that changed from the base of the PR and between 240adb7 and 94995b4.

📒 Files selected for processing (10)
  • .gitignore
  • apps/extension-wallet/src/components/AccountHeader.tsx
  • apps/extension-wallet/src/components/BalanceCard.tsx
  • apps/extension-wallet/src/components/QuickActions.tsx
  • apps/extension-wallet/src/hooks/useAccountBalance.ts
  • apps/extension-wallet/src/main.tsx
  • apps/extension-wallet/src/screens/HomeScreen.tsx
  • brief.md
  • frontend-design/LICENSE.txt
  • frontend-design/SKILL.md

Comment on lines +66 to +67
@frontend-design/
@brief.md
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Gitignore entries don't match actual file/directory names.

The entries @frontend-design/ and @brief.md use an @ prefix, but the actual files in this PR are frontend-design/ and brief.md (without @). These gitignore rules won't match and the files will be tracked.

Either remove the @ prefix to ignore these files, or if the intent is to track them, remove these gitignore entries entirely.

Proposed fix (if intent is to ignore these paths)
 # Project-specific ignores
-@frontend-design/
-@brief.md
+frontend-design/
+brief.md
 .clinerules
📝 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
@frontend-design/
@brief.md
frontend-design/
brief.md
.clinerules
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.gitignore around lines 66 - 67, The .gitignore entries use an incorrect `@`
prefix so they won't match actual files; update the entries to match the real
paths by replacing `@frontend-design/` with `frontend-design/` and `@brief.md`
with `brief.md` (or remove these lines entirely if you intend to track those
files) so Git will properly ignore the intended items.

Comment on lines +45 to +56
{Array.from({ length: 20 }).map((_, i) => (
<div
key={i}
className="absolute w-1 h-1 bg-primary/20 rounded-full animate-float"
style={{
left: `${Math.random() * 100}%`,
top: `${Math.random() * 100}%`,
animationDelay: `${Math.random() * 5}s`,
animationDuration: `${3 + Math.random() * 7}s`,
}}
/>
))}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Math.random() in render causes particle positions to change on every re-render.

The particle positions are computed using Math.random() directly in the render function. Each time the component re-renders (e.g., when balance updates, refresh button clicked), all particles will jump to new random positions, creating a jarring visual effect.

Proposed fix: memoize particle positions
+import { useMemo } from 'react';
 import { RefreshCw, TrendingUp, AlertCircle, Coins } from 'lucide-react';
 // ... other imports

 export function BalanceCard({
   // ... props
 }: BalanceCardProps) {
+  // Memoize particle positions so they don't change on re-render
+  const particles = useMemo(
+    () =>
+      Array.from({ length: 20 }).map((_, i) => ({
+        id: i,
+        left: `${Math.random() * 100}%`,
+        top: `${Math.random() * 100}%`,
+        animationDelay: `${Math.random() * 5}s`,
+        animationDuration: `${3 + Math.random() * 7}s`,
+      })),
+    []
+  );

   // ... rest of component

       {/* Animated particles background */}
       <div className="absolute inset-0 overflow-hidden">
-        {Array.from({ length: 20 }).map((_, i) => (
+        {particles.map((particle) => (
           <div
-            key={i}
+            key={particle.id}
             className="absolute w-1 h-1 bg-primary/20 rounded-full animate-float"
             style={{
-              left: `${Math.random() * 100}%`,
-              top: `${Math.random() * 100}%`,
-              animationDelay: `${Math.random() * 5}s`,
-              animationDuration: `${3 + Math.random() * 7}s`,
+              left: particle.left,
+              top: particle.top,
+              animationDelay: particle.animationDelay,
+              animationDuration: particle.animationDuration,
             }}
           />
         ))}
       </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/extension-wallet/src/components/BalanceCard.tsx` around lines 45 - 56,
The particle positions are regenerated on every render because Math.random() is
called directly inside the Array.from(...).map in the BalanceCard component; fix
by generating and memoizing a stable array of particle position objects (left,
top, animationDelay, animationDuration) once (e.g., in a useMemo or useState
initializer) and map over that memoized array instead of calling Math.random()
in the render, keeping the existing key (index) or use an id field in the
memoized objects for stable keys.

Comment on lines +19 to +21
const [accountAddress] = useState('GABC...123');
const [network] = useState('Testnet');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix clipboard flow: handle failures and wire copied-state feedback.

The copy handler currently assumes success, and the success UI (copied) is never driven from HomeScreen.

✅ Proposed fix
   const [isRefreshing, setIsRefreshing] = useState(false);
   const [accountAddress] = useState('GABC...123');
   const [network] = useState('Testnet');
+  const [copied, setCopied] = useState(false);

-  const handleCopyAddress = () => {
-    navigator.clipboard.writeText('GABC...123');
-    // In a real app, you'd show a toast notification here
-    console.log('Address copied to clipboard');
-  };
+  const handleCopyAddress = async () => {
+    try {
+      await navigator.clipboard.writeText(accountAddress);
+      setCopied(true);
+      setTimeout(() => setCopied(false), 1200);
+    } catch (err) {
+      console.error('Failed to copy address', err);
+    }
+  };

         <AccountHeader
           address={accountAddress}
           network={network}
           onCopyAddress={handleCopyAddress}
+          copied={copied}
         />

Also applies to: 29-33, 67-71

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

In `@apps/extension-wallet/src/screens/HomeScreen.tsx` around lines 19 - 21, The
copy flow assumes success and never updates the copied UI: add a local copied
state via useState (e.g., const [copied, setCopied] = useState(false)),
implement a robust copy handler (e.g., handleCopy) that tries
navigator.clipboard.writeText(accountAddress) with try/catch, falls back to a
document.execCommand('copy') fallback, sets setCopied(true) on success and
setCopied(false) on failure, and resets copied after a short timeout; then wire
the copied state (or setCopied) into the UI where the address/network copy
buttons are rendered (references: accountAddress, network, copied, and the copy
handler locations around the blocks you noted at lines 29-33 and 67-71).

Comment on lines +22 to +27
const handleRefresh = async () => {
setIsRefreshing(true);
await refreshBalance();
// Simulate network delay for better UX
setTimeout(() => setIsRefreshing(false), 800);
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Ensure refresh state always resets on failure.

If refreshBalance() rejects, isRefreshing never resets and the UI can remain in a perpetual refreshing state.

✅ Proposed fix
 const handleRefresh = async () => {
   setIsRefreshing(true);
-  await refreshBalance();
-  // Simulate network delay for better UX
-  setTimeout(() => setIsRefreshing(false), 800);
+  try {
+    await refreshBalance();
+  } finally {
+    // Simulate network delay for better UX
+    setTimeout(() => setIsRefreshing(false), 800);
+  }
 };
📝 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
const handleRefresh = async () => {
setIsRefreshing(true);
await refreshBalance();
// Simulate network delay for better UX
setTimeout(() => setIsRefreshing(false), 800);
};
const handleRefresh = async () => {
setIsRefreshing(true);
try {
await refreshBalance();
} finally {
// Simulate network delay for better UX
setTimeout(() => setIsRefreshing(false), 800);
}
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/extension-wallet/src/screens/HomeScreen.tsx` around lines 22 - 27, The
handleRefresh function can leave isRefreshing true if refreshBalance() rejects;
wrap the await refreshBalance() call in a try/finally (or try/catch/finally) so
that setIsRefreshing(false) is always invoked in the finally block (instead of
only in the setTimeout after a successful await), referencing handleRefresh,
refreshBalance, and setIsRefreshing to locate the change; keep the simulated
delay by calling setTimeout inside the finally before clearing the refreshing
state.

@drips-wave
Copy link
Copy Markdown

drips-wave bot commented Mar 25, 2026

@vrickish Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@wheval
Copy link
Copy Markdown
Contributor

wheval commented Mar 26, 2026

@vrickish please resolve conflicts

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.

Create Home Dashboard Screen

2 participants