"use client"; /** * Public profile at /u/[handle]. * * Anonymous-friendly. Mirrors /u/me's shell — ProfileHeader at the top, * a smaller tab strip (Posts + Collections only; Bookmarks and Mentions * are private), then a grid of the active tab's content. * * Owner-handle redirect: when the logged-in user lands on their own * /u/, we send them to /u/me where the owner controls live. */ import { use, useEffect, useState } from "react"; import Link from "next/link"; import { notFound, useRouter } from "next/navigation"; import { FolderClosed, LayoutGrid } from "lucide-react"; import { profile, SocialError, type Post, type PublicProfile, } from "@/lib/social"; import { ProfileHeader } from "@/components/profile/profile-header"; import { ProfileTabs, type ProfileTab, } from "@/components/profile/profile-tabs"; import { PostViews } from "@/components/social/post-views"; import { CollectionViews } from "@/components/social/collection-views"; import { useAuth } from "@/components/auth/auth-provider"; type Tab = "posts" | "collections"; export default function PublicProfilePage(props: { params: Promise<{ handle: string }>; searchParams?: Promise<{ tab?: string }>; }) { const { handle } = use(props.params); const search = props.searchParams ? use(props.searchParams) : undefined; const tab: Tab = search?.tab === "collections" ? "collections" : "posts"; const router = useRouter(); const { user } = useAuth(); const [data, setData] = useState(null); const [feed, setFeed] = useState([]); const [loading, setLoading] = useState(true); const [notFoundState, setNotFound] = useState(false); const isOwn = !!user && user.handle.toLowerCase() === handle.toLowerCase(); useEffect(() => { if (isOwn) router.replace("/u/me"); }, [isOwn, router]); useEffect(() => { if (isOwn) return; let cancelled = false; setLoading(true); Promise.all([profile.get(handle), profile.feed(handle, 30)]) .then(([p, posts]) => { if (cancelled) return; setData(p); setFeed(posts ?? []); }) .catch((err) => { if (err instanceof SocialError && err.status === 404) { setNotFound(true); } }) .finally(() => !cancelled && setLoading(false)); return () => { cancelled = true; }; }, [handle, isOwn]); if (notFoundState) notFound(); if (isOwn) return null; if (loading || !data) { return (

Loading profile…

); } const tabs: ProfileTab[] = [ { href: `/u/${data.handle}`, label: "Posts", icon: , }, { href: `/u/${data.handle}?tab=collections`, label: "Collections", icon: , }, ]; return (
{tab === "collections" ? ( data.public_collections && data.public_collections.length > 0 ? ( `/c/${c.id}`} /> ) : (

No public collections yet.

) ) : ( `/u/${data.handle}/posts#post-${p.id}`} emptyMessage="No posts yet — quotes shared by this user will appear here." /> )}
); }