import ContentCopyIcon from '@mui/icons-material/ContentCopy' import { List, ListItem, ListSubheader, TextField } from '@mui/material' import { UnsignedEvent, nip19, kinds, VerifiedEvent } from 'nostr-tools' import { useEffect, useMemo, useState } from 'react' import { useParams } from 'react-router-dom' import { toast } from 'react-toastify' import placeholderAvatar from '../../assets/images/nostr-logo.jpg' import { MetadataController, NostrController } from '../../controllers' import { ProfileMetadata } from '../../types' import styles from './style.module.scss' import { useDispatch, useSelector } from 'react-redux' import { State } from '../../store/rootReducer' import { LoadingButton } from '@mui/lab' import { Dispatch } from '../../store/store' import { setMetadataEvent } from '../../store/actions' import { LoadingSpinner } from '../../components/LoadingSpinner' export const ProfilePage = () => { const { npub } = useParams() const dispatch: Dispatch = useDispatch() const metadataController = useMemo(() => new MetadataController(), []) const nostrController = NostrController.getInstance() const [pubkey, setPubkey] = useState() const [profileMetadata, setProfileMetadata] = useState() const [savingProfileMetadata, setSavingProfileMetadata] = useState(false) const metadataState = useSelector((state: State) => state.metadata) const keys = useSelector((state: State) => state.auth?.keyPair) const usersPubkey = useSelector((state: State) => state.auth.usersPubkey) 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 (isUsersOwnProfile && metadataState) { const metadataContent = metadataController.extractProfileMetadataContent( metadataState as VerifiedEvent ) if (metadataContent) { setProfileMetadata(metadataContent) setIsLoading(false) } return } if (pubkey) { const getMetadata = async (pubkey: string) => { const metadataEvent = await metadataController .findMetadata(pubkey) .catch((err) => { toast.error(err) return null }) if (metadataEvent) { const metadataContent = metadataController.extractProfileMetadataContent(metadataEvent) if (metadataContent) setProfileMetadata(metadataContent) } setIsLoading(false) } getMetadata(pubkey) } }, [isUsersOwnProfile, metadataState, pubkey, metadataController]) const editItem = ( key: keyof ProfileMetadata, label: string, multiline = false, rows = 1 ) => ( ) => { const { value } = event.target setProfileMetadata((prev) => ({ ...prev, [key]: value })) }} /> ) const copyItem = ( value: string, label: string, copyValue?: string, isPassword = false ) => ( { navigator.clipboard.writeText(copyValue || value) toast.success('Copied to clipboard', { autoClose: 1000, hideProgressBar: true }) }} > ) const handleSaveMetadata = async () => { setSavingProfileMetadata(true) const content = JSON.stringify(profileMetadata) // We need to omit cachedAt and create new event // Relay will reject if created_at is too late const updatedMetadataState: UnsignedEvent = { content: content, created_at: Math.round(Date.now() / 1000), kind: kinds.Metadata, pubkey: pubkey!, tags: metadataState?.tags || [] } const signedEvent = await nostrController .signEvent(updatedMetadataState) .catch((error) => { toast.error(`Error saving profile metadata. ${error}`) }) if (signedEvent) { if (!metadataController.validate(signedEvent)) { toast.error(`Metadata is not valid.`) } await metadataController.publishMetadataEvent(signedEvent) dispatch(setMetadataEvent(signedEvent)) } setSavingProfileMetadata(false) } return ( <> {isLoading && }
Profile Settings } > {profileMetadata && (
{ event.target.src = placeholderAvatar }} className={styles.img} src={profileMetadata.picture || placeholderAvatar} alt='Profile Image' /> {editItem('name', 'Username')} {editItem('display_name', 'Display Name')} {editItem('nip05', 'Nostr Address (nip05)')} {editItem('lud16', 'Lightning Address (lud16)')} {editItem('about', 'About', true, 4)} {isUsersOwnProfile && ( <> {keys && keys.public && copyItem(keys.public, 'Public Key')} {keys && keys.private && copyItem( '••••••••••••••••••••••••••••••••••••••••••••••••••', 'Private Key', keys.private )} )}
)}
{isUsersOwnProfile && ( SAVE )}
) }