Skip to content

add copy wallet address functionality with feedback#95

Open
Salman8311 wants to merge 4 commits intoStabilityNexus:mainfrom
Salman8311:feature/copy-wallet-address
Open

add copy wallet address functionality with feedback#95
Salman8311 wants to merge 4 commits intoStabilityNexus:mainfrom
Salman8311:feature/copy-wallet-address

Conversation

@Salman8311
Copy link
Copy Markdown

@Salman8311 Salman8311 commented Mar 29, 2026

🚀 Add Copy Wallet Address Feature

📌 Description

This PR adds a copy-to-clipboard feature for the wallet address to improve user experience.

✅ Changes Made

  • Replaced default RainbowKit button with custom implementation
  • Added "Copy" button next to wallet address
  • Implemented clipboard functionality using navigator.clipboard
  • Added "Copied!" feedback for better UX

🎯 Result

Users can now easily copy their wallet address with a single click.

🧪 Testing

  • Tested locally after connecting wallet
  • Verified copy functionality works correctly
  • Confirmed UI updates after clicking copy

🤖 AI Usage Disclosure

This PR was created with assistance from AI tools.
All code has been reviewed and tested by me.

Summary by CodeRabbit

  • New Features

    • Navigation links now highlight based on your current page for better orientation
    • One-click copy functionality for wallet address with "Copied!" confirmation message
  • Improvements

    • Enhanced wallet button UI with clearer connection states and chain selection
    • Updated navigation spacing and styling for improved visual clarity

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 29, 2026

Walkthrough

Navigation links now dynamically style based on the current route using usePathname, while wallet connection UI is enhanced with custom state management and a clipboard copy function that provides transient user feedback.

Changes

Cohort / File(s) Summary
Navigation Active Link Styling
src/components/layout/Navbar.tsx
Imported usePathname to compute current pathname; added isActive() helper to determine active link styling; updated desktop navigation links to conditionally apply class names based on active state, replacing static hover-only styles; adjusted container spacing and link styling patterns.
Wallet Connection UI Enhancement
src/components/ui/walletButton.tsx
Replaced simple ConnectButton with custom ConnectButton.Custom implementation; added copied state and async handleCopy() function for clipboard operations; implemented conditional rendering based on wallet connection state with "Copy" button that displays transient "Copied!" feedback for 1500ms; added error logging for clipboard failures.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Suggested labels

Typescript Lang

Poem

🐰 Hoppity hop, the nav knows where,
Active links styled with care,
Wallet address, copied in a click—
Clipboard magic, fast and slick!
Two improvements, shiny and bright,
User experience feels just right!

🚥 Pre-merge checks | ✅ 2
✅ 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 'add copy wallet address functionality with feedback' directly and clearly summarizes the main change in the PR—adding copy-to-clipboard functionality with UI feedback in the wallet button.

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

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

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
Copy Markdown
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: 5

