faq.tsx
"use client"
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion"
import { Button } from "@/components/ui/button"
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@/components/ui/tabs"
import { FancyButton } from "@/components/ui/fancy-button"
import { CreditCardIcon, MailIcon, ThumbsDownIcon, ThumbsUpIcon, UserIcon } from 'lucide-react'
type FaqCategoryValue = "account" | "billing" | "support"
type FaqItem = {
value: string
question: string
answer: string
}
type FaqCategory = {
value: FaqCategoryValue
label: string
icon: React.ReactNode
}
const faqs: Record<FaqCategoryValue, FaqItem[]> = {
account: [
{
value: "a1",
question: "How do I create an account?",
answer:
"Click the 'Sign Up' button, enter your email, create a password, and verify your email address.",
},
{
value: "a2",
question: "Can I change my email address?",
answer: "Yes, you can update your email in account settings.",
},
{
value: "a3",
question: "How do I reset my password?",
answer:
"Click 'Forgot Password' on the login page and follow the emailed instructions.",
},
{
value: "a4",
question: "Can I delete my account?",
answer:
"Yes, you can request account deletion through the privacy dashboard.",
},
{
value: "a5",
question: "Can I have multiple accounts?",
answer:
"Our terms allow one personal account per user, but you can manage multiple organizations.",
},
],
billing: [
{
value: "b1",
question: "What payment methods do you accept?",
answer: "We accept all major credit cards, PayPal, and bank transfers.",
},
{
value: "b2",
question: "Do you offer refunds?",
answer: "We offer a 30-day money-back guarantee for new subscriptions.",
},
{
value: "b3",
question: "Can I change my plan anytime?",
answer:
"Yes, you can upgrade or downgrade in settings; changes are prorated.",
},
],
support: [
{
value: "s1",
question: "How do I contact support?",
answer:
"Our support team is available 24/7 via live chat, email, and phone.",
},
{
value: "s2",
question: "How long does response take?",
answer: "We typically respond within 1-2 hours during business hours.",
},
{
value: "s3",
question: "Do you have a knowledge base?",
answer:
"Yes, our comprehensive help center is available at help.example.com.",
},
],
}
const categories: FaqCategory[] = [
{
label: "Account",
value: "account",
icon: (
<UserIcon aria-hidden="true" className="size-4" />
),
},
{
label: "Billing",
value: "billing",
icon: (
<CreditCardIcon aria-hidden="true" className="size-4" />
),
},
{
label: "Support",
value: "support",
icon: (
<MailIcon aria-hidden="true" className="size-4" />
),
},
]
export function Faq() {
return (
<section
aria-label="FAQ"
className="mx-auto flex w-full max-w-4xl flex-col gap-8 text-foreground motion-reduce:**:animate-none motion-reduce:**:transition-none"
>
<header className="flex flex-col gap-3">
<p className="text-sm text-muted-foreground">Help by team</p>
<div className="flex flex-col gap-2">
<h1 className="text-3xl font-semibold tracking-tight text-balance sm:text-4xl md:text-5xl">
Account, billing, or support
</h1>
<p className="text-muted-foreground">
Choose a team on the left, then open the matching questions.
</p>
</div>
</header>
<Tabs
defaultValue="account"
orientation="vertical"
className="flex w-full flex-col gap-6 md:flex-row md:gap-10"
>
<TabsList className="flex h-auto w-full gap-1 bg-transparent p-0 md:w-44 md:flex-col">
{categories.map(({ value, label, icon }) => (
<TabsTrigger
key={value}
value={value}
aria-label={label}
className="h-auto w-full justify-start gap-2 rounded-lg px-3 py-2 text-sm text-muted-foreground shadow-none after:hidden data-active:bg-muted! data-active:font-medium data-active:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-none!"
>
{icon}
<span className="inline max-sm:hidden">{label}</span>
</TabsTrigger>
))}
</TabsList>
{categories.map(({ value, label }) => (
<TabsContent key={value} value={value} className="min-w-0 flex-1">
<h2 className="sr-only">{label} questions</h2>
<Accordion
className="gap-1"
defaultValue={faqs[value].slice(0, 1).map((item) => item.value)}
>
{faqs[value].map((item) => (
<AccordionItem
key={item.value}
value={item.value}
className="border-0 transition-[border-radius,background-color,box-shadow] duration-200 data-open:rounded-2xl data-open:bg-card data-open:shadow-elevated-sm"
>
<AccordionTrigger className="px-4 py-3.5 text-left hover:no-underline">
{item.question}
</AccordionTrigger>
<AccordionContent className="flex flex-col gap-3 px-4 pb-4 text-muted-foreground">
<p className="text-sm leading-relaxed">{item.answer}</p>
<div className="flex gap-2">
<Button variant="outline" size="sm">
<ThumbsUpIcon aria-hidden="true" data-icon="inline-start" />
Helpful
</Button>
<Button variant="outline" size="sm">
<ThumbsDownIcon aria-hidden="true" data-icon="inline-start" />
Not helpful
</Button>
</div>
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</TabsContent>
))}
</Tabs>
<FancyButton size="lg" className="w-fit">
Reach support
</FancyButton>
</section>
)
}