fix(plex): give the library search its own ephemeral state
The Plex library search box wrote to the shared, persisted feed filter (filters.q). That leaked a Plex query into the feed search box and, being persisted, restored a stale query after a reload — which then collided with a persisted collection filter to produce a confusing empty grid. Plex now has its own search state: kept across page switches within a session, but not persisted and not shared with the feed, so a reload starts clean.
This commit is contained in:
parent
d84edebc09
commit
a005a1bcbb
2 changed files with 28 additions and 8 deletions
|
|
@ -12,12 +12,17 @@ export default function Header({
|
|||
me,
|
||||
filters,
|
||||
setFilters,
|
||||
plexQ,
|
||||
setPlexQ,
|
||||
page,
|
||||
onYtSearch,
|
||||
}: {
|
||||
me: Me;
|
||||
filters: FeedFilters;
|
||||
setFilters: (f: FeedFilters) => void;
|
||||
// Plex has its own ephemeral search term (see App) — the box is shared UI, the state is not.
|
||||
plexQ: string;
|
||||
setPlexQ: (q: string) => void;
|
||||
page: Page;
|
||||
// Trigger a live YouTube search for the current term (hidden for the demo account, which
|
||||
// can't spend the shared quota).
|
||||
|
|
@ -25,11 +30,14 @@ export default function Header({
|
|||
}) {
|
||||
const { t } = useTranslation();
|
||||
const canSearchYt = !me.is_demo;
|
||||
const trimmedQ = filters.q.trim();
|
||||
// The search box serves both the YouTube feed and the Plex module (integrated search); the live
|
||||
// YouTube-search escalation (Enter / button) is feed-only.
|
||||
// YouTube-search escalation (Enter / button) is feed-only. On Plex it drives `plexQ`, on the feed
|
||||
// the persisted `filters.q`.
|
||||
const isSearchPage = page === "feed" || page === "plex";
|
||||
const isPlex = page === "plex";
|
||||
const isYtCapable = page === "feed" && canSearchYt;
|
||||
const searchValue = isPlex ? plexQ : filters.q;
|
||||
const trimmedQ = searchValue.trim();
|
||||
|
||||
return (
|
||||
<header className="glass h-14 shrink-0 border-b border-border flex items-center gap-3 px-4 z-20">
|
||||
|
|
@ -38,14 +46,18 @@ export default function Header({
|
|||
<div className="flex-1 relative">
|
||||
<Search className="w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-muted" />
|
||||
<input
|
||||
value={filters.q}
|
||||
value={searchValue}
|
||||
onChange={(e) => {
|
||||
const q = e.target.value;
|
||||
if (isPlex) {
|
||||
setPlexQ(q);
|
||||
return;
|
||||
}
|
||||
// When a search first appears, rank the feed by relevance — set atomically with
|
||||
// the query (race-free vs. per-keystroke updates). Only overrides the default
|
||||
// "newest" sort; a custom sort the user chose is left alone. Cleared in Feed.
|
||||
const startSearch =
|
||||
page === "feed" && !filters.q.trim() && !!q.trim() && filters.sort === "newest";
|
||||
!filters.q.trim() && !!q.trim() && filters.sort === "newest";
|
||||
setFilters({ ...filters, q, ...(startSearch ? { sort: "relevance" } : {}) });
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
|
|
@ -56,9 +68,9 @@ export default function Header({
|
|||
placeholder={page === "plex" ? t("plex.searchPlaceholder") : t("header.searchPlaceholder")}
|
||||
className="w-full bg-card border border-border rounded-full pl-9 pr-9 py-2 text-sm outline-none focus:border-accent"
|
||||
/>
|
||||
{filters.q && (
|
||||
{searchValue && (
|
||||
<button
|
||||
onClick={() => setFilters({ ...filters, q: "" })}
|
||||
onClick={() => (isPlex ? setPlexQ("") : setFilters({ ...filters, q: "" }))}
|
||||
title={t("header.clearSearch")}
|
||||
aria-label={t("header.clearSearch")}
|
||||
className="absolute right-2.5 top-1/2 -translate-y-1/2 p-0.5 rounded-full text-muted hover:text-fg hover:bg-border/60 transition"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue