import { createFileRoute } from "@tanstack/react-router" import { useCallback, useState } from "react" import { useTranslation } from "react-i18next" import { Clapperboard, Film, Inbox, Plus, RefreshCw } from "lucide-react" import { ReviewCard } from "@/components/review-card" import { MovieCard } from "@/components/movie-card" import { EmptyState } from "@/components/empty-state" import { SwipeTabs } from "@/components/swipe-tabs" import { SwipeToDelete } from "@/components/swipe-to-delete" import { VirtualList } from "@/components/virtual-list" import { Button } from "@/components/ui/button" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Skeleton } from "@/components/ui/skeleton" import { StarRating } from "@/components/star-rating" import { useAuth } from "@/components/auth-provider" import { useQueryClient } from "@tanstack/react-query" import { useInfiniteActivityFeed, useDeleteReview } from "@/hooks/use-diary" import { SearchOverlay } from "@/components/search-overlay" import type { MovieSelection } from "@/components/search-overlay" import { useInfiniteWatchlist, useAddToWatchlist, useRemoveFromWatchlist } from "@/hooks/use-watchlist" import { useWatchQueue, useConfirmWatch, useDismissWatch } from "@/hooks/use-webhooks" export const Route = createFileRoute("/_app/")({ component: HomePage, }) function HomePage() { const { t } = useTranslation() const homeTabs = [ { value: "feed", label: t("feed.tab") }, { value: "watchlist", label: t("feed.watchlist") }, { value: "queue", label: t("feed.queue") }, ] as const return (

{t("feed.title")}

{(tab) => ( <> {tab === "feed" && } {tab === "watchlist" && } {tab === "queue" && } )}
) } function FeedTab() { const { t } = useTranslation() const { auth } = useAuth() const qc = useQueryClient() const [refreshing, setRefreshing] = useState(false) const [sortBy, setSortBy] = useState("date") const feedSortOptions = [ { value: "date", label: t("feed.sortLatest") }, { value: "date_asc", label: t("feed.sortOldest") }, { value: "rating", label: t("feed.sortTopRated") }, { value: "rating_asc", label: t("feed.sortLowestRated") }, ] as const const { data, isPending, hasNextPage, isFetchingNextPage, fetchNextPage } = useInfiniteActivityFeed({ sort_by: sortBy }) const deleteReview = useDeleteReview() const items = data?.pages.flatMap((p) => p.items) ?? [] const loadMore = useCallback(() => fetchNextPage(), [fetchNextPage]) return (
{isPending && } {!isPending && !items.length && ( )} {items.length > 0 && ( { const card = ( ) return entry.user_id === auth?.user_id ? ( deleteReview.mutate(entry.review.id)} confirmTitle={t("feed.deleteReview")} confirmDescription={entry.movie.title} > {card} ) : ( card ) }} /> )}
) } function WatchlistTab() { const { t } = useTranslation() const { data, isPending, hasNextPage, isFetchingNextPage, fetchNextPage } = useInfiniteWatchlist() const items = data?.pages.flatMap((p) => p.items) ?? [] const addMutation = useAddToWatchlist() const removeMutation = useRemoveFromWatchlist() const loadMore = useCallback(() => fetchNextPage(), [fetchNextPage]) const [searchOpen, setSearchOpen] = useState(false) function handleAdd(movie: MovieSelection) { setSearchOpen(false) addMutation.mutate( movie.id ? { movie_id: movie.id } : { external_metadata_id: movie.external_metadata_id, manual_title: movie.title, manual_release_year: movie.release_year, }, ) } return (
{searchOpen && ( setSearchOpen(false)} onSelect={handleAdd} /> )} {isPending && } {!isPending && !items.length && ( )} {items.length > 0 && ( ( removeMutation.mutate(entry.movie.id)} confirmTitle={t("feed.removeFromWatchlist")} confirmDescription={entry.movie.title} > )} /> )}
) } function QueueTab() { const { t } = useTranslation() const { data, isPending } = useWatchQueue() const confirmMutation = useConfirmWatch() const dismissMutation = useDismissWatch() const [ratings, setRatings] = useState>({}) if (isPending) return if (!data?.length) return return (
{data.map((entry) => (

{entry.title}

{entry.year && `${entry.year} · `}{entry.source} · {entry.watched_at}

setRatings((p) => ({ ...p, [entry.id]: v }))} size="sm" />
))}
) } function FeedSkeleton() { return (
{[1, 2, 3].map((i) => (
))}
) }