Files
kolaytercih/src/features/odeme/components/odeme-sonuc-karti.tsx
bilalgursen 78ad84922a
All checks were successful
Deploy / deploy (push) Successful in 6m23s
feat(tema): açık / koyu / sistem teması
- TemaSaglayici (next-themes) + alt bilgide TemaSecici
- globals.css: .dark bloğunda palet token'ları çevrilir; bileşenlere
  dark: sınıfı yazılmaz
- yüzeyler bg-white → bg-card, koyu haplar text-slate-50, SVG'lerde
  sabit renk yerine değişken
- DESIGN.md §2.3 + tasarim-denetim kuralları (yuzey-beyaz,
  koyu-hap-beyaz-yazi, dark-sinif), AGENTS.md karanlık mod bölümü
- docs: koyu tema denetimi raporu

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-05 10:20:02 +03:00

162 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Link from "next/link";
import { ArrowRight, CheckCircle2, RotateCcw, XCircle } from "lucide-react";
import { verifySession } from "@/lib/session";
import { siparisGetir } from "../odeme-queries";
import { kullanicininRaporu } from "@/features/rapor/rapor-queries";
import { iadeEdilecekMi, odemeyiSonuclandir } from "@/lib/odeme";
import { Button } from "@/components/ui/button";
import { PagePixelDivider } from "@/components/pixel-decor";
import { Skeleton } from "@/components/ui/skeleton";
import { RaporYokCta } from "./rapor-yok-cta";
export async function OdemeSonucKarti({ siparis }: { siparis?: string }) {
// Oturum düşmüşse geri dönüşte ?siparis= kaybolmasın (başarı/unblur deneyimi)
const geriDonus = siparis
? `/odeme/sonuc?siparis=${encodeURIComponent(siparis)}`
: "/paket";
// Oturum ve sipariş sorgusu bağımsız; sahiplik kontrolü aşağıda yapılıyor
const [session, order] = await Promise.all([
verifySession(geriDonus),
siparis ? siparisGetir(siparis) : Promise.resolve(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. "paid" siparişte
// de çağrılır — kredisi yazılmamış eski kayıtları onarır (idempotent).
const durum =
order && sahibiMi ? await odemeyiSonuclandir(order.id) : "not_found";
const basarili = durum === "paid";
// Zaten paketliyken alınan ikinci paket ödemesi: kredi yazılmadı, iade edilir
const iade =
basarili && order
? await iadeEdilecekMi({ ...order, status: "paid" })
: false;
if (iade) {
return (
<div className="rounded-2xl border border-amber-200 bg-card p-8 shadow-sm">
<RotateCcw className="mx-auto size-12 text-amber-500" aria-hidden />
<h1 className="mt-4 font-heading text-2xl font-bold">
Bu ödeme iade edilecek
</h1>
<p className="mt-2 text-sm text-slate-600">
Tercih Dönemi Paketi&apos;n zaten aktifti; paket tek seferlik olduğu
için bu ikinci ödemeyi iade ediyoruz — senin bir şey yapmana gerek
yok. İade en geç 14 gün içinde yapılır; kartına yansıması bankana
göre birkaç gün daha sürebilir. Sorun olursa{" "}
<a
href="mailto:destek@kolaytercih.com"
className="font-medium text-primary underline-offset-2 hover:underline"
>
destek@kolaytercih.com
</a>
&apos;a yaz.
</p>
<PagePixelDivider seed={79} className="mx-auto mt-5" />
<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="/listem">
Listeme dön
<ArrowRight className="size-4" aria-hidden />
</Link>
</Button>
</div>
</div>
);
}
// Rapor zaten üretildiyse ödül bir tık uzakta: kullanıcıyı doğrudan
// rapor sayfasına döndür ki blur çözülme animasyonuyla tam listeyi görsün.
const rapor = basarili ? await kullanicininRaporu(session.user.id) : null;
const listeHref = rapor ? "/listem?acildi=1" : null;
return basarili ? (
<div className="rounded-2xl border border-emerald-200 bg-card 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>
<PagePixelDivider seed={79} className="mx-auto mt-5" />
<div className="mt-6 flex flex-col gap-2">
{listeHref ? (
<>
<Button
asChild
className="h-11 cursor-pointer bg-orange-500 text-white transition-colors duration-200 hover:bg-orange-600"
>
<Link href={listeHref}>
Listeni aç — kilidi kaldırdık
<ArrowRight className="size-4" aria-hidden />
</Link>
</Button>
<p className="text-center text-xs text-slate-500">
24 tercihin tamamı, gerekçeler, riskler ve PDF artık açık.
</p>
</>
) : (
<RaporYokCta />
)}
</div>
</div>
) : (
<div className="rounded-2xl border border-red-200 bg-card 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{" "}
<Link href="/iletisim" className="underline">
bizimle iletişime geç
</Link>
.
</>
)}
</p>
<PagePixelDivider seed={83} className="mx-auto mt-5" />
<Button asChild variant="outline" className="mt-6 h-11 cursor-pointer">
<Link href="/paket?kaynak=odeme_hata">Tekrar dene</Link>
</Button>
</div>
);
}
// iyzico doğrulaması beklenirken ortalanmış sonuç kartı iskeleti.
export function OdemeSonucKartiSkeleton() {
return (
<div
aria-live="polite"
className="rounded-2xl border border-slate-200 bg-card p-8 shadow-sm"
>
<Skeleton className="mx-auto size-12 rounded-full" />
<Skeleton className="mx-auto mt-5 h-7 w-2/3" />
<Skeleton className="mx-auto mt-3 h-5 w-full" />
<Skeleton className="mx-auto mt-2 h-5 w-3/4" />
<Skeleton className="mx-auto mt-6 h-12 w-full rounded-lg" />
</div>
);
}