Skip to content

Commit

Permalink
fix: bugfix for encrypted contacts (#10337)
Browse files Browse the repository at this point in the history
* feat: add contacts page

* refactor: change account render

* fix: mf-4808 empty ens

* fix: mf-4805 fix title

* fix: mf-4805 fix title

* fix: mf-4812 ui/ux

* fix: mf-4825 change link

* fix: mf-4809 search twitter handle

* fix: keybase account

* feat: upgrade to blocto v2 SDK (#10309)

* chore: update blocto SDK

* refactor: remove deprecated field

* refactor: remove server side configuration fields

* fix: Flow Balance

* fix: platform type

* fix: mf-4806 search lens/ens

* fix: mf-4811 account sort

* fix: rebase

* fix: lock file

* fix: merge error

* fix: type

* fix: type

---------

Co-authored-by: guanbinrui <52657989+guanbinrui@users.noreply.github.com>
  • Loading branch information
beyond009 and guanbinrui committed Aug 10, 2023
1 parent 5782792 commit 4262b33
Show file tree
Hide file tree
Showing 21 changed files with 416 additions and 264 deletions.
42 changes: 31 additions & 11 deletions packages/mask/src/extension/popups/hook/useFriends.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,26 @@ export type FriendsInformation = ProfileInformation & {
id: string
}

export function useFriends(network: string): AsyncStateRetry<FriendsInformation[]> {
export const PlatformSort: Record<NextIDPlatform, number> = {
[NextIDPlatform.Twitter]: 0,
[NextIDPlatform.GitHub]: 1,
[NextIDPlatform.Ethereum]: 2,
[NextIDPlatform.ENS]: 3,
[NextIDPlatform.LENS]: 4,
[NextIDPlatform.Keybase]: 5,
[NextIDPlatform.Farcaster]: 6,
[NextIDPlatform.SpaceId]: 7,
[NextIDPlatform.Unstoppable]: 8,
[NextIDPlatform.RSS3]: 9,
[NextIDPlatform.REDDIT]: 10,
[NextIDPlatform.SYBIL]: 11,
[NextIDPlatform.EthLeaderboard]: 12,
[NextIDPlatform.Bit]: 13,
[NextIDPlatform.CyberConnect]: 14,
[NextIDPlatform.NextID]: 15,
}

export function useFriends(): AsyncStateRetry<FriendsInformation[]> {
const currentPersona = useCurrentPersona()
return useAsyncRetry(async () => {
const values = await Services.Identity.queryRelationPaged(
Expand All @@ -35,7 +54,7 @@ export function useFriends(network: string): AsyncStateRetry<FriendsInformation[
const allSettled = await Promise.allSettled(
friends.map((item) => {
const id = (item.linkedPersona as ECKeyIdentifier).publicKeyAsHex
return NextIDProof.queryProfilesByPublicKey(id)
return NextIDProof.queryProfilesByPublicKey(id, 2)
}),
)
const profiles: FriendsInformation[] = allSettled.map((item, index) => {
Expand All @@ -57,21 +76,22 @@ export function useFriends(network: string): AsyncStateRetry<FriendsInformation[
}
const filtered = item.value.filter(
(x) =>
x.platform === NextIDPlatform.Twitter ||
x.platform === NextIDPlatform.LENS ||
x.platform === NextIDPlatform.ENS ||
x.platform === NextIDPlatform.Ethereum ||
x.platform === NextIDPlatform.GitHub ||
x.platform === NextIDPlatform.SpaceId ||
x.platform === NextIDPlatform.Farcaster ||
x.platform === NextIDPlatform.Unstoppable,
(x.platform === NextIDPlatform.ENS && x.name.endsWith('.eth')) ||
(x.platform !== NextIDPlatform.Bit &&
x.platform !== NextIDPlatform.CyberConnect &&
x.platform !== NextIDPlatform.REDDIT &&
x.platform !== NextIDPlatform.SYBIL &&
x.platform !== NextIDPlatform.EthLeaderboard &&
x.platform !== NextIDPlatform.NextID),
)

filtered.sort((a, b) => PlatformSort[a.platform] - PlatformSort[b.platform])
return {
profiles: filtered,
...friends[index],
id: (friends[index].linkedPersona as ECKeyIdentifier).publicKeyAsHex,
}
})
return uniqBy(profiles, ({ id }) => id).reverse()
}, [network, currentPersona])
}, [currentPersona])
}
22 changes: 14 additions & 8 deletions packages/mask/src/extension/popups/hook/useFriendsFromSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { AsyncStateRetry } from 'react-use/lib/useAsyncRetry.js'
import { uniqBy } from 'lodash-es'
import type { FriendsInformation } from './useFriends.js'
import { NextIDPlatform } from '@masknet/shared-base'
import { PlatformSort } from './useFriends.js'

export type NextIDPersonaBindingsWithIdentifier = NextIDPersonaBindings & { linkedPersona: ECKeyIdentifier } & {
isLocal?: boolean
Expand All @@ -12,24 +13,29 @@ export type NextIDPersonaBindingsWithIdentifier = NextIDPersonaBindings & { link
export function useFriendsFromSearch(
searchResult?: NextIDPersonaBindings[],
localList?: FriendsInformation[],
searchValue?: string,
): AsyncStateRetry<NextIDPersonaBindingsWithIdentifier[]> {
return useAsyncRetry(async () => {
if (!searchResult?.length) return EMPTY_LIST
const profiles: NextIDPersonaBindingsWithIdentifier[] = searchResult.map((item, index) => {
const filtered = item.proofs.filter(
(x) =>
x.platform === NextIDPlatform.Twitter ||
x.platform === NextIDPlatform.LENS ||
x.platform === NextIDPlatform.ENS ||
x.platform === NextIDPlatform.Ethereum ||
x.platform === NextIDPlatform.GitHub ||
x.platform === NextIDPlatform.SpaceId ||
x.platform === NextIDPlatform.Farcaster ||
x.platform === NextIDPlatform.Unstoppable,
(x.platform === NextIDPlatform.ENS && x.name.endsWith('.eth')) ||
(x.platform !== NextIDPlatform.Bit &&
x.platform !== NextIDPlatform.CyberConnect &&
x.platform !== NextIDPlatform.REDDIT &&
x.platform !== NextIDPlatform.SYBIL &&
x.platform !== NextIDPlatform.EthLeaderboard &&
x.platform !== NextIDPlatform.NextID),
)
const identifier = ECKeyIdentifier.fromHexPublicKeyK256(item.persona).expect(
`${item.persona} should be a valid hex public key in k256`,
)
filtered.sort((a, b) =>
a.identity === searchValue || a.name === searchValue
? -1
: PlatformSort[a.platform] - PlatformSort[b.platform],
)
return {
proofs: filtered,
linkedPersona: identifier,
Expand Down
18 changes: 18 additions & 0 deletions packages/mask/src/extension/popups/hook/useSearchValue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useAsyncRetry } from 'react-use'
import type { AsyncStateRetry } from 'react-use/lib/useAsyncRetry.js'
import { ECKeyIdentifier, NextIDPlatform } from '@masknet/shared-base'
import { ENS, Lens } from '@masknet/web3-providers'

export function useSearchValue(value: string, type?: NextIDPlatform): AsyncStateRetry<string> {
return useAsyncRetry(async () => {
if (!type) return ''
if (value.length === 44) return new ECKeyIdentifier('secp256k1', value).publicKeyAsHex ?? value
if (type === NextIDPlatform.Twitter) return value.replace(/^@/, '').toLowerCase()

if (value.endsWith('.eth')) return (await ENS.lookup(value))?.toLowerCase()

if (value.endsWith('.lens')) return (await Lens.getProfileByHandle(value)).ownedBy?.toLowerCase()

return value.toLowerCase()
}, [value])
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { memo } from 'react'
import { type BindingProof, NextIDPlatform, EnhanceableSite } from '@masknet/shared-base'
import { SocialAccount as DetailSocialAccount } from '../Detail/SocialAccount/index.js'
import { Account as DetailAccount } from '../Detail/Account/index.js'
import { SocialAccount } from '../ContactCard/SocialAccount/index.js'
import { Account } from '../ContactCard/Account/index.js'
import { safeUnreachable } from '@masknet/kit'

interface AccountRenderProps {
profile: BindingProof
detail?: boolean
}

export const AccountRender = memo<AccountRenderProps>(function AccountRender({ profile, detail }) {
return (function () {
switch (profile.platform) {
case NextIDPlatform.Twitter:
return detail ? (
<DetailSocialAccount
avatar={''}
userId={profile.name ? profile.name : profile.identity}
site={EnhanceableSite.Twitter}
/>
) : (
<SocialAccount
avatar={''}
userId={profile.name ? profile.name : profile.identity}
site={EnhanceableSite.Twitter}
/>
)
case NextIDPlatform.ENS:
case NextIDPlatform.Ethereum:
case NextIDPlatform.GitHub:
case NextIDPlatform.SpaceId:
case NextIDPlatform.LENS:
case NextIDPlatform.Unstoppable:
case NextIDPlatform.Farcaster:
case NextIDPlatform.Keybase:
const _userID =
profile.platform === NextIDPlatform.ENS || profile.platform === NextIDPlatform.Keybase
? profile.name
: profile.identity
return detail ? (
<DetailAccount userId={_userID} icon={profile.platform} />
) : (
<Account userId={_userID} icon={profile.platform} />
)
case NextIDPlatform.CyberConnect:
case NextIDPlatform.Bit:
case NextIDPlatform.SYBIL:
case NextIDPlatform.EthLeaderboard:
case NextIDPlatform.REDDIT:
case NextIDPlatform.RSS3:
case NextIDPlatform.NextID:
return null
default:
safeUnreachable(profile.platform)
return null
}
})()
})
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { memo } from 'react'
import { Box, Link } from '@mui/material'
import { Icons } from '@masknet/icons'
import { makeStyles } from '@masknet/theme'
import { NextIDPlatform, formatPersonaName } from '@masknet/shared-base'
import { NextIDPlatform } from '@masknet/shared-base'
import { formatEthereumAddress } from '@masknet/web3-shared-evm'
import { safeUnreachable } from '@masknet/kit'
import { formatUserId } from '../SocialAccount/index.js'

export type SupportedPlatforms =
| NextIDPlatform.Ethereum
Expand All @@ -14,9 +15,11 @@ export type SupportedPlatforms =
| NextIDPlatform.SpaceId
| NextIDPlatform.Farcaster
| NextIDPlatform.Unstoppable
| NextIDPlatform.Keybase

interface AccountProps {
icon: SupportedPlatforms
userId: string
userId?: string
}

const useStyles = makeStyles()((theme) => ({
Expand All @@ -33,52 +36,58 @@ const useStyles = makeStyles()((theme) => ({
lineHeight: '18px',
},
}))

export const url: Record<SupportedPlatforms, string> = {
[NextIDPlatform.ENS]: 'https://app.ens.domains/name/',
[NextIDPlatform.Unstoppable]: 'https://ud.me/',
[NextIDPlatform.GitHub]: 'https://github.com/',
[NextIDPlatform.SpaceId]: 'https://space.storage/',
[NextIDPlatform.Farcaster]: 'https://www.farcaster.xyz/',
[NextIDPlatform.LENS]: 'https://lenster.xyz/',
[NextIDPlatform.SpaceId]: 'https://bscscan.com/address/',
[NextIDPlatform.Farcaster]: 'https://warpcast.com/',
[NextIDPlatform.LENS]: 'https://lenster.xyz/u/',
[NextIDPlatform.Ethereum]: 'https://etherscan.io/address/',
[NextIDPlatform.Keybase]: 'https://keybase.io/',
}

export const Account = memo<AccountProps>(function Account({ userId, icon }) {
const { classes } = useStyles()
return (
<Box width="156px" padding="4px" display="flex" gap="10px" alignItems="center">
{(() => {
switch (icon) {
case NextIDPlatform.LENS:
return <Icons.Lens width={30} height={30} />
case NextIDPlatform.Ethereum:
return <Icons.ETH width={30} height={30} />
case NextIDPlatform.ENS:
return <Icons.ENS width={30} height={30} />
case NextIDPlatform.GitHub:
return <Icons.GitHub width={30} height={30} />
case NextIDPlatform.Farcaster:
return <Icons.Farcaster width={30} height={30} />
case NextIDPlatform.SpaceId:
return <Icons.SpaceId width={30} height={30} />
case NextIDPlatform.Unstoppable:
return <Icons.Unstoppable width={30} height={30} />
default:
safeUnreachable(icon)
return null
}
})()}
<Box className={classes.userId}>
{icon === NextIDPlatform.Ethereum ? formatEthereumAddress(userId, 4) : formatPersonaName(userId)}
<Link
underline="none"
target="_blank"
rel="noopener noreferrer"
href={url[icon] + userId}
className={classes.iconBlack}>
<Icons.LinkOut size={16} />
</Link>
userId && (
<Box width="156px" padding="4px" display="flex" gap="10px" alignItems="center">
{(() => {
switch (icon) {
case NextIDPlatform.LENS:
return <Icons.Lens width={30} height={30} />
case NextIDPlatform.Ethereum:
return <Icons.ETH width={30} height={30} />
case NextIDPlatform.ENS:
return <Icons.ENS width={30} height={30} />
case NextIDPlatform.GitHub:
return <Icons.GitHub width={30} height={30} />
case NextIDPlatform.Farcaster:
return <Icons.Farcaster width={30} height={30} />
case NextIDPlatform.SpaceId:
return <Icons.SpaceId width={30} height={30} />
case NextIDPlatform.Unstoppable:
return <Icons.Unstoppable width={30} height={30} />
case NextIDPlatform.Keybase:
return <Icons.Keybase width={30} height={30} />
default:
safeUnreachable(icon)
return null
}
})()}
<Box className={classes.userId}>
{icon === NextIDPlatform.Ethereum ? formatEthereumAddress(userId, 4) : formatUserId(userId)}
<Link
underline="none"
target="_blank"
rel="noopener noreferrer"
href={url[icon] + userId}
className={classes.iconBlack}>
<Icons.LinkOut size={16} />
</Link>
</Box>
</Box>
</Box>
)
)
})
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { memo } from 'react'
import { makeStyles } from '@masknet/theme'
import { Box, Typography, useTheme, ButtonBase } from '@mui/material'
import { type BindingProof, PopupRoutes, NextIDPlatform, EnhanceableSite } from '@masknet/shared-base'
import { type BindingProof, PopupRoutes } from '@masknet/shared-base'
import { useNavigate } from 'react-router-dom'
import { Account } from '../Account/index.js'
import { safeUnreachable } from '@masknet/kit'
import { SocialAccount } from '../SocialAccount/index.js'
import { AccountRender } from '../../AccountRender/index.js'

const useStyles = makeStyles()((theme) => ({
connectedAccounts: {
Expand Down Expand Up @@ -55,42 +53,8 @@ export const ConnectedAccounts = memo<ConnectedAccountsProps>(function ({
height="58px"
className={classes.connectedAccounts}
width="100%">
{profiles.slice(0, 2).map((profile) => {
switch (profile.platform) {
case NextIDPlatform.Twitter:
return (
<SocialAccount
avatar={''}
userId={profile.name ? profile.name : profile.identity}
site={EnhanceableSite.Twitter}
/>
)
case NextIDPlatform.ENS:
case NextIDPlatform.Ethereum:
case NextIDPlatform.GitHub:
case NextIDPlatform.SpaceId:
case NextIDPlatform.LENS:
case NextIDPlatform.Unstoppable:
case NextIDPlatform.Farcaster:
return (
<Account
userId={profile.platform === NextIDPlatform.ENS ? profile.name : profile.identity}
icon={profile.platform}
/>
)
case NextIDPlatform.CyberConnect:
case NextIDPlatform.Bit:
case NextIDPlatform.SYBIL:
case NextIDPlatform.Keybase:
case NextIDPlatform.EthLeaderboard:
case NextIDPlatform.REDDIT:
case NextIDPlatform.RSS3:
case NextIDPlatform.NextID:
return null
default:
safeUnreachable(profile.platform)
return null
}
{profiles.slice(0, 2).map((profile, index) => {
return <AccountRender key={index} profile={profile} />
})}
{profiles.length > 2 ? (
<ButtonBase
Expand Down

0 comments on commit 4262b33

Please sign in to comment.