feat(social): follows, favorites, comments, reactions, collections, public profiles

Follow/unfollow users. Recipe favorites. Threaded comments with emoji reactions.
Collections (public/private) with shared member invite. Activity feed.
Public profile pages at /u/[username].
This commit is contained in:
Arnaud
2026-07-01 08:10:30 +02:00
parent d9d58fd01a
commit 9d02a69250
23 changed files with 1825 additions and 0 deletions
@@ -0,0 +1,42 @@
"use client";
import { useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
export function FollowButton({
targetUserId: _targetUserId,
targetUsername,
initialFollowing = false,
}: {
targetUserId: string;
targetUsername: string;
initialFollowing?: boolean;
}) {
const [following, setFollowing] = useState(initialFollowing);
const [loading, setLoading] = useState(false);
async function toggle() {
setLoading(true);
try {
const res = await fetch(`/api/v1/users/${targetUsername}/follow`, {
method: following ? "DELETE" : "POST",
});
if (!res.ok) {
const err = await res.json() as { error?: string };
toast.error(err.error ?? "Failed");
return;
}
setFollowing(!following);
toast.success(following ? "Unfollowed" : "Following");
} finally {
setLoading(false);
}
}
return (
<Button variant={following ? "outline" : "default"} size="sm" onClick={toggle} disabled={loading}>
{loading ? "…" : following ? "Following" : "Follow"}
</Button>
);
}