Files
sofa/app/(pages)/dashboard/_components/stats-section.tsx
T
jakeandClaude Opus 4.6 c1867a4f23 Convert dashboard and title pages to server components with granular Suspense
Replace fully client-side dashboard and title detail pages with server
component orchestrators that fetch data directly via service functions,
eliminating extra network round-trips through API routes. Each section
streams independently through its own Suspense boundary.

- Extract getUserStats(), getTitleWithChildren(), getRecommendationsForTitle()
  into service layer; update getNewAvailableFeed() to include tmdbId/voteAverage
- Split dashboard into server sections (stats, continue watching, library,
  recommendations) with client children for animations
- Split title page into server hero + client interaction provider with shared
  context for optimistic mutations across actions and seasons
- Add generateMetadata with OG tags, server-side TMDB ID resolution via
  redirect(), loading.tsx and not-found.tsx for both pages
- Add per-section skeleton components, fix ContinueWatchingSkeleton dimensions
- Remove 6 unused API routes (feed/*, titles/[id] GET, titles/[id]/recommendations)
- Remove components/stats-summary.tsx, add lib/types/title.ts for shared types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:42:42 -05:00

40 lines
1.4 KiB
TypeScript

import { IconDeviceTv } from "@tabler/icons-react";
import Link from "next/link";
import { getUserStats } from "@/lib/services/discovery";
import { StatsDisplay } from "./stats-display";
export async function StatsSection({ userId }: { userId: string }) {
const stats = await getUserStats(userId);
const isEmpty =
stats.moviesThisMonth === 0 &&
stats.episodesThisWeek === 0 &&
stats.librarySize === 0 &&
stats.completed === 0;
return (
<>
<StatsDisplay stats={stats} />
{isEmpty && (
<div className="flex flex-col items-center gap-4 rounded-xl border border-dashed border-border/50 py-16 text-center">
<div className="animate-gentle-float rounded-full bg-primary/10 p-4">
<IconDeviceTv size={32} className="text-primary" />
</div>
<div className="space-y-1">
<p className="font-medium">Your library is empty</p>
<p className="text-sm text-muted-foreground">
Search for movies and TV shows to start tracking
</p>
</div>
<Link
href="/explore"
className="inline-flex h-9 items-center rounded-lg bg-primary px-4 text-sm font-medium text-primary-foreground transition-all hover:shadow-md hover:shadow-primary/20"
>
Start exploring
</Link>
</div>
)}
</>
);
}