Add Rybbit analytics script and enhance pricing section with new features
All checks were successful
Deploy / deploy (push) Successful in 14m22s

- Integrated Rybbit analytics script in layout.tsx for improved tracking.
- Updated pricing section in page.tsx to include detailed package features and pricing information.
- Refined button interactions and added icons for better user engagement.
- Adjusted return URL handling in odeme/sonuc/page.tsx to preserve order information.
- Enhanced satin-al-form.tsx to include visual indicators for payment redirection.
This commit is contained in:
bilalgursen
2026-08-02 18:49:17 +03:00
parent bd613adb8a
commit cc9686147e
5 changed files with 159 additions and 15 deletions

View File

@@ -1,4 +1,5 @@
import type { Metadata, Viewport } from "next";
import Script from "next/script";
import { Cal_Sans, Geist_Mono, Bricolage_Grotesque } from "next/font/google";
import localFont from "next/font/local";
import { Toaster } from "@/components/ui/sonner";
@@ -83,6 +84,12 @@ export default function RootLayout({
// içerikle büyümeli, viewport tabanı body'deki min-h-dvh'den gelir.
className={`${calSans.variable} ${clarityCity.variable} ${geistMono.variable} ${bricolage.variable} antialiased`}
>
{/* Rybbit analytics — beforeInteractive her zaman <head> içine defer olarak enjekte edilir */}
<Script
src="https://rybbit.kolaytercih.com/api/script.js"
data-site-id="f2cb042c657e"
strategy="beforeInteractive"
/>
<body className="min-h-dvh flex flex-col bg-slate-50">
<HeaderGate>
{/* Site geneli progressive blur — üst ve alt */}

View File

@@ -21,7 +21,11 @@ export default async function OdemeSonucPage({
searchParams: Promise<{ siparis?: string }>;
}) {
const { siparis } = await searchParams;
const session = await verifySession("/paket");
// Oturum düşmüşse geri dönüşte ?siparis= kaybolmasın (başarı/unblur deneyimi)
const geriDonus = siparis
? `/odeme/sonuc?siparis=${encodeURIComponent(siparis)}`
: "/paket";
const session = await verifySession(geriDonus);
const order = siparis
? await appDb.query.orders.findFirst({

View File

@@ -1,10 +1,14 @@
import {
ArrowRight,
ArrowUpRight,
BarChart3,
CheckCircle2,
Coins,
Compass,
FileText,
ListChecks,
MessageCircleQuestion,
RefreshCcw,
ShieldCheck,
TrendingUp,
Wallet,
@@ -24,13 +28,14 @@ import {
PixelField,
SectionEyebrow,
} from "@/components/pixel-decor";
import { URUNLER } from "@/lib/credits";
import { MAX_REVIZYON, URUNLER } from "@/lib/credits";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Button } from "@/components/ui/button";
import {
Card,
CardDescription,
@@ -160,10 +165,27 @@ const comparison = [
feature: "Fiyat",
robot: "Ücretsiz",
danisman: "2.00010.000 TL",
tercihai: "İnsan danışmanın ~10'da 1'i",
tercihai: `${PAKET_FIYATI} TL · tek seferlik`,
},
];
const paketOzellikleri = [
{
icon: ListChecks,
text: "Sıralamana özel, gerekçeli 24 tercihlik dengeli liste",
},
{
icon: ShieldCheck,
text: "Her tercih için yerleşme olasılığı ve risk analizi (son 4 yıl)",
},
{ icon: FileText, text: "Veliyle paylaşılabilir PDF rapor" },
{ icon: RefreshCcw, text: `${MAX_REVIZYON} liste revizyon hakkı` },
{
icon: MessageCircleQuestion,
text: `${URUNLER.paket.credits} yapay zekâ danışman sorusu`,
},
] as const;
function ComparisonCell({ value }: { value: boolean | string }) {
if (typeof value === "string") {
return <span className="text-sm font-medium">{value}</span>;
@@ -452,7 +474,102 @@ export default function Home() {
</div>
</section>
{/* Karşılaştırma → SSS geçişi */}
{/* Karşılaştırma → Fiyat geçişi */}
<div aria-hidden className="mx-auto w-56">
<Parallax strength={26}>
<PixelDivider seed={29} />
</Parallax>
</div>
{/* Fiyat */}
<section id="fiyat" className="scroll-mt-24 py-20 sm:py-24">
<div className="mx-auto max-w-4xl px-4">
<Parallax strength={16}>
<Reveal className="flex flex-col items-center gap-4 text-center">
<SectionEyebrow>Tek seferlik · Abonelik yok</SectionEyebrow>
<h2 className="font-heading text-3xl font-bold sm:text-4xl">
Ne kadar? Ne dahil?
</h2>
<p className="max-w-xl text-lg leading-relaxed text-slate-600">
İnsan danışmanın 2.00010.000 TL aldığı işi tek seferlik{" "}
{PAKET_FIYATI} TL&apos;ye alırsın. Abonelik yok, gizli ücret
yok.
</p>
</Reveal>
</Parallax>
<Parallax
strength={7}
className="mt-12 grid gap-6 sm:grid-cols-[1fr_auto]"
>
<Reveal
delay={0.08}
className="rounded-2xl border-2 border-orange-500 bg-white p-8 shadow-sm"
>
<div className="flex flex-wrap items-baseline justify-between gap-2">
<h3 className="font-heading text-xl font-bold">
{URUNLER.paket.label}
</h3>
<p className="font-heading text-3xl font-bold">
{PAKET_FIYATI} TL
</p>
</div>
<ul className="mt-6 space-y-3">
{paketOzellikleri.map((o) => (
<li
key={o.text}
className="flex items-start gap-3 text-sm text-slate-700"
>
<o.icon
className="mt-0.5 size-4 shrink-0 text-emerald-600"
aria-hidden
/>
{o.text}
</li>
))}
</ul>
<Button
asChild
className="mt-8 h-12 w-full cursor-pointer bg-orange-500 px-8 text-white transition-colors duration-200 hover:bg-orange-600"
>
<Link href="/paket">
{PAKET_FIYATI} TL Paketi incele
<ArrowRight className="size-4" aria-hidden />
</Link>
</Button>
<p className="mt-4 text-center text-xs text-slate-500">
Temel program arama herkes için ücretsiz · iyzico güvenli ödeme
</p>
</Reveal>
<Reveal
delay={0.16}
className="flex h-fit flex-col rounded-2xl border border-slate-200/70 bg-white p-6 shadow-sm sm:w-56"
>
<div className="flex items-center gap-2">
<Coins className="size-4 text-amber-500" aria-hidden />
<h3 className="font-heading font-bold">Kredi bitti mi?</h3>
</div>
<p className="mt-2 flex-1 text-sm leading-relaxed text-slate-600">
+{URUNLER.topup.credits} soru hakkı, {TOPUP_FIYATI} TL. Pakete
ek olarak, istediğin zaman.
</p>
<Button
asChild
variant="outline"
className="mt-4 h-11 w-full cursor-pointer"
>
<Link href="/paket">
+{URUNLER.topup.credits} kredi {TOPUP_FIYATI} TL
<ArrowRight className="size-4" aria-hidden />
</Link>
</Button>
</Reveal>
</Parallax>
</div>
</section>
{/* Fiyat → SSS geçişi */}
<div aria-hidden className="mx-auto w-56">
<Parallax strength={26}>
<PixelDivider seed={31} />

View File

@@ -1,6 +1,7 @@
import Link from "next/link";
import type { Metadata } from "next";
import {
ArrowRight,
CheckCircle2,
Coins,
FileText,
@@ -122,6 +123,7 @@ export default async function PaketPage({
/>
)
) : (
<div className="space-y-2">
<Button
asChild
className="h-12 w-full cursor-pointer bg-orange-500 px-8 text-white transition-colors duration-200 hover:bg-orange-600"
@@ -129,9 +131,15 @@ export default async function PaketPage({
<Link
href={`/giris?callback=${encodeURIComponent("/paket")}`}
>
Giriş yap ve {DENEME_KREDISI} deneme kredisi kazan
Giriş yap sonra {tl(URUNLER.paket.amountKurus)} TL&apos;ye
al
<ArrowRight className="size-4" aria-hidden />
</Link>
</Button>
<p className="text-center text-xs text-slate-500">
Girişte {DENEME_KREDISI} deneme kredisi de tanımlanır.
</p>
</div>
)}
</div>
<p className="mt-4 text-center text-xs text-slate-500">
@@ -159,7 +167,7 @@ export default async function PaketPage({
{u ? (
<SatinAlForm
urun="topup"
label={`+${URUNLER.topup.credits} kredi al`}
label={`+${URUNLER.topup.credits} kredi ${tl(URUNLER.topup.amountKurus)} TL`}
/>
) : (
<Button

View File

@@ -1,6 +1,7 @@
"use client";
import { useActionState, useEffect } from "react";
import { ArrowRight } from "lucide-react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { baslatOdeme, type OdemeBaslatDurum } from "./actions";
@@ -36,7 +37,14 @@ export function SatinAlForm({
}
variant={vurgulu ? "default" : "outline"}
>
{pending ? "Ödeme sayfasına yönlendiriliyorsun…" : label}
{pending ? (
"Ödeme sayfasına yönlendiriliyorsun…"
) : (
<>
{label}
<ArrowRight className="size-4" aria-hidden />
</>
)}
</Button>
</form>
);