import { type ReactNode } from "react"; import { useTranslation } from "react-i18next"; import { useQuery } from "@tanstack/react-query"; import { qk } from "../lib/queryKeys"; import { api, type PlexCard } from "../lib/api"; import { useDebounced } from "../lib/useDebounced"; import { LoadingState } from "./QueryState"; // A debounced library search-and-pick list, shared by the "Add title" panel (PlexCollectionView) and // the "New collection" first-title panel (plexBrowseLists) — both search the library the same way and // render the same result rows, differing only in the per-row action. Callers keep their own chrome // (search input, name field, close button) and supply `term` + `renderAction`; this owns the query, // the loading/error/empty states, and the row markup so those can't drift between the two surfaces. export default function PlexLibraryPicker({ scope, term, enabled = true, emptyHint = null, renderAction, }: { scope: string; /** The raw search term; debounced internally. */ term: string; /** Gate the query off (e.g. until a collection name is valid). When false, renders nothing. */ enabled?: boolean; /** Shown while the (debounced) term is empty — a hint, or nothing. */ emptyHint?: ReactNode; /** The trailing control for each result row (Add / Create-with / …). */ renderAction: (card: PlexCard) => ReactNode; }) { const { t } = useTranslation(); const debounced = useDebounced(term.trim(), 300); const q = useQuery({ queryKey: qk.plexLibrary("collection-pick", scope, debounced), queryFn: () => api.plexLibrary({ scope, q: debounced, limit: 12 }), enabled: enabled && debounced.length > 0, }); const results = q.data?.items ?? []; if (!enabled) return null; if (debounced.length === 0) return <>{emptyHint}; if (q.isLoading) return ; if (q.isError) return

{t("common.loadError")}

; if (results.length === 0) return

{t("plex.collection.addNoResults")}

; return ( ); }