import { useMemo, Fragment } from 'react'; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from '@/components/ui/accordion'; import { FAQ_CATEGORIES, type FAQCategory, type FAQItem } from '@/lib/helpContent'; // ── Inline markup renderer ──────────────────────────────────────────────────── /** * Very lightweight inline markup: **bold** and [text](url). * Returns an array of React nodes. */ function renderInlineMarkup(text: string): React.ReactNode[] { const nodes: React.ReactNode[] = []; // Match **bold** or [text](url) const regex = /\*\*(.+?)\*\*|\[([^\]]+)\]\(([^)]+)\)/g; let lastIndex = 0; let match: RegExpExecArray | null; while ((match = regex.exec(text)) !== null) { // Push text before this match if (match.index > lastIndex) { nodes.push(text.slice(lastIndex, match.index)); } if (match[1] !== undefined) { // **bold** nodes.push({match[1]}); } else if (match[2] !== undefined && match[3] !== undefined) { // [text](url) nodes.push( {match[2]} , ); } lastIndex = match.index + match[0].length; } // Trailing text if (lastIndex < text.length) { nodes.push(text.slice(lastIndex)); } return nodes; } // ── 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 filteredCategories = useMemo(() => { let cats: FAQCategory[] = FAQ_CATEGORIES; // 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]); 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)}

))}
); }