(({ asset, accoun
return (
<>
-
-
- {accountLabel}
-
-
+
+
+
+ {accountLabel}
+
+
+
|
{isLoading ? (
diff --git a/src/hooks/useCopyToClipboard.tsx b/src/hooks/useCopyToClipboard.tsx
new file mode 100644
index 00000000000..53806afcb15
--- /dev/null
+++ b/src/hooks/useCopyToClipboard.tsx
@@ -0,0 +1,36 @@
+import { useState } from 'react'
+
+export interface useCopyToClipboardProps {
+ timeout?: number
+}
+
+export function useCopyToClipboard({ timeout = 2000 }: useCopyToClipboardProps) {
+ const [isCopied, setIsCopied] = useState(false)
+ const [isCopying, setIsCopying] = useState(false)
+
+ const copyToClipboard = (value: string) => {
+ if (typeof window === 'undefined' || !navigator.clipboard?.writeText) {
+ return
+ }
+
+ if (!value) {
+ return
+ }
+
+ // Prevent race condition if the user clicks copy multiple times
+ if (isCopying) return
+ setIsCopying(true)
+
+ void navigator.clipboard.writeText(value).then(() => {
+ setIsCopied(true)
+
+ setTimeout(() => {
+ // Reset the state after the timeout
+ setIsCopying(false)
+ setIsCopied(false)
+ }, timeout)
+ })
+ }
+
+ return { isCopied, copyToClipboard }
+}
diff --git a/src/pages/Accounts/components/AccountNumberRow.tsx b/src/pages/Accounts/components/AccountNumberRow.tsx
index fad7fbe7d04..12bc56af5c6 100644
--- a/src/pages/Accounts/components/AccountNumberRow.tsx
+++ b/src/pages/Accounts/components/AccountNumberRow.tsx
@@ -1,4 +1,4 @@
-import { ArrowDownIcon, ArrowUpIcon } from '@chakra-ui/icons'
+import { ArrowDownIcon, ArrowUpIcon, CheckIcon, CopyIcon } from '@chakra-ui/icons'
import type { ButtonProps } from '@chakra-ui/react'
import {
Avatar,
@@ -15,8 +15,8 @@ import {
Stack,
useDisclosure,
} from '@chakra-ui/react'
-import type { AccountId, ChainId } from '@shapeshiftoss/caip'
-import { useMemo } from 'react'
+import { type AccountId, type ChainId, fromAccountId } from '@shapeshiftoss/caip'
+import { useCallback, useMemo } from 'react'
import { MdOutlineMoreVert } from 'react-icons/md'
import { RiWindow2Line } from 'react-icons/ri'
import { useTranslate } from 'react-polyglot'
@@ -24,6 +24,7 @@ import { useSelector } from 'react-redux'
import { Amount } from 'components/Amount/Amount'
import { NestedList } from 'components/NestedList'
import { RawText } from 'components/Text'
+import { useCopyToClipboard } from 'hooks/useCopyToClipboard'
import { getAccountTitle } from 'lib/utils/accounts'
import { isUtxoAccountId, isUtxoChainId } from 'lib/utils/utxo'
import {
@@ -51,6 +52,8 @@ const mdOutlineMoreVertIcon =
const riWindow2LineIcon =
const arrowDownIcon =
const arrowUpIcon =
+const copyIcon =
+const checkIcon =
const UtxoAccountEntries: React.FC = ({ accountIds, chainId }) => {
const feeAsset = useAppSelector(s => selectFeeAssetByChainId(s, chainId))
@@ -108,6 +111,7 @@ export const AccountNumberRow: React.FC = ({
...buttonProps
}) => {
const { isOpen, onToggle } = useDisclosure()
+ const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 })
const translate = useTranslate()
const assets = useSelector(selectAssets)
const accountId = useMemo(() => accountIds[0], [accountIds]) // all accountIds belong to the same chain
@@ -148,6 +152,11 @@ export const AccountNumberRow: React.FC = ({
const fontFamily = useMemo(() => (!isUtxoChainId(chainId) ? 'monospace' : ''), [chainId])
+ const handleCopyClick = useCallback(() => {
+ const account = fromAccountId(accountId).account
+ copyToClipboard(account)
+ }, [accountId, copyToClipboard])
+
return (
@@ -198,6 +207,9 @@ export const AccountNumberRow: React.FC = ({
+
|