feat(web): add credibility strip to subscription page
The page had no credibility signal at the point of conversion. Added a CredibilityStrip under the header (shown only to converting users: no-sub / trial / expired / pending) surfacing real, verifiable product facts — 50+ marka, 1M+ parça, OEM + alternatif kodlar, saniyede sonuç, KVKK uyumlu · SSL. Deliberately no fabricated customer counts or testimonials. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Tests for the CredibilityStrip shown to converting users (no-sub / trial /
|
||||
* expired / pending). It surfaces only real, verifiable product facts — data
|
||||
* scale, speed and security — NOT fabricated customer counts or testimonials.
|
||||
*/
|
||||
|
||||
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 { CredibilityStrip } from "@/routes/dashboard/subscription/index";
|
||||
|
||||
describe("CredibilityStrip", () => {
|
||||
test("renders all five product-fact items", () => {
|
||||
const { container } = render(<CredibilityStrip />);
|
||||
const text = container.textContent ?? "";
|
||||
for (const key of ["brands", "parts", "oem", "speed", "security"]) {
|
||||
expect(text).toContain(`subscription.credibility.${key}`);
|
||||
}
|
||||
});
|
||||
|
||||
test("each item pairs an icon (svg) with its label", () => {
|
||||
const { container } = render(<CredibilityStrip />);
|
||||
const svgs = container.querySelectorAll("svg");
|
||||
expect(svgs.length).toBe(5);
|
||||
});
|
||||
});
|
||||
@@ -30,18 +30,22 @@ import { createFileRoute, useNavigate } from "@tanstack/react-router";
|
||||
import {
|
||||
AlertTriangle,
|
||||
ArrowRight,
|
||||
Boxes,
|
||||
Check,
|
||||
CheckCircle2,
|
||||
Clock,
|
||||
CreditCard,
|
||||
Crown,
|
||||
Hash,
|
||||
Info,
|
||||
Layers,
|
||||
Loader2,
|
||||
Minus,
|
||||
Pencil,
|
||||
ShieldCheck,
|
||||
Sparkles,
|
||||
X,
|
||||
Zap,
|
||||
} from "lucide-react";
|
||||
import { Suspense, lazy, useEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
@@ -550,6 +554,8 @@ export function SubscriptionPage() {
|
||||
<p className="text-sm text-muted-foreground">{t("subscription.subtitle")}</p>
|
||||
</header>
|
||||
|
||||
{showStepper && <CredibilityStrip />}
|
||||
|
||||
{subscription && hasActiveSub && (
|
||||
<ActiveSubscriptionCard
|
||||
subscription={subscription}
|
||||
@@ -941,6 +947,29 @@ function StepCard({
|
||||
);
|
||||
}
|
||||
|
||||
export function CredibilityStrip() {
|
||||
const { t } = useTranslation();
|
||||
const items = [
|
||||
{ icon: Layers, key: "brands" },
|
||||
{ icon: Boxes, key: "parts" },
|
||||
{ icon: Hash, key: "oem" },
|
||||
{ icon: Zap, key: "speed" },
|
||||
{ icon: ShieldCheck, key: "security" },
|
||||
] as const;
|
||||
return (
|
||||
<div className="grid grid-cols-2 gap-x-4 gap-y-3 rounded-2xl border border-border bg-muted/20 px-5 py-4 sm:grid-cols-3 lg:grid-cols-5">
|
||||
{items.map(({ icon: Icon, key }) => (
|
||||
<div key={key} className="flex items-center gap-2 text-sm">
|
||||
<Icon className="h-4 w-4 shrink-0 text-primary" />
|
||||
<span className="font-medium leading-5 text-foreground/85">
|
||||
{t(`subscription.credibility.${key}`)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function PlanHelperHint() {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user