"use client"; /** * /u/me — owner Posts grid (the default tab). * * Grid-only — no Grid/Scroll toggle. Tapping a thumbnail jumps to * /u/me/posts#post- where the Instagram-style scroll feed renders * the full passages. * * `?edit=1` (set by the header's Edit profile button) swaps the grid * for the inline edit form. Saving returns to /u/me. Keeps the URL * shareable while avoiding a separate route + layout. */ import { Suspense, useEffect, useState } from "react"; import { useRouter, useSearchParams } from "next/navigation"; import { LayoutGrid } from "lucide-react"; import { useAuth } from "@/components/auth/auth-provider"; import { ProfileEditForm } from "@/components/profile/profile-edit-form"; import { PostGridCard } from "@/components/social/post-grid-card"; import { ConfirmModal } from "@/components/ui/confirm-modal"; import { posts, SocialError, type Post } from "@/lib/social"; export default function MyProfilePage() { // useSearchParams() forces a CSR bailout during prerender; the // Suspense boundary is required by Next.js so the build doesn't fail // (the same wrapping is in app/u/me/layout.tsx for its own check). // The fallback matches the page's idle loading state so the brief // moment before search params resolve doesn't flash an empty section. return ( Loading…

} >
); } function MyProfilePageInner() { const { user } = useAuth(); const router = useRouter(); const searchParams = useSearchParams(); const editMode = searchParams.get("edit") === "1"; const [feed, setFeed] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // Post id pending confirmation — modal opens when non-null and runs // the actual delete on confirm. const [pendingDelete, setPendingDelete] = useState(null); useEffect(() => { if (!user) return; posts .mine() .then((rows) => setFeed(rows ?? [])) .catch((err) => setError( err instanceof SocialError ? err.message : "Could not load posts.", ), ) .finally(() => setLoading(false)); }, [user]); // Card delete buttons stage an id; ConfirmModal runs `performDelete` // when the user confirms. We throw on failure so the modal stays open // with an inline error message. async function performDelete() { const id = pendingDelete; if (!id) return; const prev = feed; setFeed((rows) => rows.filter((p) => p.id !== id)); try { await posts.delete(id); } catch (err) { setFeed(prev); const msg = err instanceof SocialError ? err.message : "Could not delete."; setError(msg); throw new Error(msg); } } function onPostUpdated(updated: Post) { setFeed((rows) => rows.map((p) => (p.id === updated.id ? updated : p))); } if (!user) return null; if (editMode) { return router.replace("/u/me")} />; } return (
{error ? (

{error}

) : loading ? (

Loading…

) : feed.length === 0 ? ( ) : (
{feed.map((p) => ( setPendingDelete(id)} onUpdated={onPostUpdated} href={`/u/me/posts#post-${p.id}`} /> ))}
)} setPendingDelete(null)} title="Delete this post?" message="The post will be removed permanently from your feed and from any collections it's in. This can't be undone." confirmLabel="Delete post" onConfirm={performDelete} />
); } function EmptyPosts() { return (

You haven't posted anything yet. Select any passage in the knowledgebase and use the toolbar to share it to your feed.

); }