import { Event, Filter, kinds, nip19, UnsignedEvent } from 'nostr-tools' import { QRCodeSVG } from 'qrcode.react' import { useState } from 'react' import { Link } from 'react-router-dom' import { toast } from 'react-toastify' import { MetadataController, RelayController, UserRelaysType } from '../controllers' import { useAppSelector, useDidMount } from '../hooks' import { getProfilePageRoute } from '../routes' import '../styles/author.css' import '../styles/innerPage.css' import '../styles/socialPosts.css' import { UserProfile } from '../types' import { copyTextToClipboard, log, LogType, now } from '../utils' import { LoadingSpinner } from './LoadingSpinner' import { ZapPopUp } from './Zap' type Props = { pubkey: string } export const ProfileSection = ({ pubkey }: Props) => { const [profile, setProfile] = useState() useDidMount(async () => { const metadataController = await MetadataController.getInstance() metadataController.findMetadata(pubkey).then((res) => { setProfile(res) }) }) const handleCopy = async () => { copyTextToClipboard(profile?.npub as string).then((isCopied) => { if (isCopied) { toast.success('Npub copied to clipboard!') } else { toast.error( 'Failed to copy, look into console for more details on error!' ) } }) } if (!profile) return null const profileRoute = getProfilePageRoute( nip19.nprofileEncode({ pubkey }) ) return (

{profile.displayName || profile.name || ''}

{profile.nip05 || ''}

{profile.npub}

{profile.bio || profile.about}

{posts.map((post, index) => (

{post.name}

{post.content}

{post.imageUrl && (
)}
))}
) } interface Post { name: string link: string content: string imageUrl?: string } const posts: Post[] = [ { name: 'User name', link: `feed-note.html`, content: `user text, this is a long string of temporary text that would be replaced with the user post from their short posts` }, { name: 'User name', link: 'feed-note.html', content: `user text, this is a long string of temporary text that would be replaced with the user post from their short posts` }, { name: 'User name', link: `feed-note.html`, content: `user text, this is a long string of temporary text that would be replaced with the user post from their short posts`, imageUrl: '/assets/img/DEGMods%20Placeholder%20Img.png' } ] type QRButtonWithPopUpProps = { pubkey: string } const QRButtonWithPopUp = ({ pubkey }: QRButtonWithPopUpProps) => { const [isOpen, setIsOpen] = useState(false) const nprofile = nip19.nprofileEncode({ pubkey }) const onQrCodeClicked = async () => { const href = `https://njump.me/${nprofile}` const a = document.createElement('a') a.href = href a.target = '_blank' // Open in a new tab a.rel = 'noopener noreferrer' // Recommended for security reasons a.click() } return ( <>
setIsOpen(true)} >
{isOpen && (

Nostr Address

setIsOpen(false)} >
)} ) } type ZapButtonWithPopUpProps = { pubkey: string } const ZapButtonWithPopUp = ({ pubkey }: ZapButtonWithPopUpProps) => { const [isOpen, setIsOpen] = useState(false) return ( <>
setIsOpen(true)} >
{isOpen && ( setIsOpen(false)} /> )} ) } type FollowButtonProps = { pubkey: string } const FollowButton = ({ pubkey }: FollowButtonProps) => { const [isFollowing, setIsFollowing] = useState(false) const [isLoading, setIsLoading] = useState(false) const [loadingSpinnerDesc, setLoadingSpinnerDesc] = useState('') const userState = useAppSelector((state) => state.user) useDidMount(async () => { if (userState.auth && userState.user?.pubkey) { const userHexKey = userState.user.pubkey as string const { isFollowing: isAlreadyFollowing } = await checkIfFollowing( userHexKey, pubkey ) setIsFollowing(isAlreadyFollowing) } }) const getUserPubKey = async (): Promise => { if (userState.auth && userState.user?.pubkey) { return userState.user.pubkey as string } else { return (await window.nostr?.getPublicKey()) as string } } const checkIfFollowing = async ( userHexKey: string, pubkey: string ): Promise<{ isFollowing: boolean tags: string[][] }> => { const filter: Filter = { kinds: [kinds.Contacts], authors: [userHexKey] } const contactListEvent = await RelayController.getInstance().fetchEventFromUserRelays( filter, userHexKey, UserRelaysType.Both ) if (!contactListEvent) return { isFollowing: false, tags: [] } return { isFollowing: contactListEvent.tags.some( (t) => t[0] === 'p' && t[1] === pubkey ), tags: contactListEvent.tags } } const signAndPublishEvent = async ( unsignedEvent: UnsignedEvent ): Promise => { const signedEvent = await window.nostr ?.signEvent(unsignedEvent) .then((event) => event as Event) .catch((err) => { toast.error('Failed to sign the event!') log(true, LogType.Error, 'Failed to sign the event!', err) return null }) if (!signedEvent) return false const publishedOnRelays = await RelayController.getInstance().publish( signedEvent as Event ) if (publishedOnRelays.length === 0) { toast.error('Failed to publish event on any relay') return false } toast.success( `Event published successfully to the following relays\n\n${publishedOnRelays.join( '\n' )}` ) return true } const handleFollow = async () => { setIsLoading(true) setLoadingSpinnerDesc('Processing follow request') const userHexKey = await getUserPubKey() if (!userHexKey) { setIsLoading(false) toast.error('Could not get pubkey') return } const { isFollowing: isAlreadyFollowing, tags } = await checkIfFollowing( userHexKey, pubkey ) if (isAlreadyFollowing) { toast.info('Already following!') setIsFollowing(true) setIsLoading(false) return } const unsignedEvent: UnsignedEvent = { content: '', created_at: now(), kind: kinds.Contacts, pubkey: userHexKey, tags: [...tags, ['p', pubkey]] } setLoadingSpinnerDesc('Signing and publishing follow event') const success = await signAndPublishEvent(unsignedEvent) setIsFollowing(success) setIsLoading(false) } const handleUnFollow = async () => { setIsLoading(true) setLoadingSpinnerDesc('Processing unfollow request') const userHexKey = await getUserPubKey() if (!userHexKey) { setIsLoading(false) toast.error('Could not get pubkey') return } const filter: Filter = { kinds: [kinds.Contacts], authors: [userHexKey] } const contactListEvent = await RelayController.getInstance().fetchEventFromUserRelays( filter, userHexKey, UserRelaysType.Both ) if ( !contactListEvent || !contactListEvent.tags.some((t) => t[0] === 'p' && t[1] === pubkey) ) { // could not found target pubkey in user's follow list // so, just update the status and return setIsFollowing(false) setIsLoading(false) return } const unsignedEvent: UnsignedEvent = { content: '', created_at: now(), kind: kinds.Contacts, pubkey: userHexKey, tags: contactListEvent.tags.filter( (t) => !(t[0] === 'p' && t[1] === pubkey) ) } setLoadingSpinnerDesc('Signing and publishing unfollow event') const success = await signAndPublishEvent(unsignedEvent) setIsFollowing(!success) setIsLoading(false) } return ( <> {isLoading && } ) }