chore(refactor): use NDKContext in profile page
This commit is contained in:
parent
3c061d5920
commit
2248128001
@ -198,7 +198,9 @@ export const NDKContextProvider = ({ children }: { children: ReactNode }) => {
|
||||
const user = new NDKUser({ npub })
|
||||
user.ndk = ndk
|
||||
|
||||
return await user.fetchProfile()
|
||||
return await user.fetchProfile({
|
||||
cacheUsage: NDKSubscriptionCacheUsage.PARALLEL
|
||||
})
|
||||
}
|
||||
|
||||
const publish = async (
|
||||
|
@ -1,48 +1,49 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Link, useNavigate, useParams } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import ContentCopyIcon from '@mui/icons-material/ContentCopy'
|
||||
import EditIcon from '@mui/icons-material/Edit'
|
||||
import { Box, IconButton, SxProps, Theme, Typography } from '@mui/material'
|
||||
import { Event, VerifiedEvent, kinds, nip19 } from 'nostr-tools'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useAppSelector } from '../../hooks/store'
|
||||
import { Link, useNavigate, useParams } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import { nip19 } from 'nostr-tools'
|
||||
|
||||
import { Container } from '../../components/Container'
|
||||
import { Footer } from '../../components/Footer/Footer'
|
||||
import { LoadingSpinner } from '../../components/LoadingSpinner'
|
||||
import { MetadataController } from '../../controllers'
|
||||
import { useAppSelector } from '../../hooks/store'
|
||||
|
||||
import { getProfileSettingsRoute } from '../../routes'
|
||||
import { NostrJoiningBlock, ProfileMetadata } from '../../types'
|
||||
|
||||
import {
|
||||
getNostrJoiningBlockNumber,
|
||||
getProfileUsername,
|
||||
getRoboHashPicture,
|
||||
hexToNpub,
|
||||
shorten
|
||||
} from '../../utils'
|
||||
|
||||
import { NDKEvent, NDKUserProfile, profileFromEvent } from '@nostr-dev-kit/ndk'
|
||||
import { useNDKContext } from '../../hooks'
|
||||
import styles from './style.module.scss'
|
||||
import { Container } from '../../components/Container'
|
||||
import { Footer } from '../../components/Footer/Footer'
|
||||
|
||||
export const ProfilePage = () => {
|
||||
const navigate = useNavigate()
|
||||
|
||||
const { npub } = useParams()
|
||||
|
||||
const metadataController = useMemo(() => MetadataController.getInstance(), [])
|
||||
const { ndk, findMetadata } = useNDKContext()
|
||||
|
||||
const [pubkey, setPubkey] = useState<string>()
|
||||
const [nostrJoiningBlock, setNostrJoiningBlock] =
|
||||
useState<NostrJoiningBlock | null>(null)
|
||||
const [profileMetadata, setProfileMetadata] = useState<ProfileMetadata>()
|
||||
const [userProfile, setUserProfile] = useState<NDKUserProfile | null>(null)
|
||||
|
||||
const userRobotImage = useAppSelector((state) => state.userRobotImage)
|
||||
const metadataState = useAppSelector((state) => state.metadata)
|
||||
const { usersPubkey } = useAppSelector((state) => state.auth)
|
||||
const userRobotImage = useAppSelector((state) => state.userRobotImage)
|
||||
|
||||
const [isUsersOwnProfile, setIsUsersOwnProfile] = useState(false)
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [loadingSpinnerDesc] = useState('Fetching metadata')
|
||||
|
||||
const profileName = pubkey && getProfileUsername(pubkey, profileMetadata)
|
||||
|
||||
useEffect(() => {
|
||||
if (npub) {
|
||||
try {
|
||||
@ -57,60 +58,30 @@ export const ProfilePage = () => {
|
||||
}, [npub, usersPubkey])
|
||||
|
||||
useEffect(() => {
|
||||
if (pubkey) {
|
||||
getNostrJoiningBlockNumber(pubkey)
|
||||
.then((res) => {
|
||||
setNostrJoiningBlock(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
// todo: handle error
|
||||
console.log('err :>> ', err)
|
||||
})
|
||||
}
|
||||
|
||||
if (isUsersOwnProfile && metadataState) {
|
||||
const metadataContent = metadataController.extractProfileMetadataContent(
|
||||
metadataState as VerifiedEvent
|
||||
)
|
||||
if (metadataContent) {
|
||||
setProfileMetadata(metadataContent)
|
||||
setIsLoading(false)
|
||||
}
|
||||
const ndkEvent = new NDKEvent(ndk, metadataState)
|
||||
const profile = profileFromEvent(ndkEvent)
|
||||
|
||||
setUserProfile(profile)
|
||||
|
||||
setIsLoading(false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (pubkey) {
|
||||
const getMetadata = async (pubkey: string) => {
|
||||
const handleMetadataEvent = (event: Event) => {
|
||||
const metadataContent =
|
||||
metadataController.extractProfileMetadataContent(event)
|
||||
if (metadataContent) {
|
||||
setProfileMetadata(metadataContent)
|
||||
}
|
||||
}
|
||||
|
||||
metadataController.on(pubkey, (kind: number, event: Event) => {
|
||||
if (kind === kinds.Metadata) {
|
||||
handleMetadataEvent(event)
|
||||
}
|
||||
findMetadata(pubkey)
|
||||
.then((profile) => {
|
||||
setUserProfile(profile)
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err)
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoading(false)
|
||||
})
|
||||
|
||||
const metadataEvent = await metadataController
|
||||
.findMetadata(pubkey)
|
||||
.catch((err) => {
|
||||
toast.error(err)
|
||||
return null
|
||||
})
|
||||
|
||||
if (metadataEvent) handleMetadataEvent(metadataEvent)
|
||||
|
||||
setIsLoading(false)
|
||||
}
|
||||
|
||||
getMetadata(pubkey)
|
||||
}
|
||||
}, [isUsersOwnProfile, metadataState, pubkey, metadataController])
|
||||
}, [ndk, isUsersOwnProfile, metadataState, pubkey, findMetadata])
|
||||
|
||||
/**
|
||||
* Rendering text with button which copies the provided text
|
||||
@ -146,29 +117,32 @@ export const ProfilePage = () => {
|
||||
*
|
||||
* @returns robohash image url
|
||||
*/
|
||||
const getProfileImage = (metadata: ProfileMetadata) => {
|
||||
if (!metadata) return ''
|
||||
const getProfileImage = (profile: NDKUserProfile | null) => {
|
||||
if (!profile) return getRoboHashPicture(npub)
|
||||
|
||||
if (!isUsersOwnProfile) {
|
||||
return metadata.picture || getRoboHashPicture(npub!)
|
||||
return profile.image || getRoboHashPicture(npub!)
|
||||
}
|
||||
|
||||
// userRobotImage is used only when visiting own profile
|
||||
// while kind 0 picture is not set
|
||||
return metadata.picture || userRobotImage || getRoboHashPicture(npub!)
|
||||
return profile.image || userRobotImage || getRoboHashPicture(npub!)
|
||||
}
|
||||
|
||||
const profileName =
|
||||
pubkey && getProfileUsername(pubkey, userProfile || undefined)
|
||||
|
||||
return (
|
||||
<>
|
||||
{isLoading && <LoadingSpinner desc={loadingSpinnerDesc} />}
|
||||
{pubkey && (
|
||||
<Container className={styles.container}>
|
||||
<Box
|
||||
className={`${styles.banner} ${!profileMetadata || !profileMetadata.banner ? styles.noImage : ''}`}
|
||||
className={`${styles.banner} ${!userProfile || !userProfile.banner ? styles.noImage : ''}`}
|
||||
>
|
||||
{profileMetadata && profileMetadata.banner ? (
|
||||
{userProfile && userProfile.banner ? (
|
||||
<img
|
||||
src={profileMetadata.banner}
|
||||
src={userProfile.banner}
|
||||
alt={`banner image for ${profileName}`}
|
||||
/>
|
||||
) : (
|
||||
@ -189,24 +163,12 @@ export const ProfilePage = () => {
|
||||
>
|
||||
<img
|
||||
className={styles['image-placeholder']}
|
||||
src={getProfileImage(profileMetadata!)}
|
||||
src={getProfileImage(userProfile)}
|
||||
alt={profileName}
|
||||
/>
|
||||
</div>
|
||||
</Box>
|
||||
<Box className={styles.middle}>
|
||||
<Typography
|
||||
component={Link}
|
||||
to={`https://njump.me/${nostrJoiningBlock?.encodedEventPointer || ''}`}
|
||||
target="_blank"
|
||||
className={`${styles.nostrSince} ${styles.link}`}
|
||||
variant="caption"
|
||||
>
|
||||
{nostrJoiningBlock
|
||||
? `On nostr since ${nostrJoiningBlock.block.toLocaleString()}`
|
||||
: 'On nostr since: unknown'}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box className={styles.right}>
|
||||
{isUsersOwnProfile && (
|
||||
<IconButton
|
||||
@ -224,15 +186,13 @@ export const ProfilePage = () => {
|
||||
display: 'flex'
|
||||
}}
|
||||
>
|
||||
{profileMetadata && (
|
||||
<Typography
|
||||
sx={{ margin: '5px 0 5px 0' }}
|
||||
variant="h6"
|
||||
className={styles.bold}
|
||||
>
|
||||
{profileName}
|
||||
</Typography>
|
||||
)}
|
||||
<Typography
|
||||
sx={{ margin: '5px 0 5px 0' }}
|
||||
variant="h6"
|
||||
className={styles.bold}
|
||||
>
|
||||
{profileName}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box>
|
||||
{textElementWithCopyIcon(
|
||||
@ -242,42 +202,34 @@ export const ProfilePage = () => {
|
||||
)}
|
||||
</Box>
|
||||
<Box>
|
||||
{profileMetadata?.nip05 &&
|
||||
textElementWithCopyIcon(
|
||||
profileMetadata.nip05,
|
||||
undefined,
|
||||
15
|
||||
)}
|
||||
{userProfile?.nip05 &&
|
||||
textElementWithCopyIcon(userProfile.nip05, undefined, 15)}
|
||||
</Box>
|
||||
<Box>
|
||||
{profileMetadata?.lud16 &&
|
||||
textElementWithCopyIcon(
|
||||
profileMetadata.lud16,
|
||||
undefined,
|
||||
15
|
||||
)}
|
||||
{userProfile?.lud16 &&
|
||||
textElementWithCopyIcon(userProfile.lud16, undefined, 15)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
{profileMetadata?.website && (
|
||||
{userProfile?.website && (
|
||||
<Typography
|
||||
sx={{ marginTop: '10px' }}
|
||||
variant="caption"
|
||||
component={Link}
|
||||
to={profileMetadata.website}
|
||||
to={userProfile.website}
|
||||
target="_blank"
|
||||
className={`${styles.website} ${styles.link} ${styles.captionWrapper}`}
|
||||
>
|
||||
{profileMetadata.website}
|
||||
{userProfile.website}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box>
|
||||
{profileMetadata?.about && (
|
||||
{userProfile?.about && (
|
||||
<Typography mt={1} className={styles.about}>
|
||||
{profileMetadata.about}
|
||||
{userProfile.about}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
|
@ -1,4 +1,11 @@
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import { SmartToy } from '@mui/icons-material'
|
||||
import ContentCopyIcon from '@mui/icons-material/ContentCopy'
|
||||
import LaunchIcon from '@mui/icons-material/Launch'
|
||||
import { LoadingButton } from '@mui/lab'
|
||||
import {
|
||||
Box,
|
||||
IconButton,
|
||||
@ -7,59 +14,53 @@ import {
|
||||
ListItem,
|
||||
ListSubheader,
|
||||
TextField,
|
||||
Tooltip,
|
||||
Typography,
|
||||
useTheme
|
||||
Tooltip
|
||||
} from '@mui/material'
|
||||
import { UnsignedEvent, nip19, kinds, VerifiedEvent, Event } from 'nostr-tools'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { Link, useParams } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
import { MetadataController, NostrController } from '../../../controllers'
|
||||
import { NostrJoiningBlock, ProfileMetadata } from '../../../types'
|
||||
import styles from './style.module.scss'
|
||||
|
||||
import {
|
||||
NDKEvent,
|
||||
NDKUserProfile,
|
||||
profileFromEvent,
|
||||
serializeProfile
|
||||
} from '@nostr-dev-kit/ndk'
|
||||
import { launch as launchNostrLoginDialog } from 'nostr-login'
|
||||
import { kinds, nip19, UnsignedEvent } from 'nostr-tools'
|
||||
|
||||
import { NostrController } from '../../../controllers'
|
||||
|
||||
import { useNDKContext } from '../../../hooks'
|
||||
import { useAppDispatch, useAppSelector } from '../../../hooks/store'
|
||||
|
||||
import { LoadingButton } from '@mui/lab'
|
||||
import { Dispatch } from '../../../store/store'
|
||||
import { setMetadataEvent } from '../../../store/actions'
|
||||
import { LoadingSpinner } from '../../../components/LoadingSpinner'
|
||||
import { LoginMethod, NostrLoginAuthMethod } from '../../../store/auth/types'
|
||||
import { SmartToy } from '@mui/icons-material'
|
||||
import {
|
||||
getNostrJoiningBlockNumber,
|
||||
getRoboHashPicture,
|
||||
unixNow
|
||||
} from '../../../utils'
|
||||
import { getRoboHashPicture, unixNow } from '../../../utils'
|
||||
|
||||
import { Container } from '../../../components/Container'
|
||||
import { Footer } from '../../../components/Footer/Footer'
|
||||
import LaunchIcon from '@mui/icons-material/Launch'
|
||||
import { launch as launchNostrLoginDialog } from 'nostr-login'
|
||||
import { LoadingSpinner } from '../../../components/LoadingSpinner'
|
||||
|
||||
import { setMetadataEvent } from '../../../store/actions'
|
||||
import { LoginMethod, NostrLoginAuthMethod } from '../../../store/auth/types'
|
||||
import { Dispatch } from '../../../store/store'
|
||||
|
||||
import styles from './style.module.scss'
|
||||
|
||||
export const ProfileSettingsPage = () => {
|
||||
const theme = useTheme()
|
||||
|
||||
const { npub } = useParams()
|
||||
|
||||
const dispatch: Dispatch = useAppDispatch()
|
||||
|
||||
const metadataController = MetadataController.getInstance()
|
||||
const nostrController = NostrController.getInstance()
|
||||
const { npub } = useParams()
|
||||
const { ndk, findMetadata, publish } = useNDKContext()
|
||||
|
||||
const [pubkey, setPubkey] = useState<string>()
|
||||
const [nostrJoiningBlock, setNostrJoiningBlock] =
|
||||
useState<NostrJoiningBlock | null>(null)
|
||||
const [profileMetadata, setProfileMetadata] = useState<ProfileMetadata>()
|
||||
const [savingProfileMetadata, setSavingProfileMetadata] = useState(false)
|
||||
const [userProfile, setUserProfile] = useState<NDKUserProfile | null>(null)
|
||||
|
||||
const userRobotImage = useAppSelector((state) => state.userRobotImage)
|
||||
const metadataState = useAppSelector((state) => state.metadata)
|
||||
const keys = useAppSelector((state) => state.auth?.keyPair)
|
||||
const { usersPubkey, loginMethod, nostrLoginAuthMethod } = useAppSelector(
|
||||
(state) => state.auth
|
||||
)
|
||||
const userRobotImage = useAppSelector((state) => state.userRobotImage)
|
||||
|
||||
const [savingProfileMetadata, setSavingProfileMetadata] = useState(false)
|
||||
const [isUsersOwnProfile, setIsUsersOwnProfile] = useState(false)
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [loadingSpinnerDesc] = useState('Fetching metadata')
|
||||
|
||||
@ -79,63 +80,33 @@ export const ProfileSettingsPage = () => {
|
||||
}, [npub, usersPubkey])
|
||||
|
||||
useEffect(() => {
|
||||
if (pubkey) {
|
||||
getNostrJoiningBlockNumber(pubkey)
|
||||
.then((res) => {
|
||||
setNostrJoiningBlock(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
// todo: handle error
|
||||
console.log('err :>> ', err)
|
||||
})
|
||||
}
|
||||
|
||||
if (isUsersOwnProfile && metadataState) {
|
||||
const metadataContent = metadataController.extractProfileMetadataContent(
|
||||
metadataState as VerifiedEvent
|
||||
)
|
||||
if (metadataContent) {
|
||||
setProfileMetadata(metadataContent)
|
||||
setIsLoading(false)
|
||||
}
|
||||
const ndkEvent = new NDKEvent(ndk, metadataState)
|
||||
const profile = profileFromEvent(ndkEvent)
|
||||
|
||||
setUserProfile(profile)
|
||||
|
||||
setIsLoading(false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (pubkey) {
|
||||
const getMetadata = async (pubkey: string) => {
|
||||
const handleMetadataEvent = (event: Event) => {
|
||||
const metadataContent =
|
||||
metadataController.extractProfileMetadataContent(event)
|
||||
if (metadataContent) {
|
||||
setProfileMetadata(metadataContent)
|
||||
}
|
||||
}
|
||||
|
||||
metadataController.on(pubkey, (kind: number, event: Event) => {
|
||||
if (kind === kinds.Metadata) {
|
||||
handleMetadataEvent(event)
|
||||
}
|
||||
findMetadata(pubkey)
|
||||
.then((profile) => {
|
||||
setUserProfile(profile)
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err)
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoading(false)
|
||||
})
|
||||
|
||||
const metadataEvent = await metadataController
|
||||
.findMetadata(pubkey)
|
||||
.catch((err) => {
|
||||
toast.error(err)
|
||||
return null
|
||||
})
|
||||
|
||||
if (metadataEvent) handleMetadataEvent(metadataEvent)
|
||||
|
||||
setIsLoading(false)
|
||||
}
|
||||
|
||||
getMetadata(pubkey)
|
||||
}
|
||||
}, [isUsersOwnProfile, metadataState, pubkey, metadataController])
|
||||
}, [ndk, isUsersOwnProfile, metadataState, pubkey, findMetadata])
|
||||
|
||||
const editItem = (
|
||||
key: keyof ProfileMetadata,
|
||||
key: keyof NDKUserProfile,
|
||||
label: string,
|
||||
multiline = false,
|
||||
rows = 1,
|
||||
@ -145,7 +116,7 @@ export const ProfileSettingsPage = () => {
|
||||
<TextField
|
||||
label={label}
|
||||
id={label.split(' ').join('-')}
|
||||
value={profileMetadata![key] || ''}
|
||||
value={userProfile![key] || ''}
|
||||
size="small"
|
||||
multiline={multiline}
|
||||
rows={rows}
|
||||
@ -155,7 +126,7 @@ export const ProfileSettingsPage = () => {
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { value } = event.target
|
||||
|
||||
setProfileMetadata((prev) => ({
|
||||
setUserProfile((prev) => ({
|
||||
...prev,
|
||||
[key]: value
|
||||
}))
|
||||
@ -197,32 +168,45 @@ export const ProfileSettingsPage = () => {
|
||||
)
|
||||
|
||||
const handleSaveMetadata = async () => {
|
||||
if (!userProfile) return
|
||||
|
||||
setSavingProfileMetadata(true)
|
||||
|
||||
const content = JSON.stringify(profileMetadata)
|
||||
const serializedProfile = serializeProfile(userProfile)
|
||||
|
||||
// We need to omit cachedAt and create new event
|
||||
// Relay will reject if created_at is too late
|
||||
const updatedMetadataState: UnsignedEvent = {
|
||||
content: content,
|
||||
const unsignedEvent: UnsignedEvent = {
|
||||
content: serializedProfile,
|
||||
created_at: unixNow(),
|
||||
kind: kinds.Metadata,
|
||||
pubkey: pubkey!,
|
||||
tags: metadataState?.tags || []
|
||||
tags: []
|
||||
}
|
||||
|
||||
const nostrController = NostrController.getInstance()
|
||||
const signedEvent = await nostrController
|
||||
.signEvent(updatedMetadataState)
|
||||
.signEvent(unsignedEvent)
|
||||
.catch((error) => {
|
||||
toast.error(`Error saving profile metadata. ${error}`)
|
||||
return null
|
||||
})
|
||||
|
||||
if (signedEvent) {
|
||||
if (!metadataController.validate(signedEvent)) {
|
||||
toast.error(`Metadata is not valid.`)
|
||||
}
|
||||
if (!signedEvent) {
|
||||
setSavingProfileMetadata(false)
|
||||
return
|
||||
}
|
||||
|
||||
await metadataController.publishMetadataEvent(signedEvent)
|
||||
const ndkEvent = new NDKEvent(ndk, signedEvent)
|
||||
const publishedOnRelays = await publish(ndkEvent)
|
||||
|
||||
// Handle cases where publishing failed or succeeded
|
||||
if (publishedOnRelays.length === 0) {
|
||||
toast.error('Failed to publish event on any relay')
|
||||
} else {
|
||||
toast.success(
|
||||
`Event published successfully to the following relays\n\n${publishedOnRelays.join(
|
||||
'\n'
|
||||
)}`
|
||||
)
|
||||
|
||||
dispatch(setMetadataEvent(signedEvent))
|
||||
}
|
||||
@ -241,7 +225,7 @@ export const ProfileSettingsPage = () => {
|
||||
|
||||
const robotAvatarLink = getRoboHashPicture(npub!, robotSet.current)
|
||||
|
||||
setProfileMetadata((prev) => ({
|
||||
setUserProfile((prev) => ({
|
||||
...prev,
|
||||
picture: robotAvatarLink
|
||||
}))
|
||||
@ -267,14 +251,14 @@ export const ProfileSettingsPage = () => {
|
||||
*
|
||||
* @returns robohash image url
|
||||
*/
|
||||
const getProfileImage = (metadata: ProfileMetadata) => {
|
||||
const getProfileImage = (profile: NDKUserProfile) => {
|
||||
if (!isUsersOwnProfile) {
|
||||
return metadata.picture || getRoboHashPicture(npub!)
|
||||
return profile.image || getRoboHashPicture(npub!)
|
||||
}
|
||||
|
||||
// userRobotImage is used only when visiting own profile
|
||||
// while kind 0 picture is not set
|
||||
return metadata.picture || userRobotImage || getRoboHashPicture(npub!)
|
||||
return profile.image || userRobotImage || getRoboHashPicture(npub!)
|
||||
}
|
||||
|
||||
return (
|
||||
@ -300,7 +284,7 @@ export const ProfileSettingsPage = () => {
|
||||
</ListSubheader>
|
||||
}
|
||||
>
|
||||
{profileMetadata && (
|
||||
{userProfile && (
|
||||
<div>
|
||||
<ListItem
|
||||
sx={{
|
||||
@ -309,10 +293,10 @@ export const ProfileSettingsPage = () => {
|
||||
flexDirection: 'column'
|
||||
}}
|
||||
>
|
||||
{profileMetadata.banner ? (
|
||||
{userProfile.banner ? (
|
||||
<img
|
||||
className={styles.bannerImg}
|
||||
src={profileMetadata.banner}
|
||||
src={userProfile.banner}
|
||||
alt="Banner Image"
|
||||
/>
|
||||
) : (
|
||||
@ -334,24 +318,9 @@ export const ProfileSettingsPage = () => {
|
||||
event.currentTarget.src = getRoboHashPicture(npub!)
|
||||
}}
|
||||
className={styles.img}
|
||||
src={getProfileImage(profileMetadata)}
|
||||
src={getProfileImage(userProfile)}
|
||||
alt="Profile Image"
|
||||
/>
|
||||
|
||||
{nostrJoiningBlock && (
|
||||
<Typography
|
||||
sx={{
|
||||
color: theme.palette.getContrastText(
|
||||
theme.palette.background.paper
|
||||
)
|
||||
}}
|
||||
component={Link}
|
||||
to={`https://njump.me/${nostrJoiningBlock.encodedEventPointer}`}
|
||||
target="_blank"
|
||||
>
|
||||
On nostr since {nostrJoiningBlock.block.toLocaleString()}
|
||||
</Typography>
|
||||
)}
|
||||
</ListItem>
|
||||
|
||||
{editItem('picture', 'Picture URL', undefined, undefined, {
|
||||
@ -368,6 +337,7 @@ export const ProfileSettingsPage = () => {
|
||||
<>
|
||||
{usersPubkey &&
|
||||
copyItem(nip19.npubEncode(usersPubkey), 'Public Key')}
|
||||
|
||||
{loginMethod === LoginMethod.privateKey &&
|
||||
keys &&
|
||||
keys.private &&
|
||||
|
Loading…
Reference in New Issue
Block a user