Fix missing userStatus on title cards across dashboard, recommendations, and filmography

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 20:24:17 -05:00
co-authored by Claude Opus 4.6
parent 61908778c9
commit 70a2a9f28d
8 changed files with 68 additions and 3 deletions
@@ -16,6 +16,7 @@ export async function LibrarySection({ userId }: { userId: string }) {
posterPath: tmdbImageUrl(t.posterPath, "w500"), posterPath: tmdbImageUrl(t.posterPath, "w500"),
releaseDate: t.releaseDate ?? t.firstAirDate, releaseDate: t.releaseDate ?? t.firstAirDate,
voteAverage: t.voteAverage, voteAverage: t.voteAverage,
userStatus: t.userStatus as "watchlist" | "in_progress" | "completed",
})); }));
return ( return (
@@ -10,6 +10,7 @@ interface TitleGridItem {
posterPath: string | null; posterPath: string | null;
releaseDate?: string | null; releaseDate?: string | null;
voteAverage?: number | null; voteAverage?: number | null;
userStatus?: "watchlist" | "in_progress" | "completed" | null;
} }
export function TitleGrid({ items }: { items: TitleGridItem[] }) { export function TitleGrid({ items }: { items: TitleGridItem[] }) {
@@ -29,6 +30,7 @@ export function TitleGrid({ items }: { items: TitleGridItem[] }) {
posterPath={t.posterPath} posterPath={t.posterPath}
releaseDate={t.releaseDate} releaseDate={t.releaseDate}
voteAverage={t.voteAverage} voteAverage={t.voteAverage}
userStatus={t.userStatus}
/> />
</div> </div>
))} ))}
@@ -18,9 +18,13 @@ type Sort = "newest" | "rating";
interface FilmographyGridProps { interface FilmographyGridProps {
credits: PersonCredit[]; credits: PersonCredit[];
userStatuses?: Record<string, "watchlist" | "in_progress" | "completed">;
} }
export function FilmographyGrid({ credits }: FilmographyGridProps) { export function FilmographyGrid({
credits,
userStatuses,
}: FilmographyGridProps) {
const [filter, setFilter] = useState<Filter>("all"); const [filter, setFilter] = useState<Filter>("all");
const [sort, setSort] = useState<Sort>("newest"); const [sort, setSort] = useState<Sort>("newest");
@@ -128,6 +132,7 @@ export function FilmographyGrid({ credits }: FilmographyGridProps) {
posterPath={credit.posterPath} posterPath={credit.posterPath}
releaseDate={credit.releaseDate ?? credit.firstAirDate} releaseDate={credit.releaseDate ?? credit.firstAirDate}
voteAverage={credit.voteAverage} voteAverage={credit.voteAverage}
userStatus={userStatuses?.[credit.titleId]}
/> />
</div> </div>
))} ))}
+9 -1
View File
@@ -9,6 +9,7 @@ import {
getOrFetchPerson, getOrFetchPerson,
getOrFetchPersonByTmdbId, getOrFetchPersonByTmdbId,
} from "@/lib/services/person"; } from "@/lib/services/person";
import { getUserStatusesByTitleIds } from "@/lib/services/tracking";
import { FilmographyGrid } from "./_components/filmography-grid"; import { FilmographyGrid } from "./_components/filmography-grid";
import { PersonHero } from "./_components/person-hero"; import { PersonHero } from "./_components/person-hero";
@@ -47,11 +48,18 @@ export default async function PersonDetailPage({
if (!person) notFound(); if (!person) notFound();
const filmography = getLocalFilmography(person.id); const filmography = getLocalFilmography(person.id);
const session = await getSession();
const userStatuses = session
? getUserStatusesByTitleIds(
session.user.id,
filmography.map((c) => c.titleId),
)
: {};
return ( return (
<div className="space-y-10"> <div className="space-y-10">
<PersonHero person={person} /> <PersonHero person={person} />
<FilmographyGrid credits={filmography} /> <FilmographyGrid credits={filmography} userStatuses={userStatuses} />
</div> </div>
); );
} }
@@ -6,8 +6,10 @@ import type { RecommendedTitle } from "@/lib/types/title";
export function RecommendationsGrid({ export function RecommendationsGrid({
recommendations, recommendations,
userStatuses,
}: { }: {
recommendations: RecommendedTitle[]; recommendations: RecommendedTitle[];
userStatuses?: Record<string, "watchlist" | "in_progress" | "completed">;
}) { }) {
return ( return (
<div className="space-y-4"> <div className="space-y-4">
@@ -30,6 +32,7 @@ export function RecommendationsGrid({
posterPath={rec.posterPath} posterPath={rec.posterPath}
releaseDate={rec.releaseDate ?? rec.firstAirDate} releaseDate={rec.releaseDate ?? rec.firstAirDate}
voteAverage={rec.voteAverage} voteAverage={rec.voteAverage}
userStatus={userStatuses?.[rec.id]}
/> />
</div> </div>
))} ))}
@@ -1,4 +1,6 @@
import { getSession } from "@/lib/auth/session";
import { getRecommendationsForTitle } from "@/lib/services/discovery"; import { getRecommendationsForTitle } from "@/lib/services/discovery";
import { getUserStatusesByTitleIds } from "@/lib/services/tracking";
import type { RecommendedTitle } from "@/lib/types/title"; import type { RecommendedTitle } from "@/lib/types/title";
import { RecommendationsGrid } from "./recommendations-grid"; import { RecommendationsGrid } from "./recommendations-grid";
@@ -17,5 +19,18 @@ export async function TitleRecommendations({ titleId }: { titleId: string }) {
voteAverage: r.voteAverage, voteAverage: r.voteAverage,
})); }));
return <RecommendationsGrid recommendations={recommendations} />; const session = await getSession();
const userStatuses = session
? getUserStatusesByTitleIds(
session.user.id,
recommendations.map((r) => r.id),
)
: {};
return (
<RecommendationsGrid
recommendations={recommendations}
userStatuses={userStatuses}
/>
);
} }
+1
View File
@@ -370,6 +370,7 @@ export function getNewAvailableFeed(userId: string, days = 14) {
firstAirDate: titles.firstAirDate, firstAirDate: titles.firstAirDate,
voteAverage: titles.voteAverage, voteAverage: titles.voteAverage,
popularity: titles.popularity, popularity: titles.popularity,
userStatus: userTitleStatus.status,
}) })
.from(titles) .from(titles)
.innerJoin( .innerJoin(
+30
View File
@@ -451,6 +451,36 @@ export function getUserStatusesByTmdbIds(
return result; return result;
} }
export function getUserStatusesByTitleIds(
userId: string,
titleIds: string[],
): Record<string, "watchlist" | "in_progress" | "completed"> {
if (titleIds.length === 0) return {};
const rows = db
.select({
titleId: userTitleStatus.titleId,
status: userTitleStatus.status,
})
.from(userTitleStatus)
.where(
and(
eq(userTitleStatus.userId, userId),
inArray(userTitleStatus.titleId, titleIds),
),
)
.all();
const result: Record<string, "watchlist" | "in_progress" | "completed"> = {};
for (const row of rows) {
result[row.titleId] = row.status as
| "watchlist"
| "in_progress"
| "completed";
}
return result;
}
export function getEpisodeProgressByTmdbIds( export function getEpisodeProgressByTmdbIds(
userId: string, userId: string,
tmdbIds: { tmdbId: number; type: string }[], tmdbIds: { tmdbId: number; type: string }[],