🤖 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/components/layout/Navbar.tsx`:
- Around line 59-101: Replace the hardcoded nav labels in the Navbar component
with translation keys: remove literal strings "Explore", "Create", "Portfolio"
and use your i18n hook/utility (e.g., useTranslations/useTranslation) to render
t('nav.explore'), t('nav.create'), t('nav.portfolio'); add those keys to the
locale resource files and import the translation hook at the top of Navbar.tsx,
keeping the existing Link elements and isActive(...) logic intact; while
editing, normalize JSX indentation in the <nav> and child <Link> blocks for
consistent formatting.

In `@src/components/ui/walletButton.tsx`:
- Line 45: The hardcoded user-visible string "Connect Wallet" in the
WalletButton component (src/components/ui/walletButton.tsx) must be externalized
for i18n: replace the literal with a lookup from your localization/resource
system (e.g., use t('wallet.connect') or messages.connectWallet) and add the key
"wallet.connect" (or agreed key) to the resource files for all supported
locales; update imports in walletButton.tsx to include the i18n helper (e.g.,
useTranslation or messages import) and ensure the component uses that translated
value instead of the hardcoded string.
- Around line 72-74: The title attribute and hardcoded button labels in
WalletButton need i18n: replace the literal title="Copy wallet address" and the
labels 'Copy'/'Copied!' with calls to your localization function (e.g.,
t('wallet.copy') / t('wallet.copied')) and load the translation hook where
WalletButton is defined (or import the i18n helper) so the UI uses resource keys
instead of hardcoded strings; update translation resources with keys for
wallet.copy and wallet.copied and use the component's copied state to choose the
appropriate localized string.
- Around line 52-76: Extract the duplicated className string used by the chain
and account buttons into a shared constant (e.g., BUTTON_BASE_CLASS) at the top
of the WalletButton component file and replace the inline className for the
buttons that call openChainModal and openAccountModal with that constant; ensure
the copy button remains unchanged or optionally reuse the constant with
additional classes if desired, and keep existing handlers (openChainModal,
openAccountModal, handleCopy) and render values (chain.name,
account.displayName, account.address, copied) intact.
- Around line 9-22: The handleCopy function uses setTimeout to reset setCopied
but never clears the timer on unmount, risking state updates on an unmounted
component; change handleCopy to store the timeout id (e.g., in a ref like
copyTimeoutRef) and clearTimeout(copyTimeoutRef.current) in a useEffect cleanup
that runs on unmount, and ensure you set copyTimeoutRef.current = undefined
after clearing; also surface clipboard failures to the user instead of only
console.error by setting an error state or calling the existing UI
notification/toast (e.g., setCopyError or showToast) inside the catch block so
users receive feedback when navigator.clipboard.writeText fails.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: edbb8c72-e11f-4362-bf67-0fb6540569c5

📥 Commits

Reviewing files that changed from the base of the PR and between fbd27aa and 4a22779.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • src/components/layout/Navbar.tsx
  • src/components/ui/walletButton.tsx

Comment on lines +59 to +101
<nav
className={cn(
"hidden min-[900px]:flex absolute left-1/2 transform -translate-x-1/2 space-x-2 text-md text-center px-3 py-2 rounded-full",
"bg-[#f0f1f4] dark:bg-[#1a1b1f] text-gray-900 dark:text-white backdrop-blur-sm",
"font-[var(--font-bebas-nueue)]"
)}
>
<Link
href="/explorePools"
className={cn(
"px-4 py-1 rounded-full transition-all",
isActive("/explorePools")
? "bg-black text-white dark:bg-white dark:text-black"
: "text-gray-900 dark:text-white hover:text-yellow-500"
)}
>
Explore
</Link>

<Link
href="/createPool"
className={cn(
"px-4 py-1 rounded-full transition-all",
isActive("/createPool")
? "bg-black text-white dark:bg-white dark:text-black"
: "text-gray-900 dark:text-white hover:text-yellow-500"
)}
>
Create
</Link>

<Link
href="/portfolio"
className={cn(
"px-4 py-1 rounded-full transition-all",
isActive("/portfolio")
? "bg-black text-white dark:bg-white dark:text-black"
: "text-gray-900 dark:text-white hover:text-yellow-500"
)}
>
Portfolio
</Link>
</nav>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Externalize user-visible strings for i18n.

The navigation labels "Explore", "Create", and "Portfolio" are hardcoded. Per coding guidelines, user-visible strings should be externalized to resource files for internationalization.

♻️ Example refactor using i18n
- >
-   Explore
- </Link>
+ >
+   {t('nav.explore')}
+ </Link>

Consider using a library like next-intl or react-i18next to manage translations.


Minor: Inconsistent indentation in JSX.

The <nav> block and its child <Link> elements have inconsistent indentation (mix of leading spaces). While this doesn't affect functionality, it impacts readability.

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

In `@src/components/layout/Navbar.tsx` around lines 59 - 101, Replace the
hardcoded nav labels in the Navbar component with translation keys: remove
literal strings "Explore", "Create", "Portfolio" and use your i18n hook/utility
(e.g., useTranslations/useTranslation) to render t('nav.explore'),
t('nav.create'), t('nav.portfolio'); add those keys to the locale resource files
and import the translation hook at the top of Navbar.tsx, keeping the existing
Link elements and isActive(...) logic intact; while editing, normalize JSX
indentation in the <nav> and child <Link> blocks for consistent formatting.

Comment on lines +9 to +22
const handleCopy = async (address?: string) => {
if (!address) return;

try {
await navigator.clipboard.writeText(address);
setCopied(true);

setTimeout(() => {
setCopied(false);
}, 1500);
} catch (error) {
console.error('Failed to copy wallet address:', error);
}
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential memory leak: setTimeout not cleaned up on unmount.

If the component unmounts before the 1500ms timeout completes, setCopied will be called on an unmounted component. Consider using a ref to track mount state or converting to useEffect for cleanup.

Additionally, on clipboard failure, only console.error is called—users receive no feedback that the copy failed.

🛠️ Proposed fix using a mounted ref
+import { useState, useRef, useEffect } from 'react';
-import { useState } from 'react';
 import { ConnectButton } from '@rainbow-me/rainbowkit';
 
 export default function WalletButton() {
   const [copied, setCopied] = useState(false);
+  const mountedRef = useRef(true);
+
+  useEffect(() => {
+    return () => {
+      mountedRef.current = false;
+    };
+  }, []);
 
   const handleCopy = async (address?: string) => {
     if (!address) return;
 
     try {
       await navigator.clipboard.writeText(address);
       setCopied(true);
 
       setTimeout(() => {
-        setCopied(false);
+        if (mountedRef.current) {
+          setCopied(false);
+        }
       }, 1500);
     } catch (error) {
       console.error('Failed to copy wallet address:', error);
+      // Optionally provide user feedback on failure
     }
   };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ui/walletButton.tsx` around lines 9 - 22, The handleCopy
