feat(web): add FAQ section to pricing page

The pricing page had no objection handling and a half-empty page below the
cards. Added a PricingFaq disclosure section (native <details>) covering the
six recurring questions: how the free trial works, whether a card is needed,
cancellation, refunds, changing plan/brands, and payment security — all
grounded in actual product behaviour (30-day Full trial, no card, period-end
access on cancel, downgrade, Stripe PCI-DSS / KVKK).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-25 16:15:03 +03:00
parent d895c9dd28
commit b8c2e7568a
4 changed files with 94 additions and 3 deletions

View File

@@ -0,0 +1,36 @@
/**
* Tests the pricing FAQ — the objection-handling section that fills the
* previously-empty space below the cards (trial, credit card, cancel,
* refund, plan/brand change, payment security).
*/
import { render } from "@testing-library/react";
import { vi } from "vitest";
vi.mock("@/lib/i18n", () => ({
useTranslation: () => ({
t: (key: string) => key,
locale: "tr",
setLocale: vi.fn(),
}),
}));
import { PricingFaq } from "@/routes/pricing";
describe("PricingFaq", () => {
test("renders the title and all six question/answer pairs", () => {
const { container } = render(<PricingFaq />);
const text = container.textContent ?? "";
expect(text).toContain("pricing.faq.title");
for (let i = 1; i <= 6; i++) {
expect(text).toContain(`pricing.faq.q${i}`);
expect(text).toContain(`pricing.faq.a${i}`);
}
});
test("uses native <details> disclosures (one per question)", () => {
const { container } = render(<PricingFaq />);
expect(container.querySelectorAll("details")).toHaveLength(6);
expect(container.querySelectorAll("summary")).toHaveLength(6);
});
});

View File

@@ -7,7 +7,7 @@ import { Button } from "@sase/ui";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@sase/ui";
import { Badge } from "@sase/ui";
import { Link, createFileRoute } from "@tanstack/react-router";
import { Check, Info } from "lucide-react";
import { Check, ChevronDown, Info } from "lucide-react";
export const Route = createFileRoute("/pricing")({
component: PricingPage,
@@ -143,7 +143,32 @@ function PricingPage() {
<div className="mx-auto mt-12 max-w-5xl">
<CredibilityStrip />
</div>
<PricingFaq />
</main>
</div>
);
}
export function PricingFaq() {
const { t } = useTranslation();
const ids = [1, 2, 3, 4, 5, 6] as const;
return (
<section className="mx-auto mt-20 max-w-3xl">
<h2 className="text-center text-2xl font-bold">{t("pricing.faq.title")}</h2>
<div className="mt-8 divide-y divide-border overflow-hidden rounded-2xl border border-border">
{ids.map((i) => (
<details key={i} className="group">
<summary className="flex cursor-pointer list-none items-center justify-between gap-4 p-5 font-medium">
{t(`pricing.faq.q${i}`)}
<ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground transition-transform group-open:rotate-180" />
</summary>
<p className="px-5 pb-5 text-sm leading-6 text-muted-foreground">
{t(`pricing.faq.a${i}`)}
</p>
</details>
))}
</div>
</section>
);
}