Files
jarv.is/components/post-stats.tsx
T
jakeandClaude Sonnet 5.5 6d255ce822 refactor: move read queries into server-only lib/data and render post stats on the server
Reads no longer live in "use server" files (which made them public
endpoints). /notes stats come from one cached query pair rendered on the
server; the post page comment count streams in as a dynamic hole.
revalidateTag("views"/"comments") now invalidates the cached stats.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 08:40:14 -04:00

62 lines
1.9 KiB
TypeScript

import { IconEye, IconMessages } from "@tabler/icons-react";
import Link from "next/link";
import { Badge } from "@/components/ui/badge";
import { Skeleton } from "@/components/ui/skeleton";
import { getPostStats } from "@/lib/data/stats";
const numberFormatter = new Intl.NumberFormat(process.env.NEXT_PUBLIC_SITE_LOCALE);
/**
* Placeholder shown while the stats for a post are loading.
*/
const PostStatsSkeleton = () => (
<>
<Skeleton className="inline-block h-5 w-16 translate-y-[-2px] rounded-4xl border border-transparent align-middle" />
<Skeleton className="inline-block h-5 w-12 translate-y-[-2px] rounded-4xl border border-transparent align-middle" />
</>
);
/**
* Displays view/comment badges for a single post.
* Every instance shares one cached getPostStats() result.
*/
const PostStats = async ({ slug }: { slug: string }) => {
const { views, comments } = await getPostStats();
const viewCount = views[slug] ?? 0;
const commentCount = comments[slug] ?? 0;
return (
<>
{viewCount > 0 && (
<Badge
variant="secondary"
className="gap-[5px] text-xs font-medium tracking-wide text-foreground/80"
>
<IconEye className="text-foreground/65" aria-hidden="true" />
{numberFormatter.format(viewCount)}
</Badge>
)}
{commentCount > 0 && (
<Badge
variant="secondary"
className="gap-[5px] text-xs font-medium tracking-wide text-foreground/80"
render={
<Link
href={`/${slug}#comments`}
title={`${numberFormatter.format(commentCount)} ${commentCount === 1 ? "comment" : "comments"}`}
/>
}
>
<IconMessages className="text-foreground/65" aria-hidden="true" />
{numberFormatter.format(commentCount)}
</Badge>
)}
</>
);
};
export { PostStats, PostStatsSkeleton };