function uses setTimeout to reset setCopied but never clears the timer on
unmount, risking state updates on an unmounted component; change handleCopy to
store the timeout id (e.g., in a ref like copyTimeoutRef) and
clearTimeout(copyTimeoutRef.current) in a useEffect cleanup that runs on
unmount, and ensure you set copyTimeoutRef.current = undefined after clearing;
also surface clipboard failures to the user instead of only console.error by
setting an error state or calling the existing UI notification/toast (e.g.,
setCopyError or showToast) inside the catch block so users receive feedback when
navigator.clipboard.writeText fails.

type="button"
className="px-4 py-2 rounded-full bg-black text-white dark:bg-white dark:text-black hover:opacity-80 transition"
>
Connect Wallet
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Hardcoded user-visible string violates i18n guidelines.

"Connect Wallet" should be externalized to a resource file for internationalization support.

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

In `@src/components/ui/walletButton.tsx` at line 45, The hardcoded user-visible
string "Connect Wallet" in the WalletButton component
(src/components/ui/walletButton.tsx) must be externalized for i18n: replace the
literal with a lookup from your localization/resource system (e.g., use
t('wallet.connect') or messages.connectWallet) and add the key "wallet.connect"
(or agreed key) to the resource files for all supported locales; update imports
in walletButton.tsx to include the i18n helper (e.g., useTranslation or messages
import) and ensure the component uses that translated value instead of the
hardcoded string.

Comment on lines +52 to +76
<button
onClick={openChainModal}
type="button"
className="px-3 py-1 rounded-full bg-[#f0f1f4] dark:bg-[#1a1b1f] text-gray-900 dark:text-white border border-gray-300 dark:border-gray-700 hover:bg-gray-200 dark:hover:bg-[#2a2b30] transition"
>
{chain.name}
</button>

<button
onClick={openAccountModal}
type="button"
className="px-3 py-1 rounded-full bg-[#f0f1f4] dark:bg-[#1a1b1f] text-gray-900 dark:text-white border border-gray-300 dark:border-gray-700 hover:bg-gray-200 dark:hover:bg-[#2a2b30] transition"
>
{account.displayName}
</button>

<button
onClick={() => handleCopy(account.address)}
type="button"
className="px-3 py-1 rounded-full bg-black text-white dark:bg-white dark:text-black hover:opacity-80 transition"
title="Copy wallet address"
>
{copied ? 'Copied!' : 'Copy'}
</button>
</div>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider extracting repeated button styles.

The chain and account buttons share nearly identical className strings. Extracting to a shared constant or utility improves maintainability and reduces duplication.

♻️ Optional refactor
+const secondaryButtonClass =
+  "px-3 py-1 rounded-full bg-[`#f0f1f4`] dark:bg-[`#1a1b1f`] text-gray-900 dark:text-white border border-gray-300 dark:border-gray-700 hover:bg-gray-200 dark:hover:bg-[`#2a2b30`] transition";
+
 return (
   <div className="flex items-center gap-2">
     <button
       onClick={openChainModal}
       type="button"
-      className="px-3 py-1 rounded-full bg-[`#f0f1f4`] dark:bg-[`#1a1b1f`] text-gray-900 dark:text-white border border-gray-300 dark:border-gray-700 hover:bg-gray-200 dark:hover:bg-[`#2a2b30`] transition"
+      className={secondaryButtonClass}
     >
       {chain.name}
     </button>

     <button
       onClick={openAccountModal}
       type="button"
-      className="px-3 py-1 rounded-full bg-[`#f0f1f4`] dark:bg-[`#1a1b1f`] text-gray-900 dark:text-white border border-gray-300 dark:border-gray-700 hover:bg-gray-200 dark:hover:bg-[`#2a2b30`] transition"
+      className={secondaryButtonClass}
     >
📝 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
<button
onClick={openChainModal}
type="button"
className="px-3 py-1 rounded-full bg-[#f0f1f4] dark:bg-[#1a1b1f] text-gray-900 dark:text-white border border-gray-300 dark:border-gray-700 hover:bg-gray-200 dark:hover:bg-[#2a2b30] transition"
>
{chain.name}
</button>
<button
onClick={openAccountModal}
type="button"
className="px-3 py-1 rounded-full bg-[#f0f1f4] dark:bg-[#1a1b1f] text-gray-900 dark:text-white border border-gray-300 dark:border-gray-700 hover:bg-gray-200 dark:hover:bg-[#2a2b30] transition"
>
{account.displayName}
</button>
<button
onClick={() => handleCopy(account.address)}
type="button"
className="px-3 py-1 rounded-full bg-black text-white dark:bg-white dark:text-black hover:opacity-80 transition"
title="Copy wallet address"
>
{copied ? 'Copied!' : 'Copy'}
</button>
</div>
const secondaryButtonClass =
"px-3 py-1 rounded-full bg-[`#f0f1f4`] dark:bg-[`#1a1b1f`] text-gray-900 dark:text-white border border-gray-300 dark:border-gray-700 hover:bg-gray-200 dark:hover:bg-[`#2a2b30`] transition";
<button
onClick={openChainModal}
type="button"
className={secondaryButtonClass}
>
{chain.name}
</button>
<button
onClick={openAccountModal}
type="button"
className={secondaryButtonClass}
>
{account.displayName}
</button>
<button
onClick={() => handleCopy(account.address)}
type="button"
className="px-3 py-1 rounded-full bg-black text-white dark:bg-white dark:text-black hover:opacity-80 transition"
title="Copy wallet address"
>
{copied ? 'Copied!' : 'Copy'}
</button>
</div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ui/walletButton.tsx` around lines 52 - 76, Extract the
duplicated className string used by the chain and account buttons into a shared
constant (e.g., BUTTON_BASE_CLASS) at the top of the WalletButton component file
and replace the inline className for the buttons that call openChainModal and
openAccountModal with that constant; ensure the copy button remains unchanged or
optionally reuse the constant with additional classes if desired, and keep
existing handlers (openChainModal, openAccountModal, handleCopy) and render
values (chain.name, account.displayName, account.address, copied) intact.

Comment on lines +72 to +74
title="Copy wallet address"
>
{copied ? 'Copied!' : 'Copy'}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Additional hardcoded strings need i18n externalization.

The title attribute and button labels ("Copy", "Copied!") should also be externalized for internationalization. As per coding guidelines: "User-visible strings should be externalized to resource files (i18n)".

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

In `@src/components/ui/walletButton.tsx` around lines 72 - 74, The title attribute
and hardcoded button labels in WalletButton need i18n: replace the literal
title="Copy wallet address" and the labels 'Copy'/'Copied!' with calls to your
localization function (e.g., t('wallet.copy') / t('wallet.copied')) and load the
translation hook where WalletButton is defined (or import the i18n helper) so
the UI uses resource keys instead of hardcoded strings; update translation
resources with keys for wallet.copy and wallet.copied and use the component's
copied state to choose the appropriate localized string.

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.

1 participant