← Files WixARCHIVED FILE

skills/wix-headless-templates/faq/project/src/hooks/faq/useFaq.ts

1.86 KB · Oct 8, 2026 · 12:02 UTC

↓ Download file

See the change to this file →

// React binding of the FAQ store (wix/faq/faq-store.ts) — the state machine (category filter, search,
// accordion, URL state, the load) lives there, framework-free and module-scoped; this hook seeds it
// with the island's SSR props during render and subscribes with useSyncExternalStore. Every island on
// the page calls it and they all see one state. Astro islands and React SPAs use this; a static page,
// Vue, or Svelte uses the store directly.
import { useMemo, useSyncExternalStore } from "react";
import {
  collapseAll,
  expandQuestion,
  getFaqState,
  retry,
  seedFaq,
  selectCategory,
  setQuery,
  subscribeFaq,
  toggleQuestion,
  type FaqState,
  type FaqStoreOptions,
} from "../../wix/faq/faq-store";
import { groupByCategory } from "../../wix/faq/faq-core";
import type { FaqSection } from "../../wix/faq/types";

export type UseFaqOptions = FaqStoreOptions;

export interface UseFaq extends FaqState {
  /** The visible questions grouped by category in owner order (one section when a category is active). */
  sections: FaqSection[];
  isExpanded(id: string): boolean;
  selectCategory: typeof selectCategory;
  setQuery: typeof setQuery;
  toggleQuestion: typeof toggleQuestion;
  expandQuestion: typeof expandQuestion;
  collapseAll: typeof collapseAll;
  retry: typeof retry;
}

export function useFaq(options: UseFaqOptions = {}): UseFaq {
  // Idempotent in the browser (the first island seeds); on the server it makes this request's data current.
  seedFaq(options);
  const state = useSyncExternalStore(subscribeFaq, getFaqState, getFaqState);
  const sections = useMemo(() => groupByCategory(state.data?.categories ?? [], state.visible), [state.data, state.visible]);
  return {
    ...state,
    sections,
    isExpanded: (id) => state.expandedIds.includes(id),
    selectCategory,
    setQuery,
    toggleQuestion,
    expandQuestion,
    collapseAll,
    retry,
  };
}

SHA-256: 75b896247c6d98610e4cd16a5b3284911c250b9b02b14a1d91a453dd3860fe48