import React, { useEffect, useState } from 'react' import { createPortal } from 'react-dom' function galleryUrlFor(author) { if (!author?.username) return null return `/@${author.username}/gallery` } export default function AuthorBioPopover({ author }) { const [open, setOpen] = useState(false) const [loading, setLoading] = useState(false) const [bio, setBio] = useState(undefined) const [error, setError] = useState('') const username = author?.username || '' const profileUrl = author?.profile_url || (username ? `/@${username}` : null) const galleryUrl = galleryUrlFor(author) useEffect(() => { if (!open) return undefined function onKeyDown(event) { if (event.key === 'Escape') { setOpen(false) } } document.addEventListener('keydown', onKeyDown) const previousOverflow = document.body.style.overflow document.body.style.overflow = 'hidden' return () => { document.removeEventListener('keydown', onKeyDown) document.body.style.overflow = previousOverflow } }, [open]) async function loadBio() { if (!username || loading || bio !== undefined) { return } setLoading(true) setError('') try { const response = await fetch(`/api/profile/${encodeURIComponent(username)}/ai-biography`, { credentials: 'same-origin', headers: { Accept: 'application/json', 'X-Requested-With': 'XMLHttpRequest', }, }) if (!response.ok) { throw new Error(`Failed to load biography (${response.status})`) } const payload = await response.json() setBio(payload?.data?.text || null) } catch { setError('Biography is unavailable right now.') setBio(null) } finally { setLoading(false) } } if (!username || !profileUrl) { return null } const dialog = open ? createPortal(