"use client"; /** * /u/me shared layout — auth gate + Instagram-style profile shell. * * • Anonymous visitors trigger the global AuthModal and are bounced * home if they dismiss it (unchanged from before). * • Renders the ProfileHeader + ProfileTabs above every /u/me/* page. * Tabs: Posts / Collections / Bookmarks / Mentions. * * The old left ProfileSidebar is gone. The "Edit profile" affordance * moved onto the header as a button that toggles edit mode on /u/me * via a query param (kept simple — no new route for the form). */ import { Suspense, useEffect } from "react"; import { useRouter, useSearchParams } from "next/navigation"; import { AtSign, Bookmark, FolderClosed, LayoutGrid, } from "lucide-react"; import { useAuth } from "@/components/auth/auth-provider"; import { useAuthGate } from "@/components/auth/auth-gate"; import { ProfileHeader } from "@/components/profile/profile-header"; import { ProfileTabs, type ProfileTab } from "@/components/profile/profile-tabs"; export default function MeLayout({ children }: { children: React.ReactNode }) { const { user, loading } = useAuth(); const { requireAuth } = useAuthGate(); const router = useRouter(); useEffect(() => { if (loading || user) return; let cancelled = false; (async () => { const ok = await requireAuth(); if (!ok && !cancelled) router.replace("/"); })(); return () => { cancelled = true; }; }, [loading, user, requireAuth, router]); if (loading || !user) { return (

{loading ? "Loading…" : "Sign in to view your library."}

); } const tabs: ProfileTab[] = [ { href: "/u/me", label: "Posts", icon: , activeFor: ["/u/me/posts"], }, { href: "/u/me/collections", label: "Collections", icon: , }, { href: "/u/me/bookmarks", label: "Bookmarks", icon: , }, { href: "/u/me/mentions", label: "Mentions", icon: , }, ]; return (
{/* Tab strip hides on /u/me?edit=1 (see ConditionalTabs). The Suspense boundary is required by Next.js because useSearchParams forces a CSR bailout during prerender. Without it, every /u/me/* route fails to build. Fallback renders the tabs as-is so the visual default (tabs visible) is what users see while the search params resolve. */} }>
{children}
); } function ConditionalTabs({ tabs }: { tabs: ProfileTab[] }) { const searchParams = useSearchParams(); // /u/me?edit=1 swaps the Posts grid for the inline edit form (see // app/u/me/page.tsx). The tab strip would just be in the way while the // user is editing — hide it for that one URL state. const editMode = searchParams.get("edit") === "1"; return editMode ? null : ; }