feat: kimlik doğrulama, ödeme, kredi ve AI rapor sihirbazı ekle
- better-auth ile giriş/oturum yönetimi (src/lib/auth, giris sayfası) - iyzico ödeme entegrasyonu ve paket satın alma akışı - kredi sistemi ve uygulama veritabanı şeması (drizzle) - AI destekli rapor üretimi ve tercih sihirbazı - rapor yazdırma sayfası ve site header/kullanıcı menüsü Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
96
src/app/odeme/sonuc/page.tsx
Normal file
96
src/app/odeme/sonuc/page.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
import Link from "next/link";
|
||||
import type { Metadata } from "next";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { CheckCircle2, Sparkles, XCircle } from "lucide-react";
|
||||
import { verifySession } from "@/lib/session";
|
||||
import { appDb, schema } from "@/lib/appdb";
|
||||
import { odemeyiSonuclandir } from "@/lib/odeme";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Ödeme Sonucu — KolayTercih",
|
||||
};
|
||||
|
||||
export default async function OdemeSonucPage({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: Promise<{ siparis?: string }>;
|
||||
}) {
|
||||
const { siparis } = await searchParams;
|
||||
const session = await verifySession("/paket");
|
||||
|
||||
const order = siparis
|
||||
? await appDb.query.orders.findFirst({
|
||||
where: eq(schema.orders.id, siparis),
|
||||
})
|
||||
: null;
|
||||
|
||||
// Yalnızca kendi siparişi görüntülenebilir
|
||||
const sahibiMi = order?.userId === session.user.id;
|
||||
|
||||
// Self-healing: callback kaybolduysa burada tekrar doğrula
|
||||
const durum =
|
||||
order && sahibiMi
|
||||
? order.status === "paid"
|
||||
? "paid"
|
||||
: await odemeyiSonuclandir(order.id)
|
||||
: "not_found";
|
||||
|
||||
const basarili = durum === "paid";
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen flex-col bg-slate-50 text-slate-900">
|
||||
<main className="mx-auto flex w-full max-w-md flex-1 flex-col justify-center px-4 py-16 text-center">
|
||||
{basarili ? (
|
||||
<div className="rounded-2xl border border-emerald-200 bg-white p-8 shadow-sm">
|
||||
<CheckCircle2
|
||||
className="mx-auto size-12 text-emerald-500"
|
||||
aria-hidden
|
||||
/>
|
||||
<h1 className="mt-4 font-heading text-2xl font-bold">
|
||||
Ödeme alındı 🎉
|
||||
</h1>
|
||||
<p className="mt-2 text-sm text-slate-600">
|
||||
<span className="font-semibold">
|
||||
{order!.credits} kredi
|
||||
</span>{" "}
|
||||
hesabına tanımlandı
|
||||
{order!.product === "paket"
|
||||
? " ve Tercih Dönemi Paketi'n aktif — kişisel listen, risk raporun ve PDF çıktın hazır olduğunda burada."
|
||||
: "."}
|
||||
</p>
|
||||
<div className="mt-6 flex flex-col gap-2">
|
||||
<Button
|
||||
asChild
|
||||
className="h-11 cursor-pointer bg-orange-500 text-white transition-colors duration-200 hover:bg-orange-600"
|
||||
>
|
||||
<Link href="/">
|
||||
<Sparkles className="size-4" aria-hidden />
|
||||
24'lük listeni oluştur
|
||||
</Link>
|
||||
</Button>
|
||||
<p className="text-center text-xs text-slate-500">
|
||||
Sıralamanı girip sonuç sayfasındaki sihirbazla listeni kur.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="rounded-2xl border border-red-200 bg-white p-8 shadow-sm">
|
||||
<XCircle className="mx-auto size-12 text-red-500" aria-hidden />
|
||||
<h1 className="mt-4 font-heading text-2xl font-bold">
|
||||
Ödeme tamamlanamadı
|
||||
</h1>
|
||||
<p className="mt-2 text-sm text-slate-600">
|
||||
{durum === "pending"
|
||||
? "Ödemen hâlâ işleniyor. Birkaç saniye sonra bu sayfayı yenile — kartından çekim yapıldıysa krediler mutlaka tanımlanır."
|
||||
: "Çekim yapılmadı ya da işlem iptal edildi. Kartından para çekildiğini düşünüyorsan bizimle iletişime geç."}
|
||||
</p>
|
||||
<Button asChild variant="outline" className="mt-6 h-11 cursor-pointer">
|
||||
<Link href="/paket">Tekrar dene</Link>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user