"use client"; import { IconBookmarkFilled, IconCheck, IconCircleCheckFilled, IconDeviceTv, IconLoader, IconMovie, IconPlayerPlayFilled, IconPlus, IconStarFilled, } from "@tabler/icons-react"; import { motion } from "motion/react"; import Image from "next/image"; import Link from "next/link"; import { useState } from "react"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; import { quickAddToWatchlist } from "@/lib/actions/watchlist"; type TitleStatus = "watchlist" | "in_progress" | "completed"; interface TitleCardProps { id?: string; tmdbId: number; type: string; title: string; posterPath: string | null; releaseDate?: string | null; voteAverage?: number | null; href?: string; onImport?: () => void; showQuickAdd?: boolean; userStatus?: TitleStatus | null; episodeProgress?: { watched: number; total: number } | null; } type QuickAddState = "idle" | "loading" | "added"; const statusConfig = { watchlist: { icon: IconBookmarkFilled, label: "On Watchlist", badgeClass: "bg-status-watching/90 text-white", }, in_progress: { icon: IconPlayerPlayFilled, label: "Watching", badgeClass: "bg-status-watching/90 text-white", }, completed: { icon: IconCircleCheckFilled, label: "Completed", badgeClass: "bg-status-completed/90 text-white", }, } as const; function QuickAddButton({ tmdbId, type, userStatus, }: { tmdbId: number; type: "movie" | "tv"; userStatus?: TitleStatus | null; }) { const [state, setState] = useState( userStatus ? "added" : "idle", ); const [addedStatus, setAddedStatus] = useState( userStatus ?? null, ); const effectiveStatus = addedStatus; const config = effectiveStatus ? statusConfig[effectiveStatus] : null; async function handleClick(e: React.MouseEvent) { e.preventDefault(); e.stopPropagation(); if (state === "loading" || state === "added") return; setState("loading"); try { const result = await quickAddToWatchlist(tmdbId, type); setState("added"); setAddedStatus(result.alreadyAdded ? null : "watchlist"); if (result.alreadyAdded) { // Already existed — keep as added but we don't know exact status setAddedStatus("watchlist"); } } catch { setState("idle"); } } if (state === "added" && config) { const StatusIcon = config.icon; return ( } > {config.label} ); } return ( } > {state === "idle" && } {state === "loading" && } {state === "added" && } {state === "added" ? "Added to Watchlist" : "Add to Watchlist"} ); } function StatusBadge({ status }: { status: TitleStatus }) { const config = statusConfig[status]; const StatusIcon = config.icon; return (
{config.label}
); } function ProgressBar({ watched, total }: { watched: number; total: number }) { const pct = total > 0 ? (watched / total) * 100 : 0; return ( } >
{watched}/{total} episodes ); } export function TitleCard({ id, tmdbId, type, title, posterPath, releaseDate, voteAverage, href, onImport, showQuickAdd, userStatus, episodeProgress, }: TitleCardProps) { const year = releaseDate?.slice(0, 4); const TypeIcon = type === "movie" ? IconMovie : IconDeviceTv; const cardInner = (
{posterPath ? ( {title} ) : (

{title}

)} {/* Status badge on poster */} {userStatus && } {/* Hover gradient overlay */}
{/* Metadata */}

{title}

{year && {year}} {voteAverage != null && voteAverage > 0 && ( {voteAverage.toFixed(1)} )}
{/* Episode progress bar */} {episodeProgress && episodeProgress.watched > 0 && ( )} ); if (href || id) { return (
{showQuickAdd && ( )} {cardInner}
); } if (onImport) { return ( ); } return cardInner; }