"use client"; // Dev süperadmin paneli: yalnızca geliştirme ortamında render edilir // (layout.tsx NODE_ENV kontrolüyle monte eder; aksiyonlar da sunucuda // ayrıca korunur). Amaç: satın alma / giriş / kredi durumlarını tek // tıkla taklit edip uygulamanın tüm sayfalarını gerçek akışta gezmek. // // Yüzey opak kutu değil, yarı saydam malzemedir. import { useCallback, useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { Wrench, X } from "lucide-react"; import { toast } from "sonner"; import { authClient } from "@/lib/auth-client"; import { tercihProfiliSil } from "@/features/sihirbaz/sihirbaz-profil"; import { devAnindaGiris, devAyarla, devDurum, devRaporSil, devSahteOdeme, type DevDurum, } from "@/lib/dev/actions"; const SAYFALAR: { ad: string; href: string }[] = [ { ad: "Ana sayfa", href: "/" }, { ad: "Sonuç (sırasız)", href: "/sonuc" }, { ad: "Sonuç (85k · SAY)", href: "/sonuc?sira=85000&tur=say&sihirbaz=1" }, { ad: "Sonuç (girişsiz hazır)", href: "/sonuc?sira=85000&tur=say&hazir=1" }, { ad: "Listem", href: "/listem" }, { ad: "Listem (kilit açılışı)", href: "/listem?acildi=1" }, { ad: "Paket", href: "/paket" }, { ad: "Paket (ödeme hatası)", href: "/paket?hata=token" }, { ad: "PDF / yazdır", href: "/rapor/yazdir" }, { ad: "Bölümler", href: "/bolumler" }, { ad: "Bölüm (bilg. müh.)", href: "/bolum/bilgisayar-muhendisligi" }, { ad: "Üniversiteler", href: "/universiteler" }, { ad: "Üniversite (Boğaziçi)", href: "/universite/bogazici-universitesi" }, { ad: "Rehber", href: "/rehber" }, { ad: "Rehber (devlet/vakıf)", href: "/rehber/devlet-mi-vakif-mi" }, { ad: "Meraklısına", href: "/meraklisina" }, { ad: "Giriş", href: "/giris" }, { ad: "Gizlilik", href: "/gizlilik" }, { ad: "Koşullar", href: "/kosullar" }, { ad: "İletişim", href: "/iletisim" }, { ad: "404", href: "/boyle-bir-sayfa-yok" }, ]; // Basış anında tepki (pointer-down feedback) — bırakınca değil. const BASIS = "active:scale-[0.97] transition-[transform,background-color,border-color,opacity] duration-150 ease-out"; // Yarı saydam malzeme; şeffaflık azaltılsın diyen kullanıcıya opak yüzey. const MALZEME = "border border-white/60 bg-card/80 shadow-2xl shadow-slate-900/20 backdrop-blur-2xl backdrop-saturate-150 " + "[@media(prefers-reduced-transparency:reduce)]:bg-card [@media(prefers-reduced-transparency:reduce)]:backdrop-blur-none"; export function DevPanel() { const [acik, setAcik] = useState(false); const [durum, setDurum] = useState(null); const [email, setEmail] = useState("test@kolaytercih.dev"); const [mesgul, setMesgul] = useState(false); const router = useRouter(); const yenile = useCallback(async () => { try { setDurum(await devDurum()); } catch { setDurum(null); } }, []); function paneliAc() { setAcik(true); void yenile(); } // Yol bulma: panelden çıkış her an mümkün — Escape da kapatır. useEffect(() => { if (!acik) return; const f = (e: KeyboardEvent) => { if (e.key === "Escape") setAcik(false); }; window.addEventListener("keydown", f); return () => window.removeEventListener("keydown", f); }, [acik]); // Her aksiyonu tek kalıptan geçir: meşgul kilidi + durum tazeleme + // server component'lerin (header'daki kredi rozeti dahil) yenilenmesi async function calistir(fn: () => Promise) { setMesgul(true); try { await fn(); await yenile(); router.refresh(); } catch (e) { toast.error(e instanceof Error ? e.message : "Dev aksiyonu başarısız."); } finally { setMesgul(false); } } async function anindaGiris() { setMesgul(true); try { const sonuc = await devAnindaGiris(email); if (!sonuc.ok) { toast.error(sonuc.error); return; } // Verify URL'i oturumu kurup callback'e yönlendirir window.location.assign(sonuc.url); } catch (e) { // Sunucu hatası (ör. e-posta gönderimi) sessiz kalmasın (6 Eki 2026 QA) toast.error(e instanceof Error ? e.message : "Anında giriş başarısız."); } finally { setMesgul(false); } } async function odemeEkrani() { setMesgul(true); try { const sonuc = await devSahteOdeme(); if (!sonuc.ok) { toast.error(sonuc.error); return; } router.push(`/odeme/sonuc?siparis=${sonuc.siparis}`); } finally { setMesgul(false); } } const g = durum?.girisli ? durum : null; return ( <> {!acik ? ( ) : (
{/* Başlık: opak şerit değil, aynı malzemenin üstünde ince bir kenar çizgisiyle ayrışan katman. */}

Dev süperadmin {mesgul ? ( ) : null}

{/* Oturum */}

Oturum

{g ? (

{g.email}

{g.kredi} kredi · {g.hasPaket ? "paketli" : "paketsiz"} ·{" "} {g.raporVar ? `rapor var (${g.sira?.toLocaleString("tr-TR")} · ${g.tur})` : "rapor yok"}

) : (

Girişsiz geziyorsun.

)}
setEmail(e.target.value)} placeholder="deneme@ornek.dev" className="h-9 min-w-0 flex-1 rounded-lg border border-slate-900/10 bg-card/70 px-2.5 text-xs outline-none transition-colors duration-150 focus-visible:border-violet-400" />

Yeni e-posta = 5 kredili yeni kullanıcı (magic link atlanır).

{/* Senaryolar */}

Senaryo

{( [ { ad: "Yeni kullanıcı", aciklama: "5 kredi · paketsiz · raporsuz", fn: async () => { await devAyarla({ kredi: 5, hasPaket: false }); await devRaporSil(); }, }, { ad: "Paketli", aciklama: "60 kredi · paket aktif", fn: () => devAyarla({ kredi: 60, hasPaket: true }), }, { ad: "Kredisi bitmiş", aciklama: "0 kredi", fn: () => devAyarla({ kredi: 0 }), }, { ad: "Raporu sil", aciklama: "boş durumlar", fn: () => devRaporSil(), }, ] as const ).map((s) => ( ))}
{/* Sıra + sihirbaz profili localStorage'ta yaşar; girişten bağımsızdır — bu yüzden !g ile kilitlenmez. */}
{/* Sayfalar */}

Sayfalar

{SAYFALAR.map((s) => ( {s.ad} ))}
)} ); }