feat(qrcode): add hover-to-copy functionality #2851#3345
feat(qrcode): add hover-to-copy functionality #2851#3345rajanarahul93 wants to merge 8 commits intogetAlby:masterfrom
Conversation
|
Hi @reneaaron @stackingsaunter |
package.json
Outdated
| "prepare": "husky install" | ||
| }, | ||
| "dependencies": { | ||
| "@bitcoin-design/bitcoin-icons-react": "^0.1.10", |
There was a problem hiding this comment.
why new library for just one icon. we use popicons by default. and i guess copy icon should be there as well PopiconsCopyLine
src/app/components/QRCode/index.tsx
Outdated
| import { classNames, useTheme } from "~/app/utils"; | ||
| import { useState } from "react"; | ||
| import { useTranslation } from "react-i18next"; | ||
| import { CopyIcon } from "@bitcoin-design/bitcoin-icons-react/filled"; |
src/app/screens/Receive/index.tsx
Outdated
| value={lightningAddress} | ||
| size={192} | ||
| level="Q" | ||
| onCopy={() => toast.success("Copied to clipboard")} |
There was a problem hiding this comment.
why this new callback was introduced? just to show success message? can't we do same within the qr code component?
src/i18n/locales/en/translation.json
Outdated
| }, | ||
| "website_permissions": "Website Permissions" | ||
| "website_permissions": "Website Permissions", | ||
| "qrcode": { |
There was a problem hiding this comment.
we already have copy_clipboard and copied_to_clipboard in common section of translations. always check before introducing new ones
src/app/components/QRCode/index.tsx
Outdated
| bgColor={bgColor} | ||
| className={classNames( | ||
| "w-full h-auto rounded-md transition-opacity", | ||
| isHovering ? "opacity-80" : "opacity-100", |
There was a problem hiding this comment.
for hover why we need to use state varbiles? can use tailwind here only?
eg.
className="text-gray-600 hover: text-gray-800"
|
screenshot looks a bit messsy. missing translations broken ui. can you check if other elements are not effected by your ui change and update screenshots? thanks! |
|
Thanks for your review, @pavanjoshi914 .I’ll make the suggested changes and update the PR shortly. |
…de and @popicons/react
| level={level} | ||
| /> | ||
| <div className="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity"> | ||
| <PopiconsCopyLine className="h-8 w-8 text-white drop-shadow-lg" /> |
There was a problem hiding this comment.
where this is used now? i don't see any apperance of this
| <QRCode | ||
| value={invoice.paymentRequest.toUpperCase()} | ||
| size={512} | ||
| size={192} |
|
@stackingsaunter can you please assit him in hover opacity and overlay that should be shown when user hovers the qr code. currently its not that clear visually that we can copy qr code |
|
@pavanjoshi914 , I will make sure the required changes are done!! |
|
I've made the following changes based on your feedback: Re-added the overlay with: <div className="absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity z-20">Reverted the QR code size back to 512: <QRCode value={invoice.paymentRequest.toUpperCase()} size={512} />I tried implementing the copy functionality on the icon but haven't been able to get it working yet. Still exploring possible approaches—if you have any suggestions, I’d love to hear them! The above two changes haven't been pushed yet — I’ll push them together once the copy feature on the logo is working. Let me know if there's anything else you'd like me to check meanwhile. Thanks again for your review! |
|
@pavanjoshi914 any suggestions? |
|
@stackingsaunter any suggestions from you side to solve the issue? |
|
I have submitted a new PR to address this: #3469 I've implemented the click-to-copy interaction with a hover overlay and ensured the entire QR area is clickable by setting pointer-events-none on the center avatar. This version uses the internal toast component and standard translation keys. Ready for review! |
📝 WalkthroughWalkthroughThe changes add click-to-copy functionality to the QR code component with internationalization support and visual feedback via a centered copy icon overlay on hover. A toast notification confirms the clipboard action. The QR code size in the invoice screen is also reduced from 512 to 192. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/app/screens/ReceiveInvoice/index.tsx (1)
154-183:⚠️ Potential issue | 🟠 MajorAvatar overlay blocks click-to-copy on QR code center.
The Avatar (lines 157-162) and logo image (lines 174-182) are positioned absolutely over the QR code center with
z-1, which means they intercept click events. When users click the center of the QR code (where the avatar/logo is), the copy action won't trigger because the click is captured by the overlay element instead of the QRCode component.Add
pointer-events-noneto allow clicks to pass through to the QRCode underneath.🐛 Proposed fix
<Avatar size={64} - className="border-[6px] border-white rounded-full absolute inset-1/2 transform -translate-x-1/2 -translate-y-1/2 z-1 bg-white" + className="border-[6px] border-white rounded-full absolute inset-1/2 transform -translate-x-1/2 -translate-y-1/2 z-1 bg-white pointer-events-none" url={auth.account.avatarUrl} name={auth.account.id} /><img - className="w-[64px] h-[64px] absolute z-1" + className="w-[64px] h-[64px] absolute z-1 pointer-events-none" src={ theme === "dark"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/app/screens/ReceiveInvoice/index.tsx` around lines 154 - 183, The Avatar overlay and fallback img/SkeletonLoader are intercepting clicks on the QRCode; update the elements rendering the overlay (Avatar component, SkeletonLoader when rendered, and the fallback img) to include the pointer-events-none utility in their className so clicks pass through to the underlying QRCode component (modify the className on Avatar, SkeletonLoader, and the img to add "pointer-events-none").
🧹 Nitpick comments (1)
src/app/components/QRCode/index.tsx (1)
35-35: Consider adding keyboard accessibility.The clickable div lacks keyboard support. Users navigating with keyboards cannot trigger the copy action.
♿ Proposed enhancement
- <div className="relative cursor-pointer group" onClick={handleCopy}> + <div + className="relative cursor-pointer group" + onClick={handleCopy} + onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') handleCopy(); }} + role="button" + tabIndex={0} + aria-label={t("actions.copy_to_clipboard")} + >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/app/components/QRCode/index.tsx` at line 35, The clickable div with className "relative cursor-pointer group" in the QRCode component lacks keyboard accessibility; update it to behave like a button by adding role="button", tabIndex={0}, and an onKeyDown handler that calls the existing handleCopy when Enter or Space is pressed (ensure Space uses event.preventDefault() to avoid page scroll), and add an appropriate aria-label or aria-labelledby so screen readers convey the action.
🤖 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/app/components/QRCode/index.tsx`:
- Around line 29-32: The handleCopy function currently calls
navigator.clipboard.writeText(value) without awaiting or handling rejection;
change it to an async flow (or attach .then/.catch) around
navigator.clipboard.writeText in src/app/components/QRCode/index.tsx so failures
are caught and handled, and on success still call
toast.success(t("actions.copied_to_clipboard")), while on error call
toast.error(t("actions.copy_failed")) (or another translation key) and
optionally log the error; update the handleCopy implementation and ensure you
reference navigator.clipboard.writeText, handleCopy, toast.success/toast.error,
and t(...) in the fix.
- Around line 47-49: The copy icon is invisible on light backgrounds; update the
icon container (the div wrapping PopiconsCopyLine in the QRCode component) to
add a semi-transparent circular background and make the icon theme-aware—e.g.
add classes like "rounded-full p-1 bg-black/50 dark:bg-white/50" to the
container and change the icon class from "text-white" to a theme-aware class
such as "text-white dark:text-black" (or equivalent tailwind dark/light
variants) so the icon remains visible on both light and dark QR backgrounds.
---
Outside diff comments:
In `@src/app/screens/ReceiveInvoice/index.tsx`:
- Around line 154-183: The Avatar overlay and fallback img/SkeletonLoader are
intercepting clicks on the QRCode; update the elements rendering the overlay
(Avatar component, SkeletonLoader when rendered, and the fallback img) to
include the pointer-events-none utility in their className so clicks pass
through to the underlying QRCode component (modify the className on Avatar,
SkeletonLoader, and the img to add "pointer-events-none").
---
Nitpick comments:
In `@src/app/components/QRCode/index.tsx`:
- Line 35: The clickable div with className "relative cursor-pointer group" in
the QRCode component lacks keyboard accessibility; update it to behave like a
button by adding role="button", tabIndex={0}, and an onKeyDown handler that
calls the existing handleCopy when Enter or Space is pressed (ensure Space uses
event.preventDefault() to avoid page scroll), and add an appropriate aria-label
or aria-labelledby so screen readers convey the action.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7f02be6e-77b9-4154-9f02-abfe80c1d505
📒 Files selected for processing (2)
src/app/components/QRCode/index.tsxsrc/app/screens/ReceiveInvoice/index.tsx
| const handleCopy = () => { | ||
| navigator.clipboard.writeText(value); | ||
| toast.success(t("actions.copied_to_clipboard")); | ||
| }; |
There was a problem hiding this comment.
Add error handling for clipboard API.
navigator.clipboard.writeText() returns a Promise that can reject (e.g., clipboard permission denied, insecure context). The current implementation ignores errors, which could result in silent failures with no user feedback.
🛡️ Proposed fix
const handleCopy = () => {
- navigator.clipboard.writeText(value);
- toast.success(t("actions.copied_to_clipboard"));
+ navigator.clipboard.writeText(value)
+ .then(() => {
+ toast.success(t("actions.copied_to_clipboard"));
+ })
+ .catch((err) => {
+ console.error("Failed to copy:", err);
+ toast.error(t("actions.copy_failed"));
+ });
};Alternatively, using async/await:
- const handleCopy = () => {
- navigator.clipboard.writeText(value);
- toast.success(t("actions.copied_to_clipboard"));
+ const handleCopy = async () => {
+ try {
+ await navigator.clipboard.writeText(value);
+ toast.success(t("actions.copied_to_clipboard"));
+ } catch (err) {
+ if (err instanceof Error) {
+ toast.error(err.message);
+ }
+ }
};Note: You may need to add a translation key for the error case (e.g., actions.copy_failed).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/app/components/QRCode/index.tsx` around lines 29 - 32, The handleCopy
function currently calls navigator.clipboard.writeText(value) without awaiting
or handling rejection; change it to an async flow (or attach .then/.catch)
around navigator.clipboard.writeText in src/app/components/QRCode/index.tsx so
failures are caught and handled, and on success still call
toast.success(t("actions.copied_to_clipboard")), while on error call
toast.error(t("actions.copy_failed")) (or another translation key) and
optionally log the error; update the handleCopy implementation and ensure you
reference navigator.clipboard.writeText, handleCopy, toast.success/toast.error,
and t(...) in the fix.
| <div className="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity"> | ||
| <PopiconsCopyLine className="h-8 w-8 text-white drop-shadow-lg" /> | ||
| </div> |
There was a problem hiding this comment.
Copy icon is invisible on light theme.
The copy icon uses text-white which won't be visible against the white QR code background (bgColor is #FFFFFF on light theme). Even with the QR opacity reduced to 80% on hover, a white icon on a near-white background lacks sufficient contrast.
Consider using a theme-aware color or adding a semi-transparent background behind the icon.
🎨 Proposed fix - add background to icon container
<div className="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
- <PopiconsCopyLine className="h-8 w-8 text-white drop-shadow-lg" />
+ <div className="bg-black/50 dark:bg-white/50 rounded-full p-2">
+ <PopiconsCopyLine className="h-8 w-8 text-white dark:text-black drop-shadow-lg" />
+ </div>
</div>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/app/components/QRCode/index.tsx` around lines 47 - 49, The copy icon is
invisible on light backgrounds; update the icon container (the div wrapping
PopiconsCopyLine in the QRCode component) to add a semi-transparent circular
background and make the icon theme-aware—e.g. add classes like "rounded-full p-1
bg-black/50 dark:bg-white/50" to the container and change the icon class from
"text-white" to a theme-aware class such as "text-white dark:text-black" (or
equivalent tailwind dark/light variants) so the icon remains visible on both
light and dark QR backgrounds.



Describe the changes you have made in this PR
Added a hover-to-copy interaction on the QRCode component. When the user hovers over the QR code, a semi-transparent overlay appears with a copy icon and text prompting the user to click. On click, the QR code content is copied to the clipboard. This enhances UX by making the copy functionality more discoverable and user-friendly.
Link this PR to an issue
Fixes #2851
Type of change
feat: New feature (non-breaking change which adds functionality)Screenshots of the changes [optional]
How has this been tested?
Checklist
Summary by CodeRabbit
New Features
Style