feat(FN-204): i18n pricing/subscription/payment surfaces
Some checks failed
Sync dev → Gitea / Mirror dev to Gitea (push) Has been cancelled

Commits merged:
- feat(FN-204): i18n pricing/subscription/payment surfaces

Files changed:
.../web/src/components/payment/payment-content.tsx |  11 +-
 apps/web/src/lib/i18n.ts                           |  17 ++-
 apps/web/src/messages/en.json                      |  27 ++++-
 apps/web/src/messages/tr.json                      |  27 ++++-
 .../src/routes/dashboard/subscription/index.tsx    |   4 +-
 apps/web/src/routes/pricing.tsx                    | 127 +++++++++++----------
 6 files changed, 135 insertions(+), 78 deletions(-)

Fusion-Task-Id: FN-204
This commit is contained in:
Fusion
2026-05-12 18:11:25 +00:00
parent 688db7c990
commit ba43df45bc
6 changed files with 135 additions and 78 deletions

View File

@@ -381,7 +381,9 @@ function SubscriptionPage() {
<span className="text-sm text-muted-foreground">
{t("subscription.currentPlan")}
</span>
<Badge className="bg-brand text-brand-foreground">Full Paket</Badge>
<Badge className="bg-brand text-brand-foreground">
{t("subscription.plans.full.name")}
</Badge>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-muted-foreground">

View File

@@ -1,8 +1,10 @@
import { usePageMeta } from "@/hooks/use-page-meta";
import { useTranslation } from "@/lib/i18n";
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 } from "lucide-react";
export const Route = createFileRoute("/pricing")({
component: PricingPage,
@@ -10,60 +12,57 @@ export const Route = createFileRoute("/pricing")({
const plans = [
{
name: "1 Marka",
description: "Tek marka için yedek parça erişimi",
priceMonthly: "200",
priceYearly: "2.000",
features: ["1 marka seçimi", "Sınırsız VIN arama", "Parça kataloğu", "Şema görüntüleyici"],
key: "brand1",
brandLimit: 1,
priceMonthly: 20000,
priceYearly: 200000,
features: ["brandSelection", "vinSearch", "partsCatalog", "schemaViewer"],
},
{
name: "2 Marka",
description: "İki farklı marka için erişim",
priceMonthly: "350",
priceYearly: "3.500",
key: "brand2",
brandLimit: 2,
priceMonthly: 35000,
priceYearly: 350000,
popular: true,
features: [
"2 marka seçimi",
"Sınırsız VIN arama",
"Parça kataloğu",
"Şema görüntüleyici",
"Öncelikli destek",
],
features: ["brandSelection", "vinSearch", "partsCatalog", "schemaViewer", "prioritySupport"],
},
{
name: "3 Marka",
description: "Üç marka için kapsamlı erişim",
priceMonthly: "500",
priceYearly: "5.000",
features: [
"3 marka seçimi",
"Sınırsız VIN arama",
"Parça kataloğu",
"Şema görüntüleyici",
"Öncelikli destek",
],
key: "brand3",
brandLimit: 3,
priceMonthly: 50000,
priceYearly: 500000,
features: ["brandSelection", "vinSearch", "partsCatalog", "schemaViewer", "prioritySupport"],
},
{
name: "Full Paket",
description: "Tüm markalara sınırsız erişim",
priceMonthly: "999",
priceYearly: "9.990",
key: "full",
brandLimit: 999,
priceMonthly: 99900,
priceYearly: 999000,
features: [
"Tüm markalar",
"Sınırsız VIN arama",
"Parça kataloğu",
"Şema görüntüleyici",
"Öncelikli destek",
"OEM parça arama",
"allBrands",
"vinSearch",
"partsCatalog",
"schemaViewer",
"prioritySupport",
"oemSearch",
],
},
];
function formatTRY(amount: number): string {
return new Intl.NumberFormat("tr-TR", {
style: "currency",
currency: "TRY",
minimumFractionDigits: 2,
}).format(amount / 100);
}
function PricingPage() {
const { t } = useTranslation();
usePageMeta({
title: "Fiyatlandırma — Sase.tr | Şase Sorgulama Planları",
description:
"200 TL/ay'dan başlayan şase numarası ve OEM parça sorgulama planları. 30 gün ücretsiz deneyin.",
title: t("pricing.pageTitle"),
description: t("pricing.metaDescription"),
canonical: "https://sase.tr/pricing",
});
@@ -76,10 +75,10 @@ function PricingPage() {
</Link>
<div className="flex items-center gap-4">
<Link to="/login">
<Button variant="ghost">Giriş Yap</Button>
<Button variant="ghost">{t("common.login")}</Button>
</Link>
<Link to="/register">
<Button>Kayıt Ol</Button>
<Button>{t("common.register")}</Button>
</Link>
</div>
</div>
@@ -87,40 +86,52 @@ function PricingPage() {
<main id="main-content" className="container mx-auto px-4 py-24">
<div className="text-center">
<h1 className="text-4xl font-bold">Fiyatlandırma</h1>
<p className="mt-4 text-lg text-muted-foreground">İhtiyacınıza uygun planı seçin.</p>
<h1 className="text-4xl font-bold">{t("pricing.title")}</h1>
<p className="mt-4 text-lg text-muted-foreground">{t("pricing.subtitle")}</p>
</div>
<div className="mt-12 grid gap-6 md:grid-cols-2 lg:grid-cols-4">
{plans.map((plan) => (
<Card
key={plan.name}
key={plan.key}
className={plan.popular ? "border-primary shadow-lg relative" : ""}
>
{plan.popular && (
<Badge className="absolute -top-3 left-1/2 -translate-x-1/2">Popüler</Badge>
<Badge className="absolute -top-3 left-1/2 -translate-x-1/2">
{t("subscription.popular")}
</Badge>
)}
<CardHeader>
<CardTitle>{plan.name}</CardTitle>
<CardDescription>{plan.description}</CardDescription>
<CardTitle>{t(`subscription.plans.${plan.key}.name`)}</CardTitle>
<CardDescription>{t(`subscription.plans.${plan.key}.description`)}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div>
<span className="text-3xl font-bold">{plan.priceMonthly} TL</span>
<span className="text-muted-foreground">/ay</span>
<span className="text-3xl font-bold">{formatTRY(plan.priceMonthly)}</span>
<span className="text-muted-foreground">{t("common.perMonth")}</span>
</div>
<p className="text-sm text-muted-foreground">veya {plan.priceYearly} TL/yıl</p>
<p className="text-sm text-muted-foreground">
{t("pricing.orYearly", {
price: formatTRY(plan.priceYearly).replace(/[₺\s]/g, "").trim(),
})}
</p>
<ul className="space-y-2 text-sm">
{plan.features.map((f) => (
<li key={f} className="flex items-center gap-2">
<span className="text-primary">&#10003;</span>
{f}
</li>
))}
{plan.features.map((f) => {
const featureLabel =
f === "brandSelection"
? t(`subscription.features.${f}`, { count: plan.brandLimit })
: t(`subscription.features.${f}`);
return (
<li key={f} className="flex items-center gap-2">
<Check className="h-4 w-4 text-primary" />
{featureLabel}
</li>
);
})}
</ul>
<Link to="/register">
<Button className="w-full" variant={plan.popular ? "default" : "outline"}>
Başla
{t("pricing.getStarted")}
</Button>
</Link>
</CardContent>