import { useMemo, Fragment } from 'react';
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from '@/components/ui/accordion';
import { useAppContext } from '@/hooks/useAppContext';
import { getFAQCategories, type FAQCategory, type FAQItem } from '@/lib/helpContent';
import { renderInlineMarkup } from '@/lib/helpMarkup';
// ── Component ─────────────────────────────────────────────────────────────────
interface HelpFAQSectionProps {
/** Show only these category IDs. Omit to show all. */
categories?: string[];
/** Show only these item IDs (across all categories). Omit to show all. */
items?: string[];
/** Hide category headings (useful when showing a single category or filtered items). */
hideHeadings?: boolean;
/** Additional class names for the wrapper. */
className?: string;
}
/**
* Reusable FAQ accordion section.
*
* Renders FAQ items from `helpContent.ts` in collapsible accordions grouped by
* category. Accepts filter props so it can be dropped into any page to show a
* relevant subset of questions.
*
* @example
* // Full FAQ (Help page)
*
*
* // Only payments questions (wallet settings page)
*
*
* // Specific questions (onboarding)
*
*/
export function HelpFAQSection({ categories, items, hideHeadings, className }: HelpFAQSectionProps) {
const { config } = useAppContext();
const filteredCategories = useMemo(() => {
let cats: FAQCategory[] = getFAQCategories(config.appName);
// Drop hidden categories from the default render. They still exist in
// the underlying template so `HelpTip` can look up individual items by
// ID, but they don't show up in the FAQ accordion.
if (!categories && !items) {
cats = cats.filter((c) => !c.hidden);
}
// Filter to specific categories
if (categories) {
cats = cats.filter((c) => categories.includes(c.id));
}
// Filter to specific items
if (items) {
cats = cats
.map((c) => ({
...c,
items: c.items.filter((i) => items.includes(i.id)),
}))
.filter((c) => c.items.length > 0);
}
return cats;
}, [categories, items, config.appName]);
if (filteredCategories.length === 0) return null;
return (
{filteredCategories.map((category, catIndex) => (
{/* Category heading */}
{!hideHeadings && (
{category.label}
)}
{category.items.map((item) => (
))}
))}
);
}
function FAQAccordionItem({ item }: { item: FAQItem }) {
return (
{item.question}
{item.answer.map((paragraph, i) => (
{renderInlineMarkup(paragraph)}
))}
);
}