feat(storefront): update FAQ and legal documentation

- Added new FAQ sections for account security, ordering and checkout, returns, shipping, and contact information.
- Introduced legal documents including privacy policy, terms of service, data protection, and general terms and conditions.
- Updated package dependencies to include gray-matter and remark-gfm for enhanced markdown support.
This commit is contained in:
2026-03-13 21:39:25 +03:00
parent f1dbf0b6ee
commit c8f5d8d096
52 changed files with 2273 additions and 261 deletions

View File

@@ -0,0 +1,132 @@
"use client";
import { Accordion } from "@heroui/react";
import Link from "next/link";
import { useMemo, useState } from "react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import type { FaqSection } from "@/lib/faq/getFaqSections";
type FaqPageViewProps = {
sections: FaqSection[];
lastUpdated?: string;
};
function FaqAnswer({ content }: { content: string }) {
return (
<ReactMarkdown
remarkPlugins={[remarkGfm]}
components={{
a: ({ href, children }) =>
href?.startsWith("/") ? (
<Link
href={href}
className="font-medium text-[#38a99f] underline transition-colors hover:text-[#236f6b]"
>
{children}
</Link>
) : (
<a
href={href}
className="font-medium text-[#38a99f] underline transition-colors hover:text-[#236f6b]"
target="_blank"
rel="noopener noreferrer"
>
{children}
</a>
),
}}
>
{content}
</ReactMarkdown>
);
}
export function FaqPageView({ sections, lastUpdated }: FaqPageViewProps) {
const [selectedId, setSelectedId] = useState<string | null>(null);
const selectedSection = useMemo(
() => (selectedId ? sections.find((s) => s.title === selectedId) ?? null : null),
[sections, selectedId]
);
const sectionId = (title: string) => title.replace(/\s+/g, "-").toLowerCase();
return (
<div className="space-y-8">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
{sections.map((section) => {
const id = sectionId(section.title);
const isSelected = selectedId === section.title;
return (
<button
key={id}
type="button"
onClick={() => setSelectedId(isSelected ? null : section.title)}
className="flex flex-col items-start rounded-lg border-2 border-[#236f6b]/20 bg-[#f0f8f7] p-5 text-left transition-colors hover:border-[#38a99f] hover:bg-[#e8f7f6] focus:outline-none focus:ring-2 focus:ring-[#38a99f] focus:ring-offset-2"
aria-expanded={isSelected}
data-selected={isSelected ? "" : undefined}
style={
isSelected
? { borderColor: "#236f6b", backgroundColor: "#e8f7f6" }
: undefined
}
>
<span className="font-[family-name:var(--font-fraunces)] text-lg font-semibold text-[#1a2e2d]">
{section.title}
</span>
{section.subtitle && (
<span className="mt-1 text-sm text-[#3d5554]">
{section.subtitle}
</span>
)}
</button>
);
})}
</div>
{selectedSection && selectedSection.items.length > 0 && (
<section
id={`faq-${sectionId(selectedSection.title)}`}
aria-labelledby={`faq-heading-${sectionId(selectedSection.title)}`}
className="rounded-lg border border-[#236f6b]/20 bg-white p-4 md:p-6"
>
<h2
id={`faq-heading-${sectionId(selectedSection.title)}`}
className="font-[family-name:var(--font-fraunces)] text-xl font-semibold text-[#236f6b]"
>
{selectedSection.title}
</h2>
<Accordion
allowsMultipleExpanded
className="mt-4 w-full"
hideSeparator={false}
>
{selectedSection.items.map((item, index) => (
<Accordion.Item
key={`${sectionId(selectedSection.title)}-${index}`}
id={`${sectionId(selectedSection.title)}-q-${index}`}
>
<Accordion.Heading>
<Accordion.Trigger className="text-left text-sm font-medium text-[#1a2e2d]">
{item.question}
<Accordion.Indicator />
</Accordion.Trigger>
</Accordion.Heading>
<Accordion.Panel>
<Accordion.Body className="pb-4 pt-1 text-[#1a2e2d] leading-relaxed [&_a]:font-medium [&_a]:text-[#38a99f] [&_a]:underline [&_a:hover]:text-[#236f6b]">
<FaqAnswer content={item.answer} />
</Accordion.Body>
</Accordion.Panel>
</Accordion.Item>
))}
</Accordion>
</section>
)}
{lastUpdated && (
<p className="text-sm text-[#3d5554]">Last updated: {lastUpdated}</p>
)}
</div>
);
}