Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion public/locales/en/address.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"view": "View",
"noProfile": {
"title": "No primary name set",
"message": "This wallet needs to set a primary name to create a profile"
"message": "This wallet needs to set a primary name to create a profile. Only normalized names are shown."
},
"noResults": "No names found",
"errors": {
Expand Down
2 changes: 1 addition & 1 deletion public/locales/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
},
"primary": {
"title": "Primary Name",
"noNameDescription": "A primary name links your address to a name, allowing dApps to display a name as your profile when connected to them. Learn about primary names",
"noNameDescription": "A primary name links your address to a name, allowing dApps to display a name as your profile when connected to them. Only normalized names are shown. <primaryNameLink>Learn about primary names</primaryNameLink>",
"choosePrimaryName": "Choose primary name",
"inheritedFromDefault": "Inherited from default",
"networkSpecificPrimaryNames": {
Expand Down
46 changes: 21 additions & 25 deletions src/__tests__/pages/address.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,13 @@ vi.mock('next/head', () => ({
// Mock hooks
vi.mock('@app/hooks/usePrimaryProfile', () => ({
usePrimaryProfile: ({ address }: { address: string }) => {
if (address === '0x43e47385f6b3f8bdbe02c210bf5c74b6c34ff441') {
if (address === '0x1111111111111111111111111111111111111111') {
return {
data: {
name: 'metamask.eth',
originalName: 'MetaMask.eth',
match: false,
name: 'test.eth',
match: true,
texts: [
{ key: 'description', value: 'MetaMask wallet' },
{ key: 'description', value: 'Test profile' },
],
},
isLoading: false,
Expand All @@ -57,10 +56,9 @@ vi.mock('@app/hooks/chain/useChainName', () => ({
}))

vi.mock('@app/components/ProfileSnippet', () => ({
ProfileSnippet: ({ name, hasMismatch, button }: any) => (
ProfileSnippet: ({ name, button }: any) => (
<div data-testid="profile-snippet">
<span data-testid="profile-name">{name}</span>
{hasMismatch && <span data-testid="has-mismatch">Mismatch</span>}
{button && <span data-testid="button-type">{button}</span>}
</div>
),
Expand Down Expand Up @@ -113,30 +111,30 @@ describe('Address Page', () => {
</QueryClientProvider>
)

it('should display MetaMask.eth with original capitalization', async () => {
it('should display a valid primary name', async () => {
vi.mocked(useRouter).mockReturnValueOnce({
isReady: true,
query: { address: '0x1111111111111111111111111111111111111111' },
} as any)

render(<Page />, { wrapper })

await waitFor(() => {
const profileName = screen.getByTestId('profile-name')
expect(profileName.textContent).toBe('MetaMask.eth')
expect(profileName.textContent).toBe('test.eth')
})
})

it('should indicate mismatch when primary name does not match', async () => {
render(<Page />, { wrapper })

await waitFor(() => {
expect(screen.getByTestId('has-mismatch')).toBeInTheDocument()
})
})
it('should show View Profile button for valid names', async () => {
vi.mocked(useRouter).mockReturnValueOnce({
isReady: true,
query: { address: '0x1111111111111111111111111111111111111111' },
} as any)

it('should not show View Profile button for mismatched names', async () => {
render(<Page />, { wrapper })

await waitFor(() => {
// When hasMismatch is true, button prop should be undefined, so button-type should not exist
const buttonType = screen.queryByTestId('button-type')
expect(buttonType).not.toBeInTheDocument()
expect(screen.getByTestId('button-type').textContent).toBe('viewProfile')
})
})

Expand All @@ -154,13 +152,11 @@ describe('Address Page', () => {
})
})

it('should pass hasMismatch prop to ProfileSnippet', async () => {
it('should show NoProfileSnippet when unnormalized names are filtered out', async () => {
render(<Page />, { wrapper })

await waitFor(() => {
const profileSnippet = screen.getByTestId('profile-snippet')
expect(profileSnippet).toBeInTheDocument()
expect(screen.getByTestId('has-mismatch')).toBeInTheDocument()
expect(screen.getByTestId('no-profile-snippet')).toBeInTheDocument()
})
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Address } from 'viem'
import { Typography } from '@ensdomains/thorin'

import { AvatarWithZorb } from '@app/components/AvatarWithZorb'
import { getPrimaryDisplayName } from '@app/hooks/ensjs/public/primaryNameUtils'
import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName'
import { QuerySpace } from '@app/types'
import { shortenAddress } from '@app/utils/utils'
Expand Down Expand Up @@ -55,7 +56,7 @@ export const AvatarWithIdentifier = ({
enabled: !name,
})

const _name = primary.data?.beautifiedName || name
const _name = name || getPrimaryDisplayName(primary.data)
const _title = _name || (shortenAddressAsTitle ? shortenAddress(address) : address)
const _subtitle = subtitle || (_name ? shortenAddress(address) : undefined)

Expand Down
3 changes: 2 additions & 1 deletion src/components/@molecules/ConnectButton/ConnectButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useConnections, useDisconnect } from 'wagmi'
import { Button, PersonSVG, Profile } from '@ensdomains/thorin'

import { useAccountSafely } from '@app/hooks/account/useAccountSafely'
import { getPrimaryDisplayName } from '@app/hooks/ensjs/public/primaryNameUtils'
import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName'
import useHasPendingTransactions from '@app/hooks/transactions/useHasPendingTransactions'
import { useCopied } from '@app/hooks/useCopied'
Expand Down Expand Up @@ -134,7 +135,7 @@ const HeaderProfile = ({ address }: { address: Address }) => {
return (
<Profile
address={address}
ensName={primary?.beautifiedName}
ensName={getPrimaryDisplayName(primary)}
dropdownItems={getDropdownItems({
primary,
disconnect,
Expand Down
3 changes: 2 additions & 1 deletion src/components/@molecules/ConnectButton/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Address } from 'viem'
import { CheckSVG, CogSVG, CopySVG, ExitSVG, PersonSVG, WalletSVG } from '@ensdomains/thorin'
import type { DropdownItem } from '@ensdomains/thorin/dist/types/components/molecules/Dropdown/Dropdown'

import { hasValidPrimaryName } from '@app/hooks/ensjs/public/primaryNameUtils'
import { shortenAddress } from '@app/utils/utils'

import BaseLink from '../../@atoms/BaseLink'
Expand Down Expand Up @@ -37,7 +38,7 @@ export const getDropdownItems = ({
address: Address
}): DropdownItem[] =>
[
...(primary?.name
...(hasValidPrimaryName(primary)
? [
{
label: t('wallet.myProfile'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Address } from 'viem'
import { Typography } from '@ensdomains/thorin'

import { AvatarWithZorb, NameAvatar } from '@app/components/AvatarWithZorb'
import { getPrimaryDisplayName } from '@app/hooks/ensjs/public/primaryNameUtils'
import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName'
import { useBeautifiedName } from '@app/hooks/useBeautifiedName'
import { TransactionDisplayItem } from '@app/types'
Expand Down Expand Up @@ -101,23 +102,24 @@ const AddressSubtitle = styled(Typography)(

const AddressValue = ({ value }: { value: string }) => {
const primary = usePrimaryName({ address: value as Address })
const primaryDisplayName = getPrimaryDisplayName(primary.data)

const AddressTypography = useMemo(
() =>
primary.data?.name ? (
primaryDisplayName ? (
<AddressSubtitle color="grey">{shortenAddress(value)}</AddressSubtitle>
) : (
<ValueTypography fontVariant="bodyBold">{shortenAddress(value)}</ValueTypography>
),
[primary.data?.name, value],
[primaryDisplayName, value],
)

return (
<ValueWithAvatarContainer>
<InnerValueWrapper>
{primary.data?.name && (
{primaryDisplayName && (
<ValueTypography fontVariant="bodyBold" color="text">
{primary.data?.beautifiedName}
{primaryDisplayName}
</ValueTypography>
)}
{AddressTypography}
Expand Down
5 changes: 3 additions & 2 deletions src/components/TabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import styled, { css } from 'styled-components'
import { CrossSVG, LeftChevronSVG, PersonSVG } from '@ensdomains/thorin'

import { useAccountSafely } from '@app/hooks/account/useAccountSafely'
import { hasValidPrimaryName } from '@app/hooks/ensjs/public/primaryNameUtils'
import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName'
import useHasPendingTransactions from '@app/hooks/transactions/useHasPendingTransactions'
import { useEnsAvatar } from '@app/hooks/useEnsAvatar'
Expand Down Expand Up @@ -225,7 +226,7 @@ export const TabBar = () => {
const { address } = useAccountSafely()
const primary = usePrimaryName({ address })

const hasPrimary = !!primary.data?.name
const hasPrimary = hasValidPrimaryName(primary.data)
const hasBack = !!router.query.from

const [isOpen, setIsOpen] = useState(false)
Expand Down Expand Up @@ -267,7 +268,7 @@ export const TabBar = () => {
address={address}
isOpen={isOpen}
setIsOpen={setIsOpen}
name={primary.data?.name}
name={hasPrimary ? primary.data?.name : undefined}
/>
</>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { useEstimateGasWithStateOverride } from '@app/hooks/chain/useEstimateGas
import { useGasPrice } from '@app/hooks/chain/useGasPrice'
import { useDnsImportData } from '@app/hooks/ensjs/dns/useDnsImportData'
import { useDnsOwner } from '@app/hooks/ensjs/dns/useDnsOwner'
import { getPrimaryDisplayName } from '@app/hooks/ensjs/public/primaryNameUtils'
import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName'
import { useApprovedForAll } from '@app/hooks/useApprovedForAll'
import { useTransactionFlow } from '@app/transaction-flow/TransactionFlowProvider'
Expand Down Expand Up @@ -78,13 +79,12 @@ const InvoiceDnsOwnerContainer = styled.div(

const InvoiceDnsOwner = ({ dnsOwner }: { dnsOwner: Address }) => {
const { data: primary } = usePrimaryName({ address: dnsOwner })
const primaryDisplayName = getPrimaryDisplayName(primary)

return (
<InvoiceDnsOwnerContainer>
<div>
{primary?.beautifiedName && (
<Typography fontVariant="bodyBold">{primary.beautifiedName}</Typography>
)}
{primaryDisplayName && <Typography fontVariant="bodyBold">{primaryDisplayName}</Typography>}
<Typography fontVariant="small" color="grey">
{shortenAddress(dnsOwner)}
</Typography>
Expand Down
10 changes: 6 additions & 4 deletions src/components/pages/profile/NameSnippet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Button, Typography } from '@ensdomains/thorin'
import { CacheableComponent } from '@app/components/@atoms/CacheableComponent'
import { AddressAvatar, AvatarWithZorb } from '@app/components/AvatarWithZorb'
import { NFTWithPlaceholder } from '@app/components/NFTWithPlaceholder'
import { getPrimaryDisplayName } from '@app/hooks/ensjs/public/primaryNameUtils'
import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName'
import { useRouterWithHistory } from '@app/hooks/useRouterWithHistory'
import { shortenAddress } from '@app/utils/utils'
Expand Down Expand Up @@ -58,15 +59,16 @@ const OwnerWithEns = styled.div(

const NameOwnerItem = ({ address }: { address?: Address }) => {
const { data: nameData } = usePrimaryName({ address })
const primaryDisplayName = getPrimaryDisplayName(nameData)

if (nameData?.name) {
if (nameData?.name && primaryDisplayName) {
return (
<OwnerContainer>
<OwnerWithEns>
<Typography weight="bold">
{nameData.beautifiedName.length > 12
? `${nameData.beautifiedName.slice(0, 12)}...`
: nameData.beautifiedName}
{primaryDisplayName.length > 12
? `${primaryDisplayName.slice(0, 12)}...`
: primaryDisplayName}
</Typography>
<Typography weight="bold">{shortenAddress(address)}</Typography>
</OwnerWithEns>
Expand Down
15 changes: 11 additions & 4 deletions src/components/pages/profile/ProfileButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ import { VerificationBadgeVerifierTooltipContent } from '@app/components/@molecu
import { VerificationBadge } from '@app/components/@molecules/VerificationBadge/VerificationBadge'
import { useBlockExplorer } from '@app/hooks/chain/useBlockExplorer'
import { useCoinChain } from '@app/hooks/chain/useCoinChain'
import {
getPrimaryDisplayName,
hasValidPrimaryName,
} from '@app/hooks/ensjs/public/primaryNameUtils'
import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName'
import { useRouterWithHistory } from '@app/hooks/useRouterWithHistory'
import { getDestinationAsHref } from '@app/routes'
Expand Down Expand Up @@ -310,6 +314,8 @@ export const OwnerProfileButton = ({
address: addressOrNameOrDate as Address,
enabled: dataType === 'address',
})
const primaryDisplayName = getPrimaryDisplayName(primary.data)
const hasPrimaryName = hasValidPrimaryName(primary.data)

const { link, ...recordItemPartialProps } = useMemo(() => {
const base = {
Expand Down Expand Up @@ -341,11 +347,11 @@ export const OwnerProfileButton = ({
if (dataType === 'address')
return {
...base,
link: primary.data?.name
link: hasPrimaryName
? getDestinationAsHref(createUrlObject(`/profile/${primary.data?.name}`, { referrer }))
: getDestinationAsHref(createUrlObject(`/address/${addressOrNameOrDate}`, { referrer })),
children:
primary.data?.beautifiedName ||
primaryDisplayName ||
(breakpoints.sm ? shortenAddress(addressOrNameOrDate) : addressOrNameOrDate.slice(0, 5)),
} as const
return {
Expand All @@ -358,8 +364,9 @@ export const OwnerProfileButton = ({
addressOrNameOrDate,
label,
breakpoints,
hasPrimaryName,
primary.data?.name,
primary.data?.beautifiedName,
primaryDisplayName,
referrer,
t,
])
Expand All @@ -374,7 +381,7 @@ export const OwnerProfileButton = ({
onClick: () => router.push(link),
}
: undefined,
primary.data?.name
hasPrimaryName
? {
icon: CopyIcon,
label: 'Copy name',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { BaseLinkWithHistory } from '@app/components/@atoms/BaseLink'
import { InnerDialog } from '@app/components/@atoms/InnerDialog'
import { ProfileRecord } from '@app/constants/profileRecordOptions'
import { useContractAddress } from '@app/hooks/chain/useContractAddress'
import { hasValidPrimaryName } from '@app/hooks/ensjs/public/primaryNameUtils'
import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName'
import { useIsEthRegistrarControllerActive } from '@app/hooks/registration/useIsEthRegistrarControllerActive'
import { useNameDetails } from '@app/hooks/useNameDetails'
Expand Down Expand Up @@ -354,7 +355,7 @@ const Registration = ({ nameDetails, isLoading }: Props) => {
resolverExists={resolverExists}
callback={pricingCallback}
isPrimaryLoading={primary.isLoading}
hasPrimaryName={!!primary.data?.name}
hasPrimaryName={hasValidPrimaryName(primary.data)}
registrationData={item}
moonpayTransactionStatus={moonpayTransactionStatus}
initiateMoonpayRegistrationMutation={initiateMoonpayRegistrationMutation}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { DisabledButtonWithTooltip } from '@app/components/@molecules/DisabledBu
import { AvatarWithZorb } from '@app/components/AvatarWithZorb'
import { useDnsImportData } from '@app/hooks/ensjs/dns/useDnsImportData'
import { GetDnsOwnerQueryKey, UseDnsOwnerError } from '@app/hooks/ensjs/dns/useDnsOwner'
import { getPrimaryDisplayName } from '@app/hooks/ensjs/public/primaryNameUtils'
import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName'
import { useOwners } from '@app/hooks/useOwners'
import { makeIntroItem } from '@app/transaction-flow/intro'
Expand Down Expand Up @@ -129,22 +130,23 @@ const OwnerDetailContainer = styled.div(
const Owner = ({ address, label }: OwnerItem) => {
const { t } = useTranslation('common')
const primary = usePrimaryName({ address })
const primaryDisplayName = getPrimaryDisplayName(primary.data)

return (
<BaseLinkWithHistory passHref href={`/address/${address}`}>
<OwnerContainer as="a">
<OwnerDetailContainer>
<AvatarWithZorb
label={primary.data?.name || address}
label={primary.data?.name ?? address}
address={address}
name={primary.data?.name}
size="10"
/>
<TextContainer>
<Name ellipsis data-testid={`owner-button-name-${label}`}>
{primary.data?.beautifiedName || shortenAddress(address)}
{primaryDisplayName || shortenAddress(address)}
</Name>
{primary.data?.name && (
{primaryDisplayName && (
<Typography data-testid={`owner-button-address-${label}`}>
{shortenAddress(address)}
</Typography>
Expand Down
Loading
Loading