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:
@@ -442,7 +442,22 @@
|
||||
"orYearly": "or {price}/year",
|
||||
"yearlySave": "· 2 months free",
|
||||
"getStarted": "Start Free",
|
||||
"pageTitle": "Pricing — Sase.tr | Chassis Search Plans"
|
||||
"pageTitle": "Pricing — Sase.tr | Chassis Search Plans",
|
||||
"faq": {
|
||||
"title": "Frequently asked questions",
|
||||
"q1": "How does the free trial work?",
|
||||
"a1": "When you sign up you get the Full Package free for 30 days — unlimited access to every brand. No credit card required.",
|
||||
"q2": "Do I need a credit card?",
|
||||
"a2": "No. We don't ask for card details to start the trial. You're only charged when you choose to move to a paid plan.",
|
||||
"q3": "Can I cancel anytime?",
|
||||
"a3": "Yes. Cancel your subscription in one click; your access continues until the end of the period you've paid for.",
|
||||
"q4": "Can I get a refund?",
|
||||
"a4": "If you're not satisfied within 7 days of payment, we'll refund you.",
|
||||
"q5": "Can I change my plan or brands later?",
|
||||
"a5": "Yes. You can upgrade, downgrade, or change the brands you have access to at any time.",
|
||||
"q6": "Is payment secure?",
|
||||
"a6": "Payments are processed on Stripe's PCI-DSS Level 1 infrastructure; we never see your card details. All data is stored in KVKK compliance."
|
||||
}
|
||||
},
|
||||
"language": {
|
||||
"tr": "Türkçe",
|
||||
|
||||
@@ -442,7 +442,22 @@
|
||||
"orYearly": "veya {price}/yıl",
|
||||
"yearlySave": "· 2 ay bedava",
|
||||
"getStarted": "Ücretsiz Başla",
|
||||
"pageTitle": "Fiyatlandırma — Sase.tr | Şase Sorgulama Planları"
|
||||
"pageTitle": "Fiyatlandırma — Sase.tr | Şase Sorgulama Planları",
|
||||
"faq": {
|
||||
"title": "Sık sorulan sorular",
|
||||
"q1": "Ücretsiz deneme nasıl çalışır?",
|
||||
"a1": "Kayıt olduğunda 30 gün boyunca Full Paket'i ücretsiz kullanırsın — tüm markalara sınırsız erişim. Kredi kartı gerekmez.",
|
||||
"q2": "Kredi kartı gerekiyor mu?",
|
||||
"a2": "Hayır. Denemeye başlamak için kart bilgisi istemiyoruz. Ödeme yalnızca ücretli bir plana geçmeyi seçtiğinde alınır.",
|
||||
"q3": "İstediğim zaman iptal edebilir miyim?",
|
||||
"a3": "Evet. Aboneliğini tek tıkla iptal edebilirsin; ödediğin dönemin sonuna kadar erişimin devam eder.",
|
||||
"q4": "Param iade edilir mi?",
|
||||
"a4": "Ödemeden sonraki 7 gün içinde memnun kalmazsan ücretini iade ediyoruz.",
|
||||
"q5": "Sonradan plan veya marka değiştirebilir miyim?",
|
||||
"a5": "Evet. Planını dilediğin zaman yükseltebilir, düşürebilir veya erişimindeki markaları değiştirebilirsin.",
|
||||
"q6": "Ödeme güvenli mi?",
|
||||
"a6": "Ödemeler Stripe'ın PCI-DSS Seviye 1 altyapısında işlenir; kart bilgilerini biz görmeyiz. Tüm veriler KVKK uyumlu saklanır."
|
||||
}
|
||||
},
|
||||
"language": {
|
||||
"tr": "Türkçe",
|
||||
|
||||
36
apps/web/src/routes/__tests__/pricing-faq.test.tsx
Normal file
36
apps/web/src/routes/__tests__/pricing-faq.test.tsx
Normal 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);
|
||||
});
|
||||
});
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user