chore(refactore): use NDKContext for findMetadata instead of metadata controller

This commit is contained in:
daniyal 2024-12-20 15:52:45 +05:00
parent 0cc1a32059
commit 458de18f12
8 changed files with 98 additions and 318 deletions

View File

@ -9,7 +9,7 @@ import {
} from '@mui/material' } from '@mui/material'
import styles from './style.module.scss' import styles from './style.module.scss'
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { ProfileMetadata, User, UserRole, KeyboardCode } from '../../types' import { User, UserRole, KeyboardCode } from '../../types'
import { MouseState, PdfPage, DrawnField, DrawTool } from '../../types/drawing' import { MouseState, PdfPage, DrawnField, DrawTool } from '../../types/drawing'
import { hexToNpub, npubToHex, getProfileUsername } from '../../utils' import { hexToNpub, npubToHex, getProfileUsername } from '../../utils'
import { SigitFile } from '../../utils/file' import { SigitFile } from '../../utils/file'
@ -21,6 +21,7 @@ import { useScale } from '../../hooks/useScale'
import { AvatarIconButton } from '../UserAvatarIconButton' import { AvatarIconButton } from '../UserAvatarIconButton'
import { UserAvatar } from '../UserAvatar' import { UserAvatar } from '../UserAvatar'
import _ from 'lodash' import _ from 'lodash'
import { NDKUserProfile } from '@nostr-dev-kit/ndk'
const DEFAULT_START_SIZE = { const DEFAULT_START_SIZE = {
width: 140, width: 140,
@ -33,7 +34,7 @@ interface HideSignersForDrawnField {
interface Props { interface Props {
users: User[] users: User[]
metadata: { [key: string]: ProfileMetadata } userProfiles: { [key: string]: NDKUserProfile }
sigitFiles: SigitFile[] sigitFiles: SigitFile[]
setSigitFiles: React.Dispatch<React.SetStateAction<SigitFile[]>> setSigitFiles: React.Dispatch<React.SetStateAction<SigitFile[]>>
selectedTool?: DrawTool selectedTool?: DrawTool
@ -563,10 +564,11 @@ export const DrawPDFFields = (props: Props) => {
> >
{signers.map((signer, index) => { {signers.map((signer, index) => {
const npub = hexToNpub(signer.pubkey) const npub = hexToNpub(signer.pubkey)
const metadata = props.metadata[signer.pubkey] const profile =
props.userProfiles[signer.pubkey]
const displayValue = getProfileUsername( const displayValue = getProfileUsername(
npub, npub,
metadata profile
) )
// make current signers dropdown visible // make current signers dropdown visible
if ( if (
@ -585,7 +587,7 @@ export const DrawPDFFields = (props: Props) => {
<MenuItem key={index} value={npub}> <MenuItem key={index} value={npub}>
<ListItemIcon> <ListItemIcon>
<AvatarIconButton <AvatarIconButton
src={metadata?.picture} src={profile?.image}
hexKey={signer.pubkey} hexKey={signer.pubkey}
aria-label={`account of user ${displayValue}`} aria-label={`account of user ${displayValue}`}
color="inherit" color="inherit"
@ -621,13 +623,13 @@ export const DrawPDFFields = (props: Props) => {
const signer = signers.find((u) => u.pubkey === npubToHex(npub)) const signer = signers.find((u) => u.pubkey === npubToHex(npub))
if (signer) { if (signer) {
const metadata = props.metadata[signer.pubkey] const profile = props.userProfiles[signer.pubkey]
displayValue = getProfileUsername(npub, metadata) displayValue = getProfileUsername(npub, profile)
return ( return (
<div className={styles.counterpartSelectValue}> <div className={styles.counterpartSelectValue}>
<AvatarIconButton <AvatarIconButton
src={props.metadata[signer.pubkey]?.picture} src={profile?.image}
hexKey={signer.pubkey || undefined} hexKey={signer.pubkey || undefined}
sx={{ sx={{
padding: 0, padding: 0,

View File

@ -23,7 +23,7 @@ export const UserAvatar = ({
}: UserAvatarProps) => { }: UserAvatarProps) => {
const profile = useProfileMetadata(pubkey) const profile = useProfileMetadata(pubkey)
const name = getProfileUsername(pubkey, profile) const name = getProfileUsername(pubkey, profile)
const image = profile?.picture const image = profile?.image
return ( return (
<Link <Link

View File

@ -4,6 +4,7 @@ import NDK, {
NDKFilter, NDKFilter,
NDKRelaySet, NDKRelaySet,
NDKSubscriptionCacheUsage, NDKSubscriptionCacheUsage,
NDKSubscriptionOptions,
NDKUser, NDKUser,
NDKUserProfile NDKUserProfile
} from '@nostr-dev-kit/ndk' } from '@nostr-dev-kit/ndk'
@ -35,7 +36,11 @@ export interface NDKContextType {
hexKey: string, hexKey: string,
userRelaysType: UserRelaysType userRelaysType: UserRelaysType
) => Promise<NDKEvent | null> ) => Promise<NDKEvent | null>
findMetadata: (pubkey: string) => Promise<NDKUserProfile | null> findMetadata: (
pubkey: string,
opts?: NDKSubscriptionOptions,
storeProfileEvent?: boolean
) => Promise<NDKUserProfile | null>
publish: (event: NDKEvent, explicitRelayUrls?: string[]) => Promise<string[]> publish: (event: NDKEvent, explicitRelayUrls?: string[]) => Promise<string[]>
} }
@ -191,16 +196,22 @@ export const NDKContextProvider = ({ children }: { children: ReactNode }) => {
* @returns A promise that resolves to the metadata event. * @returns A promise that resolves to the metadata event.
*/ */
const findMetadata = async ( const findMetadata = async (
pubkey: string pubkey: string,
opts?: NDKSubscriptionOptions,
storeProfileEvent?: boolean
): Promise<NDKUserProfile | null> => { ): Promise<NDKUserProfile | null> => {
const npub = hexToNpub(pubkey) const npub = hexToNpub(pubkey)
const user = new NDKUser({ npub }) const user = new NDKUser({ npub })
user.ndk = ndk user.ndk = ndk
return await user.fetchProfile({ return await user.fetchProfile(
cacheUsage: NDKSubscriptionCacheUsage.PARALLEL {
}) cacheUsage: NDKSubscriptionCacheUsage.PARALLEL,
...(opts || {})
},
storeProfileEvent
)
} }
const publish = async ( const publish = async (

View File

@ -1,35 +1,19 @@
import { import { Event } from 'nostr-tools'
Event,
Filter,
VerifiedEvent,
kinds,
validateEvent,
verifyEvent
} from 'nostr-tools'
import { toast } from 'react-toastify'
import { EventEmitter } from 'tseep' import { EventEmitter } from 'tseep'
import { NostrController, relayController } from '.'
import { localCache } from '../services'
import { ProfileMetadata, RelaySet } from '../types' import { ProfileMetadata, RelaySet } from '../types'
import { import {
findRelayListAndUpdateCache, findRelayListAndUpdateCache,
findRelayListInCache, findRelayListInCache,
getDefaultRelaySet, getDefaultRelaySet,
getUserRelaySet, getUserRelaySet
isOlderThanOneDay,
unixNow
} from '../utils' } from '../utils'
import { DEFAULT_LOOK_UP_RELAY_LIST } from '../utils/const' import { DEFAULT_LOOK_UP_RELAY_LIST } from '../utils/const'
export class MetadataController extends EventEmitter { export class MetadataController extends EventEmitter {
private static instance: MetadataController private static instance: MetadataController
private nostrController: NostrController
private specialMetadataRelay = 'wss://purplepag.es'
private pendingFetches = new Map<string, Promise<Event | null>>() // Track pending fetches
constructor() { constructor() {
super() super()
this.nostrController = NostrController.getInstance()
} }
public static getInstance(): MetadataController { public static getInstance(): MetadataController {
@ -39,105 +23,6 @@ export class MetadataController extends EventEmitter {
return MetadataController.instance return MetadataController.instance
} }
/**
* Asynchronously checks for more recent metadata events authored by a specific key.
* If a more recent metadata event is found, it is handled and returned.
* If no more recent event is found, the current event is returned.
* @param hexKey The hexadecimal key of the author to filter metadata events.
* @param currentEvent The current metadata event, if any, to compare with newer events.
* @returns A promise resolving to the most recent metadata event found, or null if none is found.
*/
private async checkForMoreRecentMetadata(
hexKey: string,
currentEvent: Event | null
): Promise<Event | null> {
// Return the ongoing fetch promise if one exists for the same hexKey
if (this.pendingFetches.has(hexKey)) {
return this.pendingFetches.get(hexKey)!
}
// Define the event filter to only include metadata events authored by the given key
const eventFilter: Filter = {
kinds: [kinds.Metadata],
authors: [hexKey]
}
const fetchPromise = relayController
.fetchEvent(eventFilter, DEFAULT_LOOK_UP_RELAY_LIST)
.catch((err) => {
console.error(err)
return null
})
.finally(() => {
this.pendingFetches.delete(hexKey)
})
this.pendingFetches.set(hexKey, fetchPromise)
const metadataEvent = await fetchPromise
if (
metadataEvent &&
validateEvent(metadataEvent) &&
verifyEvent(metadataEvent)
) {
if (
!currentEvent ||
metadataEvent.created_at >= currentEvent.created_at
) {
this.handleNewMetadataEvent(metadataEvent)
}
return metadataEvent
}
// todo/implement: if no valid metadata event is found in DEFAULT_LOOK_UP_RELAY_LIST
// try to query user relay list
// if current event is null we should cache empty metadata event for provided hexKey
if (!currentEvent) {
const emptyMetadata = this.getEmptyMetadataEvent(hexKey)
this.handleNewMetadataEvent(emptyMetadata as VerifiedEvent)
}
return currentEvent
}
/**
* Handle new metadata events and emit them to subscribers
*/
private async handleNewMetadataEvent(event: VerifiedEvent) {
// update the event in local cache
localCache.addUserMetadata(event)
// Emit the event to subscribers.
this.emit(event.pubkey, event.kind, event)
}
/**
* Finds metadata for a given hexadecimal key.
*
* @param hexKey - The hexadecimal key to search for metadata.
* @returns A promise that resolves to the metadata event.
*/
public findMetadata = async (hexKey: string): Promise<Event | null> => {
// Attempt to retrieve the metadata event from the local cache
const cachedMetadataEvent = await localCache.getUserMetadata(hexKey)
// If cached metadata is found, check its validity
if (cachedMetadataEvent) {
// Check if the cached metadata is older than one day
if (isOlderThanOneDay(cachedMetadataEvent.cachedAt)) {
// If older than one week, find the metadata from relays in background
this.checkForMoreRecentMetadata(hexKey, cachedMetadataEvent.event)
}
// Return the cached metadata event
return cachedMetadataEvent.event
}
// If no cached metadata is found, retrieve it from relays
return this.checkForMoreRecentMetadata(hexKey, null)
}
/** /**
* Based on the hexKey of the current user, this method attempts to retrieve a relay set. * Based on the hexKey of the current user, this method attempts to retrieve a relay set.
* @func findRelayListInCache first checks if there is already an up-to-date * @func findRelayListInCache first checks if there is already an up-to-date
@ -168,52 +53,4 @@ export class MetadataController extends EventEmitter {
return null return null
} }
} }
/**
* Function will not sign provided event if the SIG exists
*/
public publishMetadataEvent = async (event: Event) => {
let signedMetadataEvent = event
if (event.sig.length < 1) {
const timestamp = unixNow()
// Metadata event to publish to the wss://purplepag.es relay
const newMetadataEvent: Event = {
...event,
created_at: timestamp
}
signedMetadataEvent =
await this.nostrController.signEvent(newMetadataEvent)
}
await relayController
.publish(signedMetadataEvent, [this.specialMetadataRelay])
.then((relays) => {
if (relays.length) {
toast.success(`Metadata event published on: ${relays.join('\n')}`)
this.handleNewMetadataEvent(signedMetadataEvent as VerifiedEvent)
} else {
toast.error('Could not publish metadata event to any relay!')
}
})
.catch((err) => {
toast.error(err.message)
})
}
public validate = (event: Event) => validateEvent(event) && verifyEvent(event)
public getEmptyMetadataEvent = (pubkey?: string): Event => {
return {
content: '',
created_at: new Date().valueOf(),
id: '',
kind: 0,
pubkey: pubkey || '',
sig: '',
tags: []
}
}
} }

View File

@ -1,33 +1,18 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { ProfileMetadata } from '../types/profile'
import { MetadataController } from '../controllers/MetadataController' import { NDKUserProfile } from '@nostr-dev-kit/ndk'
import { Event, kinds } from 'nostr-tools' import { useNDKContext } from './useNDKContext'
export const useProfileMetadata = (pubkey: string) => { export const useProfileMetadata = (pubkey: string) => {
const [profileMetadata, setProfileMetadata] = useState<ProfileMetadata>() const { findMetadata } = useNDKContext()
const [userProfile, setUserProfile] = useState<NDKUserProfile>()
useEffect(() => { useEffect(() => {
const metadataController = MetadataController.getInstance()
const handleMetadataEvent = (event: Event) => {
const metadataContent =
metadataController.extractProfileMetadataContent(event)
if (metadataContent) {
setProfileMetadata(metadataContent)
}
}
if (pubkey) { if (pubkey) {
metadataController.on(pubkey, (kind: number, event: Event) => { findMetadata(pubkey)
if (kind === kinds.Metadata) { .then((profile) => {
handleMetadataEvent(event) if (profile) setUserProfile(profile)
}
})
metadataController
.findMetadata(pubkey)
.then((metadataEvent) => {
if (metadataEvent) handleMetadataEvent(metadataEvent)
}) })
.catch((err) => { .catch((err) => {
console.error( console.error(
@ -36,11 +21,7 @@ export const useProfileMetadata = (pubkey: string) => {
) )
}) })
} }
}, [pubkey, findMetadata])
return () => { return userProfile
metadataController.off(pubkey, handleMetadataEvent)
}
}, [pubkey])
return profileMetadata
} }

View File

@ -1,7 +1,7 @@
import { useCallback, useEffect, useRef, useState } from 'react' import { useCallback, useEffect, useRef, useState } from 'react'
import { Outlet, useNavigate, useSearchParams } from 'react-router-dom' import { Outlet, useNavigate, useSearchParams } from 'react-router-dom'
import { Event, getPublicKey, kinds, nip19 } from 'nostr-tools' import { Event, getPublicKey, nip19 } from 'nostr-tools'
import { init as initNostrLogin } from 'nostr-login' import { init as initNostrLogin } from 'nostr-login'
import { NostrLoginAuthOptions } from 'nostr-login/dist/types' import { NostrLoginAuthOptions } from 'nostr-login/dist/types'
@ -9,9 +9,15 @@ import { NostrLoginAuthOptions } from 'nostr-login/dist/types'
import { AppBar } from '../components/AppBar/AppBar' import { AppBar } from '../components/AppBar/AppBar'
import { LoadingSpinner } from '../components/LoadingSpinner' import { LoadingSpinner } from '../components/LoadingSpinner'
import { MetadataController, NostrController } from '../controllers' import { NostrController } from '../controllers'
import { useAppDispatch, useAppSelector, useAuth, useLogout } from '../hooks' import {
useAppDispatch,
useAppSelector,
useAuth,
useLogout,
useNDKContext
} from '../hooks'
import { import {
restoreState, restoreState,
@ -38,6 +44,7 @@ export const MainLayout = () => {
const navigate = useNavigate() const navigate = useNavigate()
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const logout = useLogout() const logout = useLogout()
const { findMetadata } = useNDKContext()
const { authAndGetMetadataAndRelaysMap } = useAuth() const { authAndGetMetadataAndRelaysMap } = useAuth()
const [isLoading, setIsLoading] = useState(true) const [isLoading, setIsLoading] = useState(true)
@ -143,8 +150,6 @@ export const MainLayout = () => {
}, [dispatch]) }, [dispatch])
useEffect(() => { useEffect(() => {
const metadataController = MetadataController.getInstance()
const restoredState = loadState() const restoredState = loadState()
if (restoredState) { if (restoredState) {
dispatch(restoreState(restoredState)) dispatch(restoreState(restoredState))
@ -154,20 +159,19 @@ export const MainLayout = () => {
if (loggedIn) { if (loggedIn) {
if (!loginMethod || !usersPubkey) return logout() if (!loginMethod || !usersPubkey) return logout()
// Update user profile metadata, old state might be outdated findMetadata(usersPubkey, {}, true).then((profile) => {
const handleMetadataEvent = (event: Event) => { if (profile && profile.profileEvent) {
dispatch(setMetadataEvent(event)) try {
} const event: Event = JSON.parse(profile.profileEvent)
dispatch(setMetadataEvent(event))
metadataController.on(usersPubkey, (kind: number, event: Event) => { } catch (error) {
if (kind === kinds.Metadata) { console.error(
handleMetadataEvent(event) 'An error occurred in parsing profile event from profile obj',
error
)
}
} }
}) })
metadataController.findMetadata(usersPubkey).then((metadataEvent) => {
if (metadataEvent) handleMetadataEvent(metadataEvent)
})
} else { } else {
setIsLoading(false) setIsLoading(false)
} }

View File

@ -10,7 +10,7 @@ import {
import type { Identifier, XYCoord } from 'dnd-core' import type { Identifier, XYCoord } from 'dnd-core'
import saveAs from 'file-saver' import saveAs from 'file-saver'
import JSZip from 'jszip' import JSZip from 'jszip'
import { Event, kinds } from 'nostr-tools' import { Event } from 'nostr-tools'
import { useCallback, useEffect, useRef, useState } from 'react' import { useCallback, useEffect, useRef, useState } from 'react'
import { DndProvider, useDrag, useDrop } from 'react-dnd' import { DndProvider, useDrag, useDrop } from 'react-dnd'
import { MultiBackend } from 'react-dnd-multi-backend' import { MultiBackend } from 'react-dnd-multi-backend'
@ -30,7 +30,6 @@ import {
CreateSignatureEventContent, CreateSignatureEventContent,
KeyboardCode, KeyboardCode,
Meta, Meta,
ProfileMetadata,
SignedEvent, SignedEvent,
User, User,
UserRole UserRole
@ -80,12 +79,16 @@ import { Autocomplete } from '@mui/lab'
import _, { truncate } from 'lodash' import _, { truncate } from 'lodash'
import * as React from 'react' import * as React from 'react'
import { AvatarIconButton } from '../../components/UserAvatarIconButton' import { AvatarIconButton } from '../../components/UserAvatarIconButton'
import { NDKUserProfile } from '@nostr-dev-kit/ndk'
import { useNDKContext } from '../../hooks/useNDKContext.ts'
type FoundUser = Event & { npub: string } type FoundUser = Event & { npub: string }
export const CreatePage = () => { export const CreatePage = () => {
const navigate = useNavigate() const navigate = useNavigate()
const location = useLocation() const location = useLocation()
const { findMetadata } = useNDKContext()
const { uploadedFiles } = location.state || {} const { uploadedFiles } = location.state || {}
const [currentFile, setCurrentFile] = useState<File>() const [currentFile, setCurrentFile] = useState<File>()
const isActive = (file: File) => file.name === currentFile?.name const isActive = (file: File) => file.name === currentFile?.name
@ -117,9 +120,10 @@ export const CreatePage = () => {
const nostrController = NostrController.getInstance() const nostrController = NostrController.getInstance()
const [metadata, setMetadata] = useState<{ [key: string]: ProfileMetadata }>( const [userProfiles, setUserProfiles] = useState<{
{} [key: string]: NDKUserProfile
) }>({})
const [drawnFiles, setDrawnFiles] = useState<SigitFile[]>([]) const [drawnFiles, setDrawnFiles] = useState<SigitFile[]>([])
const [parsingPdf, setIsParsing] = useState<boolean>(false) const [parsingPdf, setIsParsing] = useState<boolean>(false)
@ -280,29 +284,15 @@ export const CreatePage = () => {
useEffect(() => { useEffect(() => {
users.forEach((user) => { users.forEach((user) => {
if (!(user.pubkey in metadata)) { if (!(user.pubkey in userProfiles)) {
const metadataController = MetadataController.getInstance() findMetadata(user.pubkey)
.then((profile) => {
const handleMetadataEvent = (event: Event) => { if (profile) {
const metadataContent = setUserProfiles((prev) => ({
metadataController.extractProfileMetadataContent(event) ...prev,
if (metadataContent) [user.pubkey]: profile
setMetadata((prev) => ({ }))
...prev, }
[user.pubkey]: metadataContent
}))
}
metadataController.on(user.pubkey, (kind: number, event: Event) => {
if (kind === kinds.Metadata) {
handleMetadataEvent(event)
}
})
metadataController
.findMetadata(user.pubkey)
.then((metadataEvent) => {
if (metadataEvent) handleMetadataEvent(metadataEvent)
}) })
.catch((err) => { .catch((err) => {
console.error( console.error(
@ -312,7 +302,7 @@ export const CreatePage = () => {
}) })
} }
}) })
}, [metadata, users]) }, [userProfiles, users, findMetadata])
useEffect(() => { useEffect(() => {
if (uploadedFiles) { if (uploadedFiles) {
@ -1204,7 +1194,7 @@ export const CreatePage = () => {
) : ( ) : (
<DrawPDFFields <DrawPDFFields
users={users} users={users}
metadata={metadata} userProfiles={userProfiles}
selectedTool={selectedTool} selectedTool={selectedTool}
sigitFiles={drawnFiles} sigitFiles={drawnFiles}
setSigitFiles={setDrawnFiles} setSigitFiles={setDrawnFiles}

View File

@ -1,10 +1,12 @@
import { useEffect, useState } from 'react'
import { toast } from 'react-toastify'
import { import {
Meta, Cancel,
ProfileMetadata, CheckCircle,
SignedEventContent, Download,
User, HourglassTop
UserRole } from '@mui/icons-material'
} from '../../../types'
import { import {
Box, Box,
IconButton, IconButton,
@ -20,22 +22,19 @@ import {
Typography, Typography,
useTheme useTheme
} from '@mui/material' } from '@mui/material'
import {
Download,
CheckCircle,
Cancel,
HourglassTop
} from '@mui/icons-material'
import saveAs from 'file-saver' import saveAs from 'file-saver'
import { kinds, Event } from 'nostr-tools'
import { useState, useEffect } from 'react' import { Event } from 'nostr-tools'
import { toast } from 'react-toastify'
import { UserAvatar } from '../../../components/UserAvatar' import { UserAvatar } from '../../../components/UserAvatar'
import { MetadataController } from '../../../controllers'
import { npubToHex, hexToNpub, parseJson } from '../../../utils' import { Meta, SignedEventContent, User, UserRole } from '../../../types'
import styles from '../style.module.scss' import { hexToNpub, npubToHex, parseJson } from '../../../utils'
import { SigitFile } from '../../../utils/file' import { SigitFile } from '../../../utils/file'
import styles from '../style.module.scss'
type DisplayMetaProps = { type DisplayMetaProps = {
meta: Meta meta: Meta
files: { [fileName: string]: SigitFile } files: { [fileName: string]: SigitFile }
@ -67,9 +66,6 @@ export const DisplayMeta = ({
theme.palette.background.paper theme.palette.background.paper
) )
const [metadata, setMetadata] = useState<{ [key: string]: ProfileMetadata }>(
{}
)
const [users, setUsers] = useState<User[]>([]) const [users, setUsers] = useState<User[]>([])
useEffect(() => { useEffect(() => {
@ -104,45 +100,6 @@ export const DisplayMeta = ({
}) })
}, [signers, viewers]) }, [signers, viewers])
useEffect(() => {
const metadataController = MetadataController.getInstance()
const hexKeys: string[] = [
npubToHex(submittedBy)!,
...users.map((user) => user.pubkey)
]
hexKeys.forEach((key) => {
if (!(key in metadata)) {
const handleMetadataEvent = (event: Event) => {
const metadataContent =
metadataController.extractProfileMetadataContent(event)
if (metadataContent)
setMetadata((prev) => ({
...prev,
[key]: metadataContent
}))
}
metadataController.on(key, (kind: number, event: Event) => {
if (kind === kinds.Metadata) {
handleMetadataEvent(event)
}
})
metadataController
.findMetadata(key)
.then((metadataEvent) => {
if (metadataEvent) handleMetadataEvent(metadataEvent)
})
.catch((err) => {
console.error(`error occurred in finding metadata for: ${key}`, err)
})
}
})
}, [users, submittedBy, metadata])
const downloadFile = async (fileName: string) => { const downloadFile = async (fileName: string) => {
const file = files[fileName] const file = files[fileName]
saveAs(file) saveAs(file)
@ -229,7 +186,6 @@ export const DisplayMeta = ({
key={user.pubkey} key={user.pubkey}
meta={meta} meta={meta}
user={user} user={user}
metadata={metadata}
signedBy={signedBy} signedBy={signedBy}
nextSigner={nextSigner} nextSigner={nextSigner}
getPrevSignersSig={getPrevSignersSig} getPrevSignersSig={getPrevSignersSig}
@ -258,7 +214,6 @@ enum UserStatus {
type DisplayUserProps = { type DisplayUserProps = {
meta: Meta meta: Meta
user: User user: User
metadata: { [key: string]: ProfileMetadata }
signedBy: `npub1${string}`[] signedBy: `npub1${string}`[]
nextSigner?: string nextSigner?: string
getPrevSignersSig: (usersNpub: string) => string | null getPrevSignersSig: (usersNpub: string) => string | null