/** * Component: Watched Lists Section (Profile Page) * Documentation: documentation/features/watched-lists.md * * Shows the user's watched series and watched authors on their profile page * with the ability to remove items. */ 'use client'; import React, { useState } from 'react'; import { useRouter } from 'next/navigation'; import Image from 'next/image'; import { useWatchedSeries, useDeleteWatchedSeries, WatchedSeriesItem } from '@/lib/hooks/useWatchedSeries'; import { useWatchedAuthors, useDeleteWatchedAuthor, WatchedAuthorItem } from '@/lib/hooks/useWatchedAuthors'; import { usePreferences } from '@/contexts/PreferencesContext'; function formatRelativeTime(dateStr: string | null): string { if (!dateStr) return 'Never'; const date = new Date(dateStr); const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffMins = Math.floor(diffMs / 60000); if (diffMins < 1) return 'just now'; if (diffMins < 60) return `${diffMins}m ago`; const diffHours = Math.floor(diffMins / 60); if (diffHours < 24) return `${diffHours}h ago`; const diffDays = Math.floor(diffHours / 24); return `${diffDays}d ago`; } // --------------------------------------------------------------------------- // Watched Series Section // --------------------------------------------------------------------------- export function WatchedSeriesSection() { const router = useRouter(); const { series, isLoading } = useWatchedSeries(); const { deleteSeries, isLoading: isDeleting } = useDeleteWatchedSeries(); const { squareCovers } = usePreferences(); const [confirmDeleteId, setConfirmDeleteId] = useState(null); const handleDelete = async (id: string) => { try { await deleteSeries(id); setConfirmDeleteId(null); } catch { // Error handled by hook } }; if (isLoading) { return (
{[1, 2].map((i) => )}
); } if (series.length === 0) return null; return (
{series.map((item) => ( router.push(`/series/${item.seriesAsin}`)} onConfirmDelete={() => setConfirmDeleteId(item.id)} onCancelDelete={() => setConfirmDeleteId(null)} onDelete={() => handleDelete(item.id)} /> ))}
); } function WatchedSeriesCard({ item, squareCovers, isDeleting, confirmingDelete, onNavigate, onConfirmDelete, onCancelDelete, onDelete, }: { item: WatchedSeriesItem; squareCovers: boolean; isDeleting: boolean; confirmingDelete: boolean; onNavigate: () => void; onConfirmDelete: () => void; onCancelDelete: () => void; onDelete: () => void; }) { return (
{/* Cover */} {/* Info */}

Last checked: {formatRelativeTime(item.lastCheckedAt)}

{/* Delete */}
{confirmingDelete ? (
) : ( )}
); } // --------------------------------------------------------------------------- // Watched Authors Section // --------------------------------------------------------------------------- export function WatchedAuthorsSection() { const router = useRouter(); const { authors, isLoading } = useWatchedAuthors(); const { deleteAuthor, isLoading: isDeleting } = useDeleteWatchedAuthor(); const [confirmDeleteId, setConfirmDeleteId] = useState(null); const handleDelete = async (id: string) => { try { await deleteAuthor(id); setConfirmDeleteId(null); } catch { // Error handled by hook } }; if (isLoading) { return (
{[1, 2].map((i) => )}
); } if (authors.length === 0) return null; return (
{authors.map((item) => ( router.push(`/authors/${item.authorAsin}`)} onConfirmDelete={() => setConfirmDeleteId(item.id)} onCancelDelete={() => setConfirmDeleteId(null)} onDelete={() => handleDelete(item.id)} /> ))}
); } function WatchedAuthorCard({ item, isDeleting, confirmingDelete, onNavigate, onConfirmDelete, onCancelDelete, onDelete, }: { item: WatchedAuthorItem; isDeleting: boolean; confirmingDelete: boolean; onNavigate: () => void; onConfirmDelete: () => void; onCancelDelete: () => void; onDelete: () => void; }) { return (
{/* Avatar */} {/* Info */}

Last checked: {formatRelativeTime(item.lastCheckedAt)}

{/* Delete */}
{confirmingDelete ? (
) : ( )}
); } // --------------------------------------------------------------------------- // Shared Components // --------------------------------------------------------------------------- function SectionHeader({ title, icon, count }: { title: string; icon: 'series' | 'author'; count: number | null }) { const gradientColors = icon === 'series' ? 'from-emerald-500 to-teal-500' : 'from-blue-500 to-indigo-500'; return (

{title}

{count !== null && ( ({count}) )}
); } function CardSkeleton({ squareCovers }: { squareCovers?: boolean }) { return (
); }