E32 review round 1 (F3–F6). - Channels' open-row store and the chat dock use lib/store's createStore instead of a hand-rolled listener set (the chat dock gets a test of its own). - The Plex backdrop reads prefers-reduced-motion through useMediaQuery; the query string is one constant (REDUCED_MOTION) for the hook and the carousel's one-off read. - A link-restored collection filter showed its raw rating_key in the picker while the titles loaded: usePlexCollectionTitles now says it is pending, the picker draws a placeholder (labelsPending, as the channel picker does) and so does the chip row. - The "deleted tag" rule was written twice with two i18n keys and had drifted: the channel manager showed NO chip for a pick while the tag list loaded, or ever after a failed load, while the pick still narrowed the table. One rule now (lib/tagPicks), one key (common.deletedTag); the manager's row shows every pick, as a placeholder while loading and as its id after a failure.
34 lines
1.9 KiB
TypeScript
34 lines
1.9 KiB
TypeScript
import { useQuery } from "@tanstack/react-query";
|
|
import { api } from "./api";
|
|
import { qk } from "./queryKeys";
|
|
|
|
// A Plex link carries the collection filter as bare rating_keys (`?pf=collections%3D17045`) — nothing
|
|
// in the URL says what "17045" is called. The title is normally picked up as a side effect of choosing
|
|
// the collection in the sidebar (`collectionTitles`), so a link opened cold had no name for it and the
|
|
// picker token rendered the raw id while the filter chip could only say "Collection".
|
|
//
|
|
// This resolves the missing ones from the server and merges them over what the filter state already
|
|
// knows. It stays OUT of `collectionTitles`: that map is hashed into the Plex query keys, so writing a
|
|
// resolved title back in would split the cache from the logically identical state and refetch the grid
|
|
// for a label. Titles are display-only, so they belong in a display-only read. `pending` says the
|
|
// missing ones are still on their way, so a token or chip can show a placeholder rather than the raw id
|
|
// (Combobox `labelsPending`, ActiveFilter `pending` — the feed's channel picker does the same).
|
|
export function usePlexCollectionTitles(
|
|
ids: string[],
|
|
known: Record<string, string> | undefined,
|
|
): { titles: Record<string, string>; pending: boolean } {
|
|
// Sorted so the same set of ids in a different order is the same query.
|
|
const missing = ids.filter((id) => !known?.[id]).sort();
|
|
const q = useQuery({
|
|
queryKey: qk.plexCollections("titles", missing.join(",")),
|
|
queryFn: () => api.plexCollections(undefined, undefined, missing),
|
|
enabled: missing.length > 0,
|
|
// A collection's name is about as static as data gets, and this can be asked for on every render
|
|
// of the sidebar and the chip row.
|
|
staleTime: 60 * 60_000,
|
|
});
|
|
const titles: Record<string, string> = { ...known };
|
|
for (const c of q.data?.collections ?? []) titles[c.id] = c.title;
|
|
return { titles, pending: missing.length > 0 && q.isPending };
|
|
}
|