import "./ProfilePage.css"; import { useMemo, useRef, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { bech32 } from "bech32"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faQrcode } from "@fortawesome/free-solid-svg-icons"; import { useParams } from "react-router-dom"; import useProfile from "../feed/ProfileFeed"; import { resetProfile } from "../state/Users"; import Nostrich from "../nostrich.jpg"; import useEventPublisher from "../feed/EventPublisher"; import useTimelineFeed from "../feed/TimelineFeed"; import Note from "../element/Note"; import QRCodeStyling from "qr-code-styling"; import Modal from "../element/Modal"; import { logout } from "../state/Login"; import FollowButton from "../element/FollowButton"; import VoidUpload from "../feed/VoidUpload"; import { openFile } from "../Util"; export default function ProfilePage() { const dispatch = useDispatch(); const params = useParams(); const id = params.id; const user = useProfile(id); const publisher = useEventPublisher(); const { notes } = useTimelineFeed(id); const loginPubKey = useSelector(s => s.login.publicKey); const isMe = loginPubKey === id; const qrRef = useRef(); const [name, setName] = useState(""); const [picture, setPicture] = useState(""); const [about, setAbout] = useState(""); const [website, setWebsite] = useState(""); const [nip05, setNip05] = useState(""); const [lud16, setLud16] = useState(""); const [showLnQr, setShowLnQr] = useState(false); useMemo(() => { if (user) { setName(user.name ?? ""); setPicture(user.picture ?? ""); setAbout(user.about ?? ""); setWebsite(user.website ?? ""); setNip05(user.nip05 ?? ""); setLud16(user.lud16 ?? ""); } }, [user]); useMemo(() => { // some clients incorrectly set this to LNURL service, patch this if (lud16.toLowerCase().startsWith("lnurl")) { let decoded = bech32.decode(lud16, 1000); let url = new TextDecoder().decode(Uint8Array.from(bech32.fromWords(decoded.words))); if (url.startsWith("http")) { let parsedUri = new URL(url); // is lightning address if (parsedUri.pathname.startsWith("/.well-known/lnurlp/")) { let pathParts = parsedUri.pathname.split('/'); let username = pathParts[pathParts.length - 1]; setLud16(`${username}@${parsedUri.hostname}`); } } } }, [lud16]); useMemo(() => { if (qrRef.current && showLnQr) { let qr = new QRCodeStyling({ data: { lud16 }, type: "canvas" }); qrRef.current.innerHTML = ""; qr.append(qrRef.current); } }, [showLnQr]); async function saveProfile() { // copy user object and delete internal fields let userCopy = { ...user, name, about, picture, website, nip05, lud16 }; delete userCopy["loaded"]; delete userCopy["fromEvent"]; // event top level props should not be copied into metadata (bug) delete userCopy["pubkey"]; delete userCopy["sig"]; delete userCopy["pubkey"]; delete userCopy["tags"]; delete userCopy["content"]; delete userCopy["created_at"]; delete userCopy["id"]; delete userCopy["kind"] // trim empty string fields Object.keys(userCopy).forEach(k => { if (userCopy[k] === "") { delete userCopy[k]; } }); console.debug(userCopy); let ev = await publisher.metadata(userCopy); console.debug(ev); publisher.broadcast(ev); } async function setNewAvatar() { let file = await openFile(); console.log(file); let rsp = await VoidUpload(file); if (!rsp) { throw "Upload failed, please try again later"; } console.log(rsp); setPicture(rsp.metadata.url ?? `https://void.cat/d/${rsp.id}`) } function editor() { return (
Name:
setName(e.target.value)} />
About:
Website:
setWebsite(e.target.value)} />
NIP-05:
setNip05(e.target.value)} />
LN Address:
setLud16(e.target.value)} />
dispatch(logout())}>Logout
saveProfile()}>Save
) } function details() { return ( <>

{name}

{about}

{website ? {website} : null} {lud16 ?
setShowLnQr(true)}>
  ⚡️ {lud16.length > 20 ? lud16.substring(0, 20) : lud16}
: null} {showLnQr === true ? setShowLnQr(false)}>

{lud16}

: null} ) } return ( <>
{isMe ?
setNewAvatar()}>
Edit
: null }
{isMe ? editor() : details()}
Notes
Reactions
Followers
Follows
Relays
{notes?.sort((a, b) => b.created_at - a.created_at).map(a => )} ) }