import { useState } from "react"; import { useTranslation } from "react-i18next"; import { useInfiniteQuery, useQueryClient, type InfiniteData } from "@tanstack/react-query"; import { CircleCheck } from "lucide-react"; import { api, HttpError, type RelatedRegion, type RelatedResponse, type Video, type VideoStatus, } from "../../lib/api"; import { qk } from "../../lib/queryKeys"; import { nextPageOnClick } from "../../lib/nextPage"; import { usePref, type UsePrefOptions } from "../../lib/usePref"; import { notify } from "../../lib/notifications"; import { notifyActionError } from "../../lib/actionErrors"; import { Button } from "../../components/ui/Button"; import SegmentedToggle from "../../components/ui/SegmentedToggle"; import { LoadingState, StateMessage } from "../../components/ui/QueryState"; import { useContextMenu } from "../../components/ui/useContextMenu"; import NavGrid from "../../components/ui/NavGrid"; import VideoCard from "../video/VideoCard"; import { VideoMenu } from "../video/VideoMenu"; /** Which list YouTube fills in — on the video's topic or with what trends in Hungary — is a mood, * decided at the list, and the account keeps the last one (the owner's pick). */ const RELATED_REGION_PREF = "relatedRegion"; const RELATED_REGION_OPTIONS: UsePrefOptions = { parse: (raw) => (raw === "hu" ? "hu" : "topical"), }; // The list leaves out what the user has seen (the server does, as it fetches); a video marked here // leaves it the same way, at once. const isSeen = (v: Video) => v.status === "watched" || v.status === "hidden"; type Cached = InfiniteData; /** Patch one video in every related list held — both regions', and another opened video's. */ function patchRelated( qc: ReturnType, id: string, change: Partial