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 type { Metadata, Viewport } from "next";
import Script from "next/script";
import { Cal_Sans, Geist_Mono, Bricolage_Grotesque } from "next/font/google"; import { Cal_Sans, Geist_Mono, Bricolage_Grotesque } from "next/font/google";
import localFont from "next/font/local"; import localFont from "next/font/local";
import { Toaster } from "@/components/ui/sonner"; 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. // içerikle büyümeli, viewport tabanı body'deki min-h-dvh'den gelir.
className={`${calSans.variable} ${clarityCity.variable} ${geistMono.variable} ${bricolage.variable} antialiased`} 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"> <body className="min-h-dvh flex flex-col bg-slate-50">
<HeaderGate> <HeaderGate>
{/* Site geneli progressive blur — üst ve alt */} {/* Site geneli progressive blur — üst ve alt */}

View File

@@ -21,7 +21,11 @@ export default async function OdemeSonucPage({
searchParams: Promise<{ siparis?: string }>; searchParams: Promise<{ siparis?: string }>;
}) { }) {
const { siparis } = await searchParams; 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 const order = siparis
? await appDb.query.orders.findFirst({ ? await appDb.query.orders.findFirst({

View File

@@ -1,10 +1,14 @@
import { import {
ArrowRight,
ArrowUpRight, ArrowUpRight,
BarChart3, BarChart3,
CheckCircle2, CheckCircle2,
Coins,
Compass, Compass,
FileText,
ListChecks, ListChecks,
MessageCircleQuestion, MessageCircleQuestion,
RefreshCcw,
ShieldCheck, ShieldCheck,
TrendingUp, TrendingUp,
Wallet, Wallet,
@@ -24,13 +28,14 @@ import {
PixelField, PixelField,
SectionEyebrow, SectionEyebrow,
} from "@/components/pixel-decor"; } from "@/components/pixel-decor";
import { URUNLER } from "@/lib/credits"; import { MAX_REVIZYON, URUNLER } from "@/lib/credits";
import { import {
Accordion, Accordion,
AccordionContent, AccordionContent,
AccordionItem, AccordionItem,
AccordionTrigger, AccordionTrigger,
} from "@/components/ui/accordion"; } from "@/components/ui/accordion";
import { Button } from "@/components/ui/button";
import { import {
Card, Card,
CardDescription, CardDescription,
@@ -160,10 +165,27 @@ const comparison = [
feature: "Fiyat", feature: "Fiyat",
robot: "Ücretsiz", robot: "Ücretsiz",
danisman: "2.00010.000 TL", 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 }) { function ComparisonCell({ value }: { value: boolean | string }) {
if (typeof value === "string") { if (typeof value === "string") {
return <span className="text-sm font-medium">{value}</span>; return <span className="text-sm font-medium">{value}</span>;
@@ -452,7 +474,102 @@ export default function Home() {
</div> </div>
</section> </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"> <div aria-hidden className="mx-auto w-56">
<Parallax strength={26}> <Parallax strength={26}>
<PixelDivider seed={31} /> <PixelDivider seed={31} />

View File

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

View File

@@ -1,6 +1,7 @@
"use client"; "use client";
import { useActionState, useEffect } from "react"; import { useActionState, useEffect } from "react";
import { ArrowRight } from "lucide-react";
import { toast } from "sonner"; import { toast } from "sonner";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { baslatOdeme, type OdemeBaslatDurum } from "./actions"; import { baslatOdeme, type OdemeBaslatDurum } from "./actions";
@@ -36,7 +37,14 @@ export function SatinAlForm({
} }
variant={vurgulu ? "default" : "outline"} 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> </Button>
</form> </form>
); );