import ContentCopyIcon from '@mui/icons-material/ContentCopy' import EditIcon from '@mui/icons-material/Edit' import { Box, IconButton, SxProps, Theme, Typography } from '@mui/material' import { truncate } from 'lodash' import { Event, VerifiedEvent, kinds, nip19 } from 'nostr-tools' import { useEffect, useMemo, useState } from 'react' import { useSelector } from 'react-redux' import { Link, useNavigate, useParams } from 'react-router-dom' import { toast } from 'react-toastify' import { LoadingSpinner } from '../../components/LoadingSpinner' import { MetadataController } from '../../controllers' import { getProfileSettingsRoute } from '../../routes' import { State } from '../../store/rootReducer' import { NostrJoiningBlock, ProfileMetadata } from '../../types' import { getRoboHashPicture, hexToNpub, shorten } from '../../utils' import styles from './style.module.scss' export const ProfilePage = () => { const navigate = useNavigate() const { npub } = useParams() const metadataController = useMemo(() => new MetadataController(), []) const [pubkey, setPubkey] = useState() const [nostrJoiningBlock, setNostrJoiningBlock] = useState(null) const [profileMetadata, setProfileMetadata] = useState() const metadataState = useSelector((state: State) => state.metadata) const { usersPubkey } = useSelector((state: State) => state.auth) const userRobotImage = useSelector((state: State) => state.userRobotImage) const [isUsersOwnProfile, setIsUsersOwnProfile] = useState(false) const [isLoading, setIsLoading] = useState(true) const [loadingSpinnerDesc] = useState('Fetching metadata') useEffect(() => { if (npub) { try { const hexPubkey = nip19.decode(npub).data as string setPubkey(hexPubkey) if (hexPubkey === usersPubkey) setIsUsersOwnProfile(true) } catch (error) { toast.error('Error occurred in decoding npub' + error) } } }, [npub, usersPubkey]) useEffect(() => { if (pubkey) { metadataController .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) } 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) } }) 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]) /** * Rendering text with button which copies the provided text * @param text to be visible * @param sx props (MUI) to customize style * @returns HTML rendered text */ const textElementWithCopyIcon = ( text: string, sx?: SxProps, shortenOffset?: number ) => { const onClick = () => { navigator.clipboard.writeText(text) toast.success('Copied to clipboard', { autoClose: 1000, hideProgressBar: true }) } return ( {shorten(text, shortenOffset)} ) } /** * Handles the logic for Image URL. * If no picture in kind 0 found - use robohash avatar * * @returns robohash image url */ const getProfileImage = (metadata: ProfileMetadata) => { if (!metadata) return '' if (!isUsersOwnProfile) { return metadata.picture || getRoboHashPicture(npub!) } // userRobotImage is used only when visiting own profile // while kind 0 picture is not set return metadata.picture || userRobotImage || getRoboHashPicture(npub!) } return ( <> {isLoading && } {pubkey && ( {profileMetadata && profileMetadata.banner ? ( ) : ( '' )}
{nostrJoiningBlock ? `On nostr since ${nostrJoiningBlock.block.toLocaleString()}` : 'On nostr since: unknown'} {isUsersOwnProfile && ( navigate(getProfileSettingsRoute(pubkey))} > )}
{profileMetadata && ( {truncate( profileMetadata.display_name || profileMetadata.name || hexToNpub(pubkey), { length: 16 } )} )} {textElementWithCopyIcon( hexToNpub(pubkey) || '', undefined, 15 )} {profileMetadata?.nip05 && textElementWithCopyIcon( profileMetadata.nip05, undefined, 15 )} {profileMetadata?.lud16 && textElementWithCopyIcon( profileMetadata.lud16, undefined, 15 )} {profileMetadata?.website && ( {profileMetadata.website} )} {profileMetadata?.about && ( {profileMetadata.about} )}
)} ) }