import type { ComponentType } from "react";
import { lazyWithPreload, type PreloadableComponent } from "../lib/lazyWithPreload";
import type { Page } from "../lib/urlState";
import type { PanelId, PanelLayout } from "../lib/panelLayout";
import { useMe } from "../lib/useMe";
import { useFeedFilters, useFeedFiltersActions } from "./FeedFiltersProvider";
import { useFeedView, useFeedViewActions } from "./FeedViewProvider";
import { useNavigation, useNavigationActions } from "./NavigationProvider";
import Sidebar from "./Sidebar";
import PlaylistsRail from "./PlaylistsRail";
import PersonalViewsModal from "./PersonalViewsModal";
import { useSavedViews } from "./SavedViewsProvider";
// The RENDER half of the module registry: which component (and side rail) each page renders. The
// metadata half — nav order, label, icon, gate — lives in lib/modules.ts (imported by NavSidebar /
// Header / App's gate check). Together they let App drive the whole shell from `page` alone, with no
// `page === X` chrome conditionals.
//
// Every content entry is a PROP-FREE component: it reads `me` from useMe() and its module-local state
// from the scoped providers, so App renders `` uniformly. The two that need per-render
// wiring get a thin wrapper here (FeedPage supplies the GLOBAL feed scope; the channel page threads
// its own isolated scope to directly — see the scope note in FeedFiltersProvider).
// Route-level code splitting: each page is its own lazy chunk (admin-only pages never reach
// non-admins; the logged-out landing pulls only the shell). Rendered inside App's . Each
// one is preloadable: App fetches the chunks of every page the account can reach once the first page
// is on screen (preloadPages below), so switching modules never shows the chunk fallback.
const Home = lazyWithPreload(() => import("./Home"));
const Feed = lazyWithPreload(() => import("./Feed"));
const Channels = lazyWithPreload(() => import("./Channels"));
const Playlists = lazyWithPreload(() => import("./Playlists"));
const PlexBrowse = lazyWithPreload(() => import("./PlexBrowse"));
const PlexSidebar = lazyWithPreload(() => import("./PlexSidebar"));
const NotificationsPanel = lazyWithPreload(() => import("./NotificationsPanel"));
const Messages = lazyWithPreload(() => import("./Messages"));
const DownloadCenter = lazyWithPreload(() => import("./DownloadCenter"));
const Stats = lazyWithPreload(() => import("./Stats"));
const Scheduler = lazyWithPreload(() => import("./Scheduler"));
const ConfigPanel = lazyWithPreload(() => import("./ConfigPanel"));
const AdminUsers = lazyWithPreload(() => import("./AdminUsers"));
const AuditLog = lazyWithPreload(() => import("./AuditLog"));
const SettingsPanel = lazyWithPreload(() => import("./SettingsPanel"));
// The GLOBAL feed page: wires to the app-wide feed filters / view / live-search. (The channel
// page renders itself with its own channel-scoped filters, so those two never share state.)
function FeedPage() {
const me = useMe();
const filters = useFeedFilters();
const { setFilters } = useFeedFiltersActions();
const view = useFeedView();
const { setView } = useFeedViewActions();
const { ytSearch } = useNavigation();
const { enterYtSearch, exitYtSearch } = useNavigationActions();
// The Personal Views modal lives at the feed-page level (always mounted while on the feed, unmounts
// on navigation) rather than inside the collapsible filter rail — otherwise opening it from the
// always-visible toolbar view chip while the rail is unpinned would render nothing and latch open.
const { modalOpen } = useSavedViews();
return (
<>
{modalOpen && !me.is_demo && }
>
);
}
function MessagesPage() {
const me = useMe();
return (
);
}
export type PageDef = {
// Prop-free by construction: reads `me` + module state from hooks/providers. Preloadable by type, so
// a new page cannot silently opt out of preloadPages.
Component: PreloadableComponent