- Backend: faq_questions table (schema + migration), CRUD + reorder API, Swagger docs - Admin: FAQ page with create/edit, enable/disable, show on homepage, drag reorder - Public /faq page fetches enabled FAQs from API; layout builds dynamic JSON-LD - Homepage: FAQ section under Stay updated (homepage-enabled only) with See full FAQ link - llms.txt: FAQ section uses homepage FAQs from API - i18n: home.faq title/seeFull, admin FAQ nav Co-authored-by: Cursor <cursoragent@cursor.com>
117 lines
4.2 KiB
TypeScript
117 lines
4.2 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { useLanguage } from '@/context/LanguageContext';
|
|
import { faqApi, FaqItem } from '@/lib/api';
|
|
import Card from '@/components/ui/Card';
|
|
import { ChevronDownIcon } from '@heroicons/react/24/outline';
|
|
import clsx from 'clsx';
|
|
|
|
export default function FAQPage() {
|
|
const { locale } = useLanguage();
|
|
const [faqs, setFaqs] = useState<FaqItem[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [openIndex, setOpenIndex] = useState<number | null>(null);
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
faqApi.getList().then((res) => {
|
|
if (!cancelled) {
|
|
setFaqs(res.faqs);
|
|
}
|
|
}).finally(() => {
|
|
if (!cancelled) setLoading(false);
|
|
});
|
|
return () => { cancelled = true; };
|
|
}, []);
|
|
|
|
const toggleFAQ = (index: number) => {
|
|
setOpenIndex(openIndex === index ? null : index);
|
|
};
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="section-padding">
|
|
<div className="container-page max-w-3xl flex justify-center py-20">
|
|
<div className="animate-spin w-10 h-10 border-4 border-primary-yellow border-t-transparent rounded-full" />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="section-padding">
|
|
<div className="container-page max-w-3xl">
|
|
<div className="text-center mb-12">
|
|
<h1 className="text-4xl font-bold text-primary-dark mb-4">
|
|
{locale === 'es' ? 'Preguntas Frecuentes' : 'Frequently Asked Questions'}
|
|
</h1>
|
|
<p className="text-gray-600">
|
|
{locale === 'es'
|
|
? 'Encuentra respuestas a las preguntas más comunes sobre Spanglish'
|
|
: 'Find answers to the most common questions about Spanglish'}
|
|
</p>
|
|
</div>
|
|
|
|
{faqs.length === 0 ? (
|
|
<Card className="p-8 text-center">
|
|
<p className="text-gray-600">
|
|
{locale === 'es'
|
|
? 'No hay preguntas frecuentes publicadas en este momento.'
|
|
: 'No FAQ questions are published at the moment.'}
|
|
</p>
|
|
</Card>
|
|
) : (
|
|
<div className="space-y-4">
|
|
{faqs.map((faq, index) => (
|
|
<Card key={faq.id} className="overflow-hidden">
|
|
<button
|
|
onClick={() => toggleFAQ(index)}
|
|
className="w-full px-6 py-4 flex items-center justify-between text-left hover:bg-gray-50 transition-colors"
|
|
>
|
|
<span className="font-semibold text-primary-dark pr-4">
|
|
{locale === 'es' && faq.questionEs ? faq.questionEs : faq.question}
|
|
</span>
|
|
<ChevronDownIcon
|
|
className={clsx(
|
|
'w-5 h-5 text-gray-500 flex-shrink-0 transition-transform duration-200',
|
|
openIndex === index && 'transform rotate-180'
|
|
)}
|
|
/>
|
|
</button>
|
|
<div
|
|
className={clsx(
|
|
'overflow-hidden transition-all duration-200',
|
|
openIndex === index ? 'max-h-96' : 'max-h-0'
|
|
)}
|
|
>
|
|
<div className="px-6 pb-4 text-gray-600">
|
|
{locale === 'es' && faq.answerEs ? faq.answerEs : faq.answer}
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
<Card className="mt-12 p-8 text-center bg-primary-yellow/10">
|
|
<h2 className="text-xl font-semibold text-primary-dark mb-2">
|
|
{locale === 'es' ? '¿Todavía tienes preguntas?' : 'Still have questions?'}
|
|
</h2>
|
|
<p className="text-gray-600 mb-4">
|
|
{locale === 'es'
|
|
? 'No dudes en contactarnos. ¡Estamos aquí para ayudarte!'
|
|
: "Don't hesitate to reach out. We're here to help!"}
|
|
</p>
|
|
<a
|
|
href="/contact"
|
|
className="inline-flex items-center justify-center px-6 py-3 bg-primary-yellow text-primary-dark font-semibold rounded-btn hover:bg-primary-yellow/90 transition-colors"
|
|
>
|
|
{locale === 'es' ? 'Contáctanos' : 'Contact Us'}
|
|
</a>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|