import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode, } from "react"; import { useQuery } from "@tanstack/react-query"; import { api } from "../lib/api"; import { parseFeedView, type FeedView } from "../lib/feedView"; import { LS, readAccount, writeAccount } from "../lib/storage"; // Owns the feed's view mode (the card/row/tile density switcher), lifted out of App so both the feed // page and the channel page read it via hooks instead of prop-drilling `view`/`setView` through App. // Split State + Actions contexts, mirroring the other providers; composed in main.tsx around . // // The view mode is an account PREFERENCE, not a filter: it persists to the server on pick (savePrefs) // and is adopted from server prefs on login — so unlike the ephemeral list filters, this provider // carries the same server-sync the App god component used to. A localStorage mirror seeds the initial // render synchronously; the passive ["me"] observer adopts the server value once the account resolves. interface FeedViewActions { setView: (v: FeedView) => void; } const StateContext = createContext("cards"); const ActionsContext = createContext({ setView: () => {} }); export function useFeedView(): FeedView { return useContext(StateContext); } export function useFeedViewActions(): FeedViewActions { return useContext(ActionsContext); } export function FeedViewProvider({ children }: { children: ReactNode }) { const [view, setViewState] = useState(() => parseFeedView(readAccount(LS.feedView, null))); // Passive observer of the account App fetches (enabled:false → reads cache, re-renders on update). const { data: me } = useQuery({ queryKey: ["me"], queryFn: api.me, enabled: false }); // A user pick persists both to the localStorage mirror (instant reload) and to the server. const setView = useCallback((next: FeedView) => { setViewState(next); writeAccount(LS.feedView, next); api.savePrefs({ view: next }).catch(() => {}); }, []); // Adopt the server-stored view on login / account switch. Writes the mirror but does NOT savePrefs // (that would echo the just-adopted value straight back). parseFeedView also maps the pre-0.45 // "grid" / "list" values forward. useEffect(() => { const prefs = me?.preferences; if (!prefs) return; const adopted = parseFeedView(prefs.view); setViewState(adopted); writeAccount(LS.feedView, adopted); // eslint-disable-next-line react-hooks/exhaustive-deps }, [me?.id]); const actions = useMemo(() => ({ setView }), [setView]); return ( {children} ); }