import "@/styles/Profile.css"; import "@/styles/UserModal.css"; import Modal from "./Modal"; import Avatar from "../Avatar"; import Icon from "@/components/Icon"; import useLocalState from "@/state/state"; import { useLocation } from "wouter"; import toast from "react-hot-toast"; import { generateNprofile } from "@/logic/nostr"; import { useEffect, useState } from "react"; import type { UserType } from "@/types/nostrill"; export default function ({ user }: { user: UserType }) { const { setModal, api, lastFact, pubkey, profiles, following, followers } = useLocalState((s) => ({ setModal: s.setModal, api: s.api, pubkey: s.pubkey, profiles: s.profiles, following: s.following, followers: s.followers, lastFact: s.lastFact, })); const [_, navigate] = useLocation(); const [isLoading, setLoading] = useState(false); function close() { setModal(null); } const itsMe = "urbit" in user ? user.urbit === api?.airlock.our : "nostr" in user ? user.nostr === pubkey : false; const userString = "urbit" in user ? user.urbit : user.nostr; const profile = profiles.get(userString); const isFollowing = following.has(userString); const isFollower = followers.includes(userString); // Get follower/following counts from the user's feed if available const userFeed = following.get(userString); const postCount = userFeed ? Object.keys(userFeed.feed).length : 0; // useEffect(() => { // if (!lastFact) return; // if (!("fols" in lastFact)) return; // if (!("new" in lastFact.fols)) return; // if (lastFact.fols.new.user === userString) setLoading(false); // const name = profile?.name || userString; // toast.success(`Followed ${name}`); // }, [lastFact]); async function copy(e: React.MouseEvent) { e.stopPropagation(); await navigator.clipboard.writeText(userString); toast.success("Copied to clipboard"); } async function handleFollow(e: React.MouseEvent) { if ("error" in user) return; e.stopPropagation(); if (!api) return; setLoading(true); try { if (isFollowing) { const result = await api.unfollow(user); console.log(result); // if ("ok" in result) { // toast.success(`Unfollowed ${profile?.name || userString}`); // } else { // toast.error(result.error); // } } else { const result = await api.follow(user); console.log(result); // if ("ok" in result) { // toast.success(`Following ${profile?.name || userString}`); // } else { // toast.error(result.error); // } } } catch (err) { toast.error("Action failed"); } finally { // setLoading(false); } } async function handleAvatarClick(e: React.MouseEvent) { e.stopPropagation(); if ("nostr" in user) { const nprof = generateNprofile(userString); const href = `https://primal.net/p/${nprof}`; window.open(href, "_blank"); } } const displayName = profile?.name || ("urbit" in user ? user.urbit : "Anon"); const truncatedId = userString.length > 20 ? `${userString.slice(0, 10)}...${userString.slice(-8)}` : userString; // Get banner image from profile.other const bannerImage = profile?.other?.banner || profile?.other?.Banner; // Filter out banner from other fields since we display it separately const otherFields = profile?.other ? Object.entries(profile.other).filter( ([key]) => key.toLowerCase() !== "banner", ) : []; return ( {/* Banner Image */} {bannerImage && ( )} {/* Header with Avatar and Basic Info */} {displayName} {"urbit" in user ? user.urbit : truncatedId} {/* User type badge */} {"urbit" in user ? ( Urbit ) : ( Nostr )} {itsMe && You} {isFollower && !itsMe && ( Follows you )} {/* Profile About Section */} {profile?.about && ( {profile.about} )} {/* Stats */} {postCount > 0 && ( {postCount} Posts )} {/* Additional stats could go here */} {/* Custom Fields */} {otherFields.length > 0 && ( Additional Info {otherFields.map(([key, value]) => { console.log({ key, value }); return ( {key}: ); })} )} {/* Action Buttons */} {!itsMe && ( {isLoading ? "..." : isFollowing ? "Following" : "Follow"} )} <> { navigate(`/u/${userString}`); close(); }} > View Feed > {"nostr" in user ? ( View on Primal ) : null} ); } // Check if a string is a URL const isURL = (str: string): boolean => { if (!str) return false; try { new URL(str); return true; } catch { return false; } }; export function ProfValue({ value }: { value: any }) { if (typeof value === "string") return isURL(value) ? ( e.stopPropagation()} > {value} ) : ( {value} ); else if (typeof value === "number") return {value}; else if (typeof value === "object") return {JSON.stringify(value)}; else return {JSON.stringify(value)}; }
{profile.about}