From 1d8afdd6cd999086e303394dd03a25bd3a766b15 Mon Sep 17 00:00:00 2001 From: rajanarahul93 Date: Mon, 14 Apr 2025 14:31:50 +0530 Subject: [PATCH 1/3] feat(qrcode): add hover-to-copy functionality #2851 --- package.json | 1 + src/app/components/QRCode/index.tsx | 56 +++++++++++++++++++---- src/app/screens/Accounts/Detail/index.tsx | 3 ++ src/app/screens/Receive/index.tsx | 1 + src/app/screens/ReceiveInvoice/index.tsx | 1 + src/i18n/locales/en/translation.json | 5 +- yarn.lock | 5 ++ 7 files changed, 62 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 275193899e..710dba822d 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "prepare": "husky install" }, "dependencies": { + "@bitcoin-design/bitcoin-icons-react": "^0.1.10", "@bitcoinerlab/secp256k1": "^1.1.1", "@getalby/sdk": "^3.9.0", "@headlessui/react": "^1.7.18", diff --git a/src/app/components/QRCode/index.tsx b/src/app/components/QRCode/index.tsx index ff0447617e..29b2cde068 100644 --- a/src/app/components/QRCode/index.tsx +++ b/src/app/components/QRCode/index.tsx @@ -1,5 +1,8 @@ import ReactQRCode from "react-qr-code"; import { classNames, useTheme } from "~/app/utils"; +import { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { CopyIcon } from "@bitcoin-design/bitcoin-icons-react/filled"; export type Props = { value: string; @@ -15,21 +18,56 @@ export type Props = { // (meaning you have to aim your phone very precisely and have to wait longer for the reader // to recognize the QR code) level?: "Q" | undefined; + onCopy?: () => void; }; -export default function QRCode({ value, size, level, className }: Props) { +export default function QRCode({ + value, + size, + level, + className, + onCopy, +}: Props) { const theme = useTheme(); const fgColor = theme === "dark" ? "#FFFFFF" : "#000000"; const bgColor = theme === "dark" ? "#000000" : "#FFFFFF"; + const { t } = useTranslation("components"); + const [isHovering, setIsHovering] = useState(false); + + const handleCopy = () => { + navigator.clipboard.writeText(value); + onCopy?.(); + }; return ( - +
setIsHovering(true)} + onMouseLeave={() => setIsHovering(false)} + > + + {isHovering && ( +
+
+ + + {t("allowance_menu.qrcode.click_to_copy")} + +
+
+ )} +
); } diff --git a/src/app/screens/Accounts/Detail/index.tsx b/src/app/screens/Accounts/Detail/index.tsx index cdb6c963c4..8574cf6708 100644 --- a/src/app/screens/Accounts/Detail/index.tsx +++ b/src/app/screens/Accounts/Detail/index.tsx @@ -345,6 +345,9 @@ function AccountDetail() { + toast.success("Copied to clipboard") + } />
diff --git a/src/app/screens/Receive/index.tsx b/src/app/screens/Receive/index.tsx index 93d570097c..937b60406f 100644 --- a/src/app/screens/Receive/index.tsx +++ b/src/app/screens/Receive/index.tsx @@ -74,6 +74,7 @@ function Receive() { value={lightningAddress} size={192} level="Q" + onCopy={() => toast.success("Copied to clipboard")} /> )} diff --git a/src/app/screens/ReceiveInvoice/index.tsx b/src/app/screens/ReceiveInvoice/index.tsx index ace65f36d4..a801db202a 100644 --- a/src/app/screens/ReceiveInvoice/index.tsx +++ b/src/app/screens/ReceiveInvoice/index.tsx @@ -148,6 +148,7 @@ function ReceiveInvoice() { toast.success("Copied to clipboard!")} /> {isAlbyOAuthUser ? ( <> diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json index b65e080847..d02126294a 100644 --- a/src/i18n/locales/en/translation.json +++ b/src/i18n/locales/en/translation.json @@ -1216,7 +1216,10 @@ "always_allow": "Always allow", "always_reject": "Always reject" }, - "website_permissions": "Website Permissions" + "website_permissions": "Website Permissions", + "qrcode": { + "click_to_copy": "Click to copy" + } }, "qrcode_scanner": { "title": "Scan QR Code", diff --git a/yarn.lock b/yarn.lock index 957fa2f46a..a59d78c6f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -455,6 +455,11 @@ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@bitcoin-design/bitcoin-icons-react@^0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@bitcoin-design/bitcoin-icons-react/-/bitcoin-icons-react-0.1.10.tgz#11acf1d386c1094d3eff673ca236345860762f64" + integrity sha512-f7GSutKHa4EK4LWI/phnGCJsN8fzFbVAVQ4F1MYxiza34LVmXmbgHUmdP/BR8ZeQSIbZLt19inpJZDBtQvYe4Q== + "@bitcoinerlab/secp256k1@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@bitcoinerlab/secp256k1/-/secp256k1-1.1.1.tgz#938305c30505b67b15f3de53627bc9d8b4cc7680" From 933eb53790040b8596b140efdc778af0d72fe8e9 Mon Sep 17 00:00:00 2001 From: rajanarahul93 Date: Mon, 21 Apr 2025 14:47:11 +0530 Subject: [PATCH 2/3] feat: add QR code component with copy functionality using react-qr-code and @popicons/react --- package.json | 1 - src/app/components/QRCode/index.tsx | 43 +++++++--------------------- src/app/screens/Receive/index.tsx | 1 - src/i18n/locales/en/translation.json | 5 +--- yarn.lock | 5 ---- 5 files changed, 12 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 710dba822d..275193899e 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ "prepare": "husky install" }, "dependencies": { - "@bitcoin-design/bitcoin-icons-react": "^0.1.10", "@bitcoinerlab/secp256k1": "^1.1.1", "@getalby/sdk": "^3.9.0", "@headlessui/react": "^1.7.18", diff --git a/src/app/components/QRCode/index.tsx b/src/app/components/QRCode/index.tsx index 29b2cde068..de9d88fb16 100644 --- a/src/app/components/QRCode/index.tsx +++ b/src/app/components/QRCode/index.tsx @@ -1,8 +1,8 @@ +import { PopiconsCopyLine } from "@popicons/react"; +import { useTranslation } from "react-i18next"; import ReactQRCode from "react-qr-code"; +import toast from "~/app/components/Toast"; import { classNames, useTheme } from "~/app/utils"; -import { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { CopyIcon } from "@bitcoin-design/bitcoin-icons-react/filled"; export type Props = { value: string; @@ -18,56 +18,35 @@ export type Props = { // (meaning you have to aim your phone very precisely and have to wait longer for the reader // to recognize the QR code) level?: "Q" | undefined; - onCopy?: () => void; }; -export default function QRCode({ - value, - size, - level, - className, - onCopy, -}: Props) { +export default function QRCode({ value, size, level, className }: Props) { const theme = useTheme(); const fgColor = theme === "dark" ? "#FFFFFF" : "#000000"; const bgColor = theme === "dark" ? "#000000" : "#FFFFFF"; - const { t } = useTranslation("components"); - const [isHovering, setIsHovering] = useState(false); + const { t } = useTranslation("common"); const handleCopy = () => { navigator.clipboard.writeText(value); - onCopy?.(); + toast.success(t("actions.copied_to_clipboard")); }; return ( -
setIsHovering(true)} - onMouseLeave={() => setIsHovering(false)} - > +
- {isHovering && ( -
-
- - - {t("allowance_menu.qrcode.click_to_copy")} - -
-
- )} +
+ +
); } diff --git a/src/app/screens/Receive/index.tsx b/src/app/screens/Receive/index.tsx index 937b60406f..93d570097c 100644 --- a/src/app/screens/Receive/index.tsx +++ b/src/app/screens/Receive/index.tsx @@ -74,7 +74,6 @@ function Receive() { value={lightningAddress} size={192} level="Q" - onCopy={() => toast.success("Copied to clipboard")} /> )} diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json index d02126294a..b65e080847 100644 --- a/src/i18n/locales/en/translation.json +++ b/src/i18n/locales/en/translation.json @@ -1216,10 +1216,7 @@ "always_allow": "Always allow", "always_reject": "Always reject" }, - "website_permissions": "Website Permissions", - "qrcode": { - "click_to_copy": "Click to copy" - } + "website_permissions": "Website Permissions" }, "qrcode_scanner": { "title": "Scan QR Code", diff --git a/yarn.lock b/yarn.lock index a59d78c6f3..957fa2f46a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -455,11 +455,6 @@ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@bitcoin-design/bitcoin-icons-react@^0.1.10": - version "0.1.10" - resolved "https://registry.yarnpkg.com/@bitcoin-design/bitcoin-icons-react/-/bitcoin-icons-react-0.1.10.tgz#11acf1d386c1094d3eff673ca236345860762f64" - integrity sha512-f7GSutKHa4EK4LWI/phnGCJsN8fzFbVAVQ4F1MYxiza34LVmXmbgHUmdP/BR8ZeQSIbZLt19inpJZDBtQvYe4Q== - "@bitcoinerlab/secp256k1@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@bitcoinerlab/secp256k1/-/secp256k1-1.1.1.tgz#938305c30505b67b15f3de53627bc9d8b4cc7680" From 0a5b51aff42b462b43da63ec460f65db37c71d1c Mon Sep 17 00:00:00 2001 From: rajanarahul93 Date: Mon, 21 Apr 2025 15:11:17 +0530 Subject: [PATCH 3/3] feat(qr-code): add QR code component with copy-to-clipboard functionality --- src/app/screens/Accounts/Detail/index.tsx | 3 --- src/app/screens/ReceiveInvoice/index.tsx | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/app/screens/Accounts/Detail/index.tsx b/src/app/screens/Accounts/Detail/index.tsx index 8574cf6708..cdb6c963c4 100644 --- a/src/app/screens/Accounts/Detail/index.tsx +++ b/src/app/screens/Accounts/Detail/index.tsx @@ -345,9 +345,6 @@ function AccountDetail() { - toast.success("Copied to clipboard") - } />
diff --git a/src/app/screens/ReceiveInvoice/index.tsx b/src/app/screens/ReceiveInvoice/index.tsx index a801db202a..0802836f61 100644 --- a/src/app/screens/ReceiveInvoice/index.tsx +++ b/src/app/screens/ReceiveInvoice/index.tsx @@ -147,8 +147,7 @@ function ReceiveInvoice() {
toast.success("Copied to clipboard!")} + size={192} /> {isAlbyOAuthUser ? ( <>