78 lines
2.2 KiB
TypeScript
78 lines
2.2 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* /u/[handle]/collections/[id] — single public-collection view for another
|
|
* user's profile. Mirrors the auth user's /u/me/collections/[id] exactly —
|
|
* the CollectionScrollCard carousel (cover + posts) — but read-only: no Edit
|
|
* affordance, since the viewer doesn't own it. Private collections (or a bad
|
|
* id) 403/404 from the BFF, which we treat as "not found".
|
|
*/
|
|
|
|
import { use, useEffect, useState } from "react";
|
|
import Link from "next/link";
|
|
import { notFound } from "next/navigation";
|
|
import { ArrowLeft } from "lucide-react";
|
|
import {
|
|
collections,
|
|
SocialError,
|
|
type Collection,
|
|
type Post,
|
|
} from "@/lib/social";
|
|
import { CollectionScrollCard } from "@/components/social/collection/collection-scroll-card";
|
|
|
|
export default function PublicCollectionDetailPage(props: {
|
|
params: Promise<{ handle: string; id: string }>;
|
|
}) {
|
|
const { handle, id } = use(props.params);
|
|
|
|
const [c, setC] = useState<Collection | null>(null);
|
|
const [posts, setPosts] = useState<Post[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [missing, setMissing] = useState(false);
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
collections
|
|
.get(id)
|
|
.then(({ collection, posts }) => {
|
|
if (cancelled) return;
|
|
setC(collection);
|
|
setPosts(posts ?? []);
|
|
})
|
|
.catch((err) => {
|
|
if (cancelled) return;
|
|
if (
|
|
err instanceof SocialError &&
|
|
(err.status === 404 || err.status === 403)
|
|
) {
|
|
setMissing(true);
|
|
}
|
|
})
|
|
.finally(() => !cancelled && setLoading(false));
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [id]);
|
|
|
|
if (missing) notFound();
|
|
if (loading) return <p className="text-sm text-muted-foreground">Loading…</p>;
|
|
if (!c) return null;
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<Link
|
|
href={`/u/${handle}/collections`}
|
|
className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground"
|
|
>
|
|
<ArrowLeft className="size-4" /> All collections
|
|
</Link>
|
|
|
|
<CollectionScrollCard
|
|
collection={c}
|
|
href={`/u/${handle}/collections/${c.id}`}
|
|
initialPosts={posts}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|