chore(feed-ui): Phase 2 #2 frontend cleanup — hoist, drop wrapper, dedup caches
- Hoist withOverrides(loaded) into `merged` (was mapped twice per render for
items and playerQueue).
- Remove the needless always-true {(<>…</>)} expression wrapper around the
Source selector.
- Extract dropFeedCaches() — the feed/feed-count/facets removeQueries trio was
duplicated across the back and clear-now handlers.
Behavior-neutral. tsc green.
This commit is contained in:
parent
505f0e5650
commit
3cbb420ece
1 changed files with 32 additions and 34 deletions
|
|
@ -310,12 +310,21 @@ export default function Feed({
|
||||||
list
|
list
|
||||||
.map((v) => (overrides[v.id] ? { ...v, status: overrides[v.id] } : v))
|
.map((v) => (overrides[v.id] ? { ...v, status: overrides[v.id] } : v))
|
||||||
.map((v) => (savedOverrides[v.id] !== undefined ? { ...v, saved: savedOverrides[v.id] } : v));
|
.map((v) => (savedOverrides[v.id] !== undefined ? { ...v, saved: savedOverrides[v.id] } : v));
|
||||||
const items: Video[] = withOverrides(loaded).filter((v) => matchesView(v.status, filters.show));
|
const merged: Video[] = withOverrides(loaded);
|
||||||
|
const items: Video[] = merged.filter((v) => matchesView(v.status, filters.show));
|
||||||
// The in-app player's queue (auto-advance / loop / prev-next). It's the filtered feed, but the
|
// The in-app player's queue (auto-advance / loop / prev-next). It's the filtered feed, but the
|
||||||
// watch-state view filter is NOT applied — so marking the current video watched keeps it in the
|
// watch-state view filter is NOT applied — so marking the current video watched keeps it in the
|
||||||
// sequence (no reindex/reload mid-play), matching "watched doesn't affect the list". A video that
|
// sequence (no reindex/reload mid-play), matching "watched doesn't affect the list". A video that
|
||||||
// goes hidden still drops out ("visible affects").
|
// goes hidden still drops out ("visible affects").
|
||||||
const playerQueue: Video[] = withOverrides(loaded).filter((v) => v.status !== "hidden");
|
const playerQueue: Video[] = merged.filter((v) => v.status !== "hidden");
|
||||||
|
|
||||||
|
// A live search ingests new catalog videos, so the disabled feed queries still hold their stale
|
||||||
|
// pre-search cache. Drop them so the feed re-fetches fresh on return.
|
||||||
|
const dropFeedCaches = () => {
|
||||||
|
qc.removeQueries({ queryKey: ["feed"] });
|
||||||
|
qc.removeQueries({ queryKey: ["feed-count"] });
|
||||||
|
qc.removeQueries({ queryKey: ["facets"] });
|
||||||
|
};
|
||||||
|
|
||||||
// --- Live YouTube search mode -------------------------------------------------------------
|
// --- Live YouTube search mode -------------------------------------------------------------
|
||||||
// A separate data source rendered in the same cards/player. No watch-state view filter (the
|
// A separate data source rendered in the same cards/player. No watch-state view filter (the
|
||||||
|
|
@ -341,16 +350,11 @@ export default function Feed({
|
||||||
<div className="flex items-center gap-2 flex-wrap">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// The search just ingested new catalog videos, so the normal feed (which was
|
|
||||||
// disabled and still holds its pre-search cache) is stale. Drop those caches so
|
|
||||||
// it re-fetches fresh on return instead of showing the old (often empty) result.
|
|
||||||
// Surface the just-searched videos in the feed you return to: switch the Source
|
// Surface the just-searched videos in the feed you return to: switch the Source
|
||||||
// filter to "search" (your own search finds) and rank them by relevance.
|
// filter to "search" (your own search finds) and rank them by relevance.
|
||||||
setFilters({ ...filters, librarySource: "search", sort: "relevance" });
|
setFilters({ ...filters, librarySource: "search", sort: "relevance" });
|
||||||
onExitYtSearch();
|
onExitYtSearch();
|
||||||
qc.removeQueries({ queryKey: ["feed"] });
|
dropFeedCaches();
|
||||||
qc.removeQueries({ queryKey: ["feed-count"] });
|
|
||||||
qc.removeQueries({ queryKey: ["facets"] });
|
|
||||||
}}
|
}}
|
||||||
className="inline-flex items-center gap-1.5 text-sm text-muted hover:text-accent transition shrink-0"
|
className="inline-flex items-center gap-1.5 text-sm text-muted hover:text-accent transition shrink-0"
|
||||||
>
|
>
|
||||||
|
|
@ -394,9 +398,7 @@ export default function Feed({
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
setFilters({ ...filters, librarySource: "organic", sort: "newest" });
|
setFilters({ ...filters, librarySource: "organic", sort: "newest" });
|
||||||
onExitYtSearch();
|
onExitYtSearch();
|
||||||
qc.removeQueries({ queryKey: ["feed"] });
|
dropFeedCaches();
|
||||||
qc.removeQueries({ queryKey: ["feed-count"] });
|
|
||||||
qc.removeQueries({ queryKey: ["facets"] });
|
|
||||||
qc.removeQueries({ queryKey: ["yt-search"] });
|
qc.removeQueries({ queryKey: ["yt-search"] });
|
||||||
}}
|
}}
|
||||||
className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full border border-border text-muted hover:text-danger hover:border-danger transition"
|
className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full border border-border text-muted hover:text-danger hover:border-danger transition"
|
||||||
|
|
@ -541,29 +543,25 @@ export default function Feed({
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{(
|
<span className="mx-1 h-5 w-px bg-border" aria-hidden="true" />
|
||||||
<>
|
<label className="inline-flex items-center gap-1.5 text-xs text-muted">
|
||||||
<span className="mx-1 h-5 w-px bg-border" aria-hidden="true" />
|
<span>{t("feed.source.label")}</span>
|
||||||
<label className="inline-flex items-center gap-1.5 text-xs text-muted">
|
<select
|
||||||
<span>{t("feed.source.label")}</span>
|
value={filters.librarySource ?? "organic"}
|
||||||
<select
|
onChange={(e) =>
|
||||||
value={filters.librarySource ?? "organic"}
|
setFilters({
|
||||||
onChange={(e) =>
|
...filters,
|
||||||
setFilters({
|
librarySource: e.target.value as FeedFilters["librarySource"],
|
||||||
...filters,
|
})
|
||||||
librarySource: e.target.value as FeedFilters["librarySource"],
|
}
|
||||||
})
|
title={t("feed.source.tip")}
|
||||||
}
|
className="bg-card border border-border rounded-lg px-2 py-1 text-xs outline-none focus:border-accent"
|
||||||
title={t("feed.source.tip")}
|
>
|
||||||
className="bg-card border border-border rounded-lg px-2 py-1 text-xs outline-none focus:border-accent"
|
<option value="organic">{t("feed.source.organic")}</option>
|
||||||
>
|
<option value="all">{t("feed.source.all")}</option>
|
||||||
<option value="organic">{t("feed.source.organic")}</option>
|
<option value="search">{t("feed.source.only")}</option>
|
||||||
<option value="all">{t("feed.source.all")}</option>
|
</select>
|
||||||
<option value="search">{t("feed.source.only")}</option>
|
</label>
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<span className="mx-1 h-5 w-px bg-border" aria-hidden="true" />
|
<span className="mx-1 h-5 w-px bg-border" aria-hidden="true" />
|
||||||
<span className="text-xs text-muted whitespace-nowrap">
|
<span className="text-xs text-muted whitespace-nowrap">
|
||||||
{countQuery.data
|
{countQuery.data
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue