feat: hide post

This commit is contained in:
gosangam
2026-06-14 19:52:16 +05:30
parent 7585e6cb31
commit 79f0bd9223
5 changed files with 154 additions and 2 deletions
+76
View File
@@ -0,0 +1,76 @@
"use client";
/**
* /u/me/hidden — the owner's hidden posts.
*
* Posts hidden from timelines + public collections live here (and in any
* private collections). Each card's overflow menu offers "Unhide from
* timeline"; on unhide we drop the post from this list since it's no longer
* hidden. The tab itself is only shown (by the /u/me layout) when the user
* has at least one hidden post.
*/
import { useEffect, useState } from "react";
import { useAuth } from "@/components/auth/auth-provider";
import { PostScrollCard } from "@/components/social/post/post-scroll-card";
import { posts, SocialError, type Post } from "@/lib/social";
export default function MyHiddenPostsPage() {
const { user } = useAuth();
const [feed, setFeed] = useState<Post[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (!user) return;
posts
.hidden()
.then((rows) => setFeed(rows ?? []))
.catch((err) =>
setError(
err instanceof SocialError
? err.message
: "Could not load hidden posts.",
),
)
.finally(() => setLoading(false));
}, [user]);
function onPostUpdated(updated: Post) {
setFeed((rows) => rows.map((p) => (p.id === updated.id ? updated : p)));
}
// Unhiding a post means it's no longer hidden → remove it from this list.
function onHiddenChange(id: string, hidden: boolean) {
if (!hidden) setFeed((rows) => rows.filter((p) => p.id !== id));
}
if (!user) return null;
return (
<div className="max-w-xl w-full mx-auto space-y-6">
<p className="text-sm text-muted-foreground">
Hidden posts don&apos;t appear on your timeline, in the feed, or in
public collections — but stay in your private collections. Use a card&apos;s
menu to unhide.
</p>
{error ? (
<p className="text-sm text-destructive">{error}</p>
) : loading ? (
<p className="text-sm text-muted-foreground">Loading…</p>
) : feed.length === 0 ? (
<p className="text-sm text-muted-foreground">No hidden posts.</p>
) : (
feed.map((p) => (
<PostScrollCard
key={p.id}
post={p}
onUpdated={onPostUpdated}
onHiddenChange={onHiddenChange}
/>
))
)}
</div>
);
}
+12
View File
@@ -18,6 +18,7 @@ import { useRouter, useSearchParams } from "next/navigation";
import {
AtSign,
Bookmark,
EyeOff,
FolderClosed,
LayoutGrid,
} from "lucide-react";
@@ -51,6 +52,7 @@ export default function MeLayout({ children }: { children: React.ReactNode }) {
posts: number;
followers: number;
following: number;
hidden: number;
} | null>(null);
const handle = user?.handle;
useEffect(() => {
@@ -64,6 +66,7 @@ export default function MeLayout({ children }: { children: React.ReactNode }) {
posts: p.post_count,
followers: p.follower_count,
following: p.following_count,
hidden: p.hidden_count ?? 0,
});
}
})
@@ -109,6 +112,15 @@ export default function MeLayout({ children }: { children: React.ReactNode }) {
},
];
// Surface the "Hidden" tab only when the user actually has hidden posts.
if ((counts?.hidden ?? 0) > 0) {
tabs.push({
href: "/u/me/hidden",
label: "Hidden",
icon: <EyeOff className="size-5" />,
});
}
return (
<main className="flex-1 max-w-3xl w-full mx-auto px-4 sm:px-6">
<ProfileHeader