refactor(frontend): the module stores mount from the registry, and the feed and Plex each own their saved views
A module's definition names its store (feed: filters, view, saved views; Plex: browse state, saved views; channels, files, playlists their provider), and ModuleStores mounts them at the root in registry order instead of a hand-nested tree in main.tsx. A contract test holds that every store's read side is in reach and that no store's static imports leave its own module, so the order cannot matter. Saved views were one provider that switched between the feed and Plex by the active page and reset on each switch. The logic is now one hook (useSavedViewsStore) with an instance per module; the shared chip, popover and modal read the views their page or rail hands down. A feed view applied and edited now survives a visit to Plex. Plex's views are still asked for only on its page, and a module's manage modal still closes when its page is left. The feed's URL-override check applies only on the feed page, where its filter params live. The Channels store's tab type moves from the page into the store's context.
This commit is contained in:
@@ -58,7 +58,12 @@ import { choiceSubmenu, sortSubmenu } from "../../components/ui/pageMenuItems";
|
||||
import { optionsFromColumns } from "../../lib/sortOptions";
|
||||
import ChannelDiscovery from "./ChannelDiscovery";
|
||||
import TagManager from "../../features/channel/TagManager";
|
||||
import { useChannelLayout, useChannels, useChannelsActions } from "./channelsContext";
|
||||
import {
|
||||
useChannelLayout,
|
||||
useChannels,
|
||||
useChannelsActions,
|
||||
type ChannelsView,
|
||||
} from "./channelsContext";
|
||||
import { useNavigationActions } from "../../features/navigation/navigationContext";
|
||||
import { useFeedFilters, useFeedFiltersActions } from "../feed";
|
||||
import { useWizard } from "../../features/wizard/wizardContext";
|
||||
@@ -66,8 +71,6 @@ import { useMe } from "../../lib/useMe";
|
||||
import { useTags } from "../../lib/useTags";
|
||||
import ChannelsHeader from "./ChannelsHeader";
|
||||
|
||||
export type ChannelsView = "subscribed" | "discovery" | "hidden" | "blocked";
|
||||
|
||||
// The tag filter has its own chip row above the list, so the hidden-filter cue does not name it again.
|
||||
const SURFACED_FILTERS = ["tags"];
|
||||
|
||||
|
||||
@@ -24,13 +24,13 @@ import {
|
||||
} from "../../lib/channelsUrlState";
|
||||
import type { FilterMap } from "../../lib/tableColumns";
|
||||
import { useNavigation, useNavigationActions } from "../../features/navigation/navigationContext";
|
||||
import type { ChannelsView } from "./Channels";
|
||||
import {
|
||||
ChannelLayoutContext,
|
||||
ChannelsActionsContext,
|
||||
ChannelsStateContext,
|
||||
type ChannelsActions,
|
||||
type ChannelsState,
|
||||
type ChannelsView,
|
||||
} from "./channelsContext";
|
||||
|
||||
// Owns the Channels module's shared local state — the rail-less manager's name filter, column-filter
|
||||
|
||||
@@ -2,11 +2,13 @@ import { createContext, useContext } from "react";
|
||||
import type { ChannelLayout } from "../../lib/channelLayout";
|
||||
import type { SortState } from "../../lib/columnSort";
|
||||
import type { FilterMap } from "../../lib/tableColumns";
|
||||
import type { ChannelsView } from "./Channels";
|
||||
|
||||
// The Channels module's contexts + hooks, split out of ChannelsProvider so that file exports only
|
||||
// components (Fast Refresh). The provider owns the state; this is the read side every consumer imports.
|
||||
|
||||
// The manager's tabs.
|
||||
export type ChannelsView = "subscribed" | "discovery" | "hidden" | "blocked";
|
||||
|
||||
export type ChannelsState = {
|
||||
search: string;
|
||||
// The subscribed table's column filters, lifted out of DataTable so the top status chips, the Sync
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// The channel manager's public face: its store, mounted at the root and read app-wide, and the sync
|
||||
// chip, which the feed's header shows too.
|
||||
export { ChannelsProvider } from "./ChannelsProvider";
|
||||
export { useChannelsActions } from "./channelsContext";
|
||||
export { default as SyncStatus } from "./SyncStatus";
|
||||
export { channelsModule } from "./module";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Tv } from "lucide-react";
|
||||
import { lazyWithPreload } from "../../lib/lazyWithPreload";
|
||||
import type { ModuleDef } from "../../lib/moduleDef";
|
||||
import { ChannelsProvider } from "./ChannelsProvider";
|
||||
|
||||
// This page as the shell and the navigation know it (lib/moduleDef). Its page load lazily.
|
||||
export const channelsModule: ModuleDef = {
|
||||
@@ -11,4 +12,5 @@ export const channelsModule: ModuleDef = {
|
||||
icon: Tv,
|
||||
Page: lazyWithPreload(() => import("./Channels")),
|
||||
maxWidth: "96rem",
|
||||
Store: ChannelsProvider,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user