Files
spsays-training/app/(app)/u/me/page.tsx
T

85 lines
2.8 KiB
TypeScript

"use client";
/**
* /u/me — owner Posts grid (the default tab).
*
* Window-virtualised, infinite-scroll 2-up grid (usePostScrollFeed keyset-pages
* the owner's posts; VirtualPostGrid renders + windows them). Tapping a
* thumbnail jumps to /u/me/posts#post-<id> where the scroll feed renders the
* full passages.
*
* Editing the profile lives on its own page (/settings/profile), reached
* from the header's "Edit profile" button.
*/
import { useState } from "react";
import { useAuth } from "@/components/auth/auth-provider";
import { VirtualPostGrid } from "@/components/social/post/virtual-post-grid";
import { usePostScrollFeed } from "@/components/social/post/use-post-scroll-feed";
import { ConfirmModal } from "@/components/ui/confirm-modal";
import { posts, SocialError, type Post } from "@/lib/social";
export default function MyProfilePage() {
const { user } = useAuth();
// Defer the authed /posts/mine fetch until we have a user.
if (!user) return null;
return <OwnerGrid />;
}
function OwnerGrid() {
const { feed, setFeed, loading, hasMore, error, setError, sentinelRef } =
usePostScrollFeed(
(before, limit) => posts.mine({ limit, before: before ?? undefined }),
24,
);
const [pendingDelete, setPendingDelete] = useState<string | null>(null);
// Card delete buttons stage an id; ConfirmModal runs `performDelete` when the
// user confirms. We throw on failure so the modal stays open with an error.
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)));
}
return (
<section>
{error ? <p className="mb-3 text-sm text-destructive">{error}</p> : null}
<VirtualPostGrid
posts={feed}
loading={loading}
hasMore={hasMore}
sentinelRef={sentinelRef}
hrefFor={(p) => `/u/me/posts#post-${p.id}`}
onDelete={(id) => setPendingDelete(id)}
onUpdated={onPostUpdated}
emptyMessage="You haven't posted anything yet. Select any passage in the knowledgebase and use the toolbar to share it to your feed."
/>
<ConfirmModal
open={!!pendingDelete}
onClose={() => 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}
/>
</section>
);
}