Skip to content

Commit

Permalink
refactor: nft avatar (#12017)
Browse files Browse the repository at this point in the history
  • Loading branch information
swkatmask authored Jan 2, 2025
1 parent e3d8a08 commit 6507061
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 89 deletions.
1 change: 1 addition & 0 deletions packages/plugins/Avatar/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@masknet/web3-shared-base": "workspace:^",
"@masknet/web3-shared-evm": "workspace:^",
"@masknet/web3-telemetry": "workspace:^",
"@servie/events": "^3.0.0",
"@types/react-avatar-editor": "^13.0.2",
"@types/use-subscription": "^1.0.2",
"bignumber.js": "9.1.2",
Expand Down
4 changes: 2 additions & 2 deletions packages/plugins/Avatar/src/Application/NFTAvatarDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { InjectedDialogProps } from '@masknet/shared'
import { useMemo } from 'react'
import { MemoryRouter } from 'react-router-dom'
import { RoutePaths } from './Routes.js'
import { AvatarManagementProvider } from '../contexts/AvatarManagement.js'
import { RouterDialog } from './RouterDialog.js'
import type { InjectedDialogProps } from '@masknet/shared'
import { RoutePaths } from './Routes.js'

interface NFTAvatarDialogProps extends InjectedDialogProps {
startPicking?: boolean
Expand Down
63 changes: 26 additions & 37 deletions packages/plugins/Avatar/src/Application/NFTListDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { compact, uniqBy } from 'lodash-es'
import { useCallback, useImperativeHandle, useState, type RefAttributes } from 'react'
import { useUpdateEffect } from 'react-use'
import { useNavigate } from 'react-router-dom'
import { Icons } from '@masknet/icons'
import { Trans } from '@lingui/macro'
import { openPopupWindow } from '@masknet/plugin-infra/dom/context'
import {
AddCollectiblesModal,
ChainBoundary,
CollectionList,
EmptyStatus,
PluginVerifiedWalletStatusBar,
PopupHomeTabType,
UserAssetsProvider,
} from '@masknet/shared'
import { NetworkPluginID, PopupRoutes } from '@masknet/shared-base'
import { useRenderPhraseCallbackOnDepsChange } from '@masknet/shared-base-ui'
import { makeStyles, useCustomSnackbar } from '@masknet/theme'
import type { Web3Helper } from '@masknet/web3-helpers'
import {
Expand All @@ -25,16 +23,19 @@ import {
} from '@masknet/web3-hooks-base'
import { isGreaterThan, isSameAddress } from '@masknet/web3-shared-base'
import { type ChainId } from '@masknet/web3-shared-evm'
import { Box, Button, DialogActions, DialogContent, Typography } from '@mui/material'
import { Telemetry } from '@masknet/web3-telemetry'
import { EventID, EventType } from '@masknet/web3-telemetry/types'
import { Button, DialogActions, DialogContent } from '@mui/material'
import { compact, uniqBy } from 'lodash-es'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useUpdateEffect } from 'react-use'
import { supportPluginIds } from '../constants.js'
import { useAvatarManagement } from '../contexts/AvatarManagement.js'
import { type AllChainsNonFungibleToken, PFP_TYPE } from '../types.js'
import { emitter } from '../emitter.js'
import { PFP_TYPE, type AllChainsNonFungibleToken } from '../types.js'
import { toPNG } from '../utils/index.js'
import { RoutePaths } from './Routes.js'
import { useRenderPhraseCallbackOnDepsChange } from '@masknet/shared-base-ui'
import { Trans } from '@lingui/macro'

const useStyles = makeStyles()((theme) => ({
actions: {
Expand All @@ -61,24 +62,13 @@ const useStyles = makeStyles()((theme) => ({
overflow: 'hidden',
display: 'flex',
},
noWallet: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'column',
flex: 1,
},
}))

const gridProps = {
columns: 'repeat(auto-fill, minmax(20%, 1fr))',
}

export interface NFTListDialogRef {
handleAddCollectibles: () => void
}

export function NFTListDialog({ ref }: RefAttributes<NFTListDialogRef | undefined>) {
export function NFTListDialog() {
const { classes } = useStyles()
const { pfpType, proofs, tokenInfo, targetAccount, setTargetAccount, setSelectedTokenInfo, proof } =
useAvatarManagement()
Expand Down Expand Up @@ -173,13 +163,13 @@ export function NFTListDialog({ ref }: RefAttributes<NFTListDialogRef | undefine
})
}, [pluginID, assetChainId, targetAccount])

useImperativeHandle(
ref,
() => ({
handleAddCollectibles,
}),
[handleAddCollectibles],
)
useEffect(() => {
const unsubscribe = emitter.on('add', handleAddCollectibles)
return () => {
unsubscribe()
}
}, [handleAddCollectibles])

useRenderPhraseCallbackOnDepsChange(() => setSelectedPluginId(pluginID), [pluginID])

useUpdateEffect(() => {
Expand All @@ -191,9 +181,11 @@ export function NFTListDialog({ ref }: RefAttributes<NFTListDialogRef | undefine
}, [originAccount])

const targetWallet = wallets.find((x) => isSameAddress(targetAccount, x.address))
const walletItems = proofs.sort((a, z) => {
return isGreaterThan(a.last_checked_at, z.last_checked_at) ? -1 : 1
})
const walletItems = useMemo(() => {
return [...proofs].sort((a, z) => {
return isGreaterThan(a.last_checked_at, z.last_checked_at) ? -1 : 1
})
}, [proofs])

return (
<>
Expand All @@ -211,12 +203,9 @@ export function NFTListDialog({ ref }: RefAttributes<NFTListDialogRef | undefine
onChainChange={setAssetChainId as (chainId?: Web3Helper.ChainIdAll) => void}
/>
</UserAssetsProvider>
: <Box className={classes.noWallet} height={479}>
<Icons.EmptySimple variant="light" size={36} />
<Typography fontSize={14} color={(theme) => theme.palette.maskColor.second} mt="12px">
<Trans>No valid wallet detected. Please connect wallet or verify wallet firstly.</Trans>
</Typography>
</Box>
: <EmptyStatus height={479}>
<Trans>No valid wallet detected. Please connect wallet or verify wallet firstly.</Trans>
</EmptyStatus>
}
</DialogContent>

Expand Down
18 changes: 5 additions & 13 deletions packages/plugins/Avatar/src/Application/RouterDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { Icons } from '@masknet/icons'
import { InjectedDialog, type InjectedDialogProps } from '@masknet/shared'
import { makeStyles } from '@masknet/theme'
import { DialogContent } from '@mui/material'
import { useLayoutEffect, useRef } from 'react'
import { useLayoutEffect } from 'react'
import { matchPath, useLocation, useNavigate } from 'react-router-dom'
import { AvatarRoutes, RoutePaths } from './Routes.js'
import type { NFTListDialogRef } from './NFTListDialog.js'
import { Trans } from '@lingui/macro'
import { addCollectibles } from '../emitter.js'

const useStyles = makeStyles()({
root: {
Expand All @@ -24,23 +24,15 @@ const useStyles = makeStyles()({

export function RouterDialog(props: InjectedDialogProps) {
const { classes } = useStyles()
const nftListRef = useRef<NFTListDialogRef>(undefined)
const { pathname } = useLocation()
const navigate = useNavigate()

useLayoutEffect(() => {
if (pathname === RoutePaths.Exit) props.onClose?.()
}, [pathname, props.onClose])
}, [pathname === RoutePaths.Exit, props.onClose])

const title = matchPath(RoutePaths.Upload, pathname) ? <Trans>Edit Profile</Trans> : <Trans>NFT PFP</Trans>
const titleTail =
matchPath(RoutePaths.NFTPicker, pathname) ?
<Icons.Plus
onClick={() => {
nftListRef.current?.handleAddCollectibles()
}}
/>
: undefined
const titleTail = matchPath(RoutePaths.NFTPicker, pathname) ? <Icons.Plus onClick={addCollectibles} /> : undefined

const isOnBack = pathname !== RoutePaths.Personas

Expand All @@ -58,7 +50,7 @@ export function RouterDialog(props: InjectedDialogProps) {
navigate(-1)
}}>
<DialogContent className={classes.root}>
<AvatarRoutes ref={nftListRef} />
<AvatarRoutes />
</DialogContent>
</InjectedDialog>
)
Expand Down
7 changes: 3 additions & 4 deletions packages/plugins/Avatar/src/Application/Routes.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Navigate, Route, Routes } from 'react-router-dom'
import { NFTListDialog, type NFTListDialogRef } from './NFTListDialog.js'
import { NFTListDialog } from './NFTListDialog.js'
import { PersonaPage } from './PersonaPage.js'
import { UploadAvatarDialog } from './UploadAvatarDialog.js'
import { type RefAttributes } from 'react'

export enum RoutePaths {
Personas = '/personas',
Expand All @@ -11,11 +10,11 @@ export enum RoutePaths {
Exit = '/exit',
}

export function AvatarRoutes({ ref }: RefAttributes<NFTListDialogRef | undefined>) {
export function AvatarRoutes() {
return (
<Routes>
<Route path={RoutePaths.Personas} element={<PersonaPage />} />
<Route path={RoutePaths.NFTPicker} element={<NFTListDialog ref={ref} />} />
<Route path={RoutePaths.NFTPicker} element={<NFTListDialog />} />
<Route path={RoutePaths.Upload} element={<UploadAvatarDialog />} />
{/* If router is embedded inside a dialog, */}
{/* which should know it's time to close itself once we enter Exit */}
Expand Down
22 changes: 11 additions & 11 deletions packages/plugins/Avatar/src/Application/UploadAvatarDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Trans } from '@lingui/macro'
import { delay } from '@masknet/kit'
import { useCallback, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import AvatarEditor from 'react-avatar-editor'
import { useSubscription } from 'use-subscription'
import { Button, DialogActions, DialogContent, Slider } from '@mui/material'
import { useLastRecognizedIdentity } from '@masknet/plugin-infra/content-script'
import { currentVisitingProfile } from '@masknet/plugin-infra/content-script/context'
import { usePersonaConnectStatus } from '@masknet/shared'
import { makeStyles, useCustomSnackbar } from '@masknet/theme'
import { useNetworkContext } from '@masknet/web3-hooks-base'
import { Twitter } from '@masknet/web3-providers'
import { usePersonaConnectStatus } from '@masknet/shared'
import { isSameAddress } from '@masknet/web3-shared-base'
import { useNetworkContext } from '@masknet/web3-hooks-base'
import { useLastRecognizedIdentity } from '@masknet/plugin-infra/content-script'
import { currentVisitingProfile } from '@masknet/plugin-infra/content-script/context'
import { type AvatarInfo, useSave } from '../hooks/useSave.js'
import { Button, DialogActions, DialogContent, Slider } from '@mui/material'
import { useCallback, useState } from 'react'
import AvatarEditor from 'react-avatar-editor'
import { useNavigate } from 'react-router-dom'
import { useSubscription } from 'use-subscription'
import { useAvatarManagement } from '../contexts/AvatarManagement.js'
import { type AvatarInfo, useSave } from '../hooks/useSave.js'
import { RoutePaths } from './Routes.js'
import { Trans } from '@lingui/macro'

const useStyles = makeStyles()((theme) => ({
actions: {
Expand Down
34 changes: 17 additions & 17 deletions packages/plugins/Avatar/src/contexts/AvatarManagement.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
import { useLastRecognizedIdentity } from '@masknet/plugin-infra/content-script'
import { currentNextIDPlatform } from '@masknet/plugin-infra/content-script/context'
import { queryPersonaByProfile } from '@masknet/plugin-infra/dom/context'
import {
type BindingProof,
EMPTY_LIST,
MaskMessages,
type NextIDPersonaBindings,
NextIDPlatform,
type SocialIdentity,
} from '@masknet/shared-base'
import type { Web3Helper } from '@masknet/web3-helpers'
import { useChainContext } from '@masknet/web3-hooks-base'
import { NextIDProof } from '@masknet/web3-providers'
import { isValidAddress } from '@masknet/web3-shared-evm'
import { useQuery } from '@tanstack/react-query'
import { first, noop } from 'lodash-es'
import {
createContext,
Expand All @@ -6,27 +22,11 @@ import {
type PropsWithChildren,
type SetStateAction,
useContext,
useEffect,
useMemo,
useState,
useEffect,
} from 'react'
import {
type BindingProof,
EMPTY_LIST,
type SocialIdentity,
NextIDPlatform,
MaskMessages,
type NextIDPersonaBindings,
} from '@masknet/shared-base'
import type { Web3Helper } from '@masknet/web3-helpers'
import { useChainContext } from '@masknet/web3-hooks-base'
import { PFP_TYPE, type SelectTokenInfo } from '../types.js'
import { useLastRecognizedIdentity } from '@masknet/plugin-infra/content-script'
import { currentNextIDPlatform } from '@masknet/plugin-infra/content-script/context'
import { queryPersonaByProfile } from '@masknet/plugin-infra/dom/context'
import { useQuery } from '@tanstack/react-query'
import { NextIDProof } from '@masknet/web3-providers'
import { isValidAddress } from '@masknet/web3-shared-evm'

interface AvatarManagementContextOptions {
isPending: boolean
Expand Down
9 changes: 9 additions & 0 deletions packages/plugins/Avatar/src/emitter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Emitter } from '@servie/events'

export const emitter = new Emitter<{
add: []
}>()

export function addCollectibles() {
emitter.emit('add')
}
9 changes: 4 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 6507061

Please sign in to comment.