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. export type ChannelsState = { search: string; // The subscribed table's column filters, lifted out of DataTable so the top status chips, the Sync // column funnel, and the card layout share ONE filter state (the sync chip lives at `filters.sync`). filters: FilterMap; view: ChannelsView; // The subscribed table's sort, lifted out of DataTable so the card layout shares it. sort: SortState; // Bumped to tell the manager to drop a stale column filter when an intent sends the user to a // specific set (the header's "without full history" link). filtersResetToken: number; focusName: string | null; // Bumped every time a focus intent is (re-)issued, so re-focusing the same channel re-seeds the // manager's name filter even when the name is unchanged. focusToken: number; }; export interface ChannelsActions { setSearch: (q: string) => void; setFilters: (f: FilterMap) => void; setView: (v: ChannelsView) => void; setLayout: (l: ChannelLayout) => void; setSort: (s: SortState) => void; // "Focus this channel in the manager": jump to Channels (subscriptions tab) and seed its name // filter so the channel is isolated. Called from the feed sidebar and the notifications inbox. focusChannel: (name: string) => void; // Jump to the manager filtered to channels still missing full history (the header sync chip). goToFullHistory: () => void; } export const ChannelsStateContext = createContext({ search: "", filters: {}, view: "subscribed", sort: null, filtersResetToken: 0, focusName: null, focusToken: 0, }); // The table/cards density gets its OWN context, deliberately narrow: App reads it (to decide the // shell's top fade) and would otherwise re-render the whole app on every keystroke in the manager's // search box, since the state context above changes with it. export const ChannelLayoutContext = createContext("table"); export const ChannelsActionsContext = createContext({ setSearch: () => {}, setFilters: () => {}, setView: () => {}, setLayout: () => {}, setSort: () => {}, focusChannel: () => {}, goToFullHistory: () => {}, }); export function useChannels(): ChannelsState { return useContext(ChannelsStateContext); } /** The manager's table/cards density on its own — subscribe to this instead of the whole state when * the layout is all you need (App does, for the shell's top fade). */ export function useChannelLayout(): ChannelLayout { return useContext(ChannelLayoutContext); } export function useChannelsActions(): ChannelsActions { return useContext(ChannelsActionsContext); }