Skip to content

Commit

Permalink
Feat: copy addresses on click
Browse files Browse the repository at this point in the history
  • Loading branch information
katspaugh committed Nov 21, 2023
1 parent 09a88f6 commit 9e05eed
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 52 deletions.
7 changes: 4 additions & 3 deletions src/components/common/CopyAddressButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { type ReactElement } from 'react'

import type { ReactNode, ReactElement } from 'react'
import CopyButton from '../CopyButton'

const CopyAddressButton = ({
prefix,
address,
copyPrefix,
children,
}: {
prefix?: string
address: string
copyPrefix?: boolean
children?: ReactNode
}): ReactElement => {
const addressText = copyPrefix && prefix ? `${prefix}:${address}` : address

return <CopyButton text={addressText} />
return <CopyButton text={addressText}>{children}</CopyButton>
}

export default CopyAddressButton
49 changes: 10 additions & 39 deletions src/components/common/CopyButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { ReactNode } from 'react'
import React, { type ReactElement, type SyntheticEvent, useCallback, useState } from 'react'
import React, { type ReactElement } from 'react'
import CopyIcon from '@/public/images/common/copy.svg'
import { IconButton, SvgIcon, Tooltip } from '@mui/material'
import { IconButton, SvgIcon } from '@mui/material'
import CopyTooltip from '../CopyTooltip'

const CopyButton = ({
text,
Expand All @@ -17,44 +18,14 @@ const CopyButton = ({
ariaLabel?: string
onCopy?: () => void
}): ReactElement => {
const [tooltipText, setTooltipText] = useState(initialToolTipText)
const [isCopyEnabled, setIsCopyEnabled] = useState(true)

const handleCopy = useCallback(
(e: SyntheticEvent) => {
e.preventDefault()
e.stopPropagation()
try {
navigator.clipboard.writeText(text).then(() => setTooltipText('Copied'))
onCopy?.()
} catch (err) {
setIsCopyEnabled(false)
setTooltipText('Copying is disabled in your browser')
}
},
[text, onCopy],
)

const handleMouseLeave = useCallback(() => {
setTimeout(() => {
if (isCopyEnabled) {
setTooltipText(initialToolTipText)
}
}, 500)
}, [initialToolTipText, isCopyEnabled])

return (
<Tooltip title={tooltipText} placement="top" onMouseLeave={handleMouseLeave}>
<IconButton
aria-label={initialToolTipText}
onClick={handleCopy}
size="small"
className={className}
disabled={!isCopyEnabled}
>
{children ?? <SvgIcon component={CopyIcon} inheritViewBox color="border" fontSize="small" />}
</IconButton>
</Tooltip>
<CopyTooltip text={text} onCopy={onCopy} initialToolTipText={initialToolTipText}>
{children ?? (
<IconButton aria-label={initialToolTipText} size="small" className={className}>
<SvgIcon component={CopyIcon} inheritViewBox color="border" fontSize="small" />
</IconButton>
)}
</CopyTooltip>
)
}

Expand Down
53 changes: 53 additions & 0 deletions src/components/common/CopyTooltip/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type { ReactNode } from 'react'
import React, { type ReactElement, type SyntheticEvent, useCallback, useState } from 'react'
import { Tooltip } from '@mui/material'

const cursorPointer = { cursor: 'pointer' }

const CopyTooltip = ({
text,
children,
initialToolTipText = 'Copy to clipboard',
onCopy,
}: {
text: string
children?: ReactNode
initialToolTipText?: string
onCopy?: () => void
}): ReactElement => {
const [tooltipText, setTooltipText] = useState(initialToolTipText)
const [isCopyEnabled, setIsCopyEnabled] = useState(true)

const handleCopy = useCallback(
(e: SyntheticEvent) => {
e.preventDefault()
e.stopPropagation()
try {
navigator.clipboard.writeText(text).then(() => setTooltipText('Copied'))
onCopy?.()
} catch (err) {
setIsCopyEnabled(false)
setTooltipText('Copying is disabled in your browser')
}
},
[text, onCopy],
)

const handleMouseLeave = useCallback(() => {
setTimeout(() => {
if (isCopyEnabled) {
setTooltipText(initialToolTipText)
}
}, 500)
}, [initialToolTipText, isCopyEnabled])

return (
<Tooltip title={tooltipText} placement="top" onMouseLeave={handleMouseLeave}>
<span onClick={handleCopy} style={cursorPointer}>
{children}
</span>
</Tooltip>
)
}

export default CopyTooltip
12 changes: 6 additions & 6 deletions src/components/common/EthHashInfo/SrcEthHashInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ const SrcEthHashInfo = ({
const shouldPrefix = isAddress(address)
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down('sm'))

const identicon = <Identicon address={address} size={avatarSize} />
const shouldCopyPrefix = shouldPrefix && copyPrefix

return (
<div className={css.container}>
Expand All @@ -78,13 +78,13 @@ const SrcEthHashInfo = ({

<div className={css.addressContainer}>
<Box fontWeight="inherit" fontSize="inherit">
{showPrefix && shouldPrefix && prefix && <b>{prefix}:</b>}
<span>{shortAddress || isMobile ? shortenAddress(address) : address}</span>
<CopyAddressButton prefix={prefix} address={address} copyPrefix={shouldCopyPrefix}>
{showPrefix && shouldPrefix && prefix && <b>{prefix}:</b>}
<span>{shortAddress || isMobile ? shortenAddress(address) : address}</span>
</CopyAddressButton>
</Box>

{showCopyButton && (
<CopyAddressButton prefix={prefix} address={address} copyPrefix={shouldPrefix && copyPrefix} />
)}
{showCopyButton && <CopyAddressButton prefix={prefix} address={address} copyPrefix={shouldCopyPrefix} />}

{hasExplorer && ExplorerButtonProps && (
<Box color="border.main">
Expand Down
10 changes: 6 additions & 4 deletions src/components/sidebar/SidebarHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { selectSettings } from '@/store/settingsSlice'
import { useCurrentChain } from '@/hooks/useChains'
import { getBlockExplorerLink } from '@/utils/chains'
import EthHashInfo from '@/components/common/EthHashInfo'
import CopyButton from '@/components/common/CopyButton'
import QrCodeButton from '../QrCodeButton'
import Track from '@/components/common/Track'
import { OVERVIEW_EVENTS } from '@/services/analytics/events/overview'
Expand All @@ -29,6 +28,7 @@ import { useVisibleBalances } from '@/hooks/useVisibleBalances'
import EnvHintButton from '@/components/settings/EnvironmentVariables/EnvHintButton'
import useSafeAddress from '@/hooks/useSafeAddress'
import ExplorerButton from '@/components/common/ExplorerButton'
import CopyTooltip from '@/components/common/CopyTooltip'

const SafeHeader = (): ReactElement => {
const currency = useAppSelector(selectCurrency)
Expand Down Expand Up @@ -88,9 +88,11 @@ const SafeHeader = (): ReactElement => {
</Track>

<Track {...OVERVIEW_EVENTS.COPY_ADDRESS}>
<CopyButton text={addressCopyText} className={css.iconButton}>
<SvgIcon component={CopyIconBold} inheritViewBox color="primary" fontSize="small" />
</CopyButton>
<CopyTooltip text={addressCopyText}>
<IconButton className={css.iconButton}>
<SvgIcon component={CopyIconBold} inheritViewBox color="primary" fontSize="small" />
</IconButton>
</CopyTooltip>
</Track>

<Track {...OVERVIEW_EVENTS.OPEN_EXPLORER}>
Expand Down

0 comments on commit 9e05eed

Please sign in to comment.