"use client"; // Program satırındaki "netler" butonu: YÖK Atlas'ın "yerleşen son kişinin // netleri" verisini (data/yokatlas.db → netler tablosu, /api/netler) yıl // sütunlu tabloyla alttan açılan sayfada gösterir (DESIGN.md §4.10: ayrıntı // her zaman Drawer, ortada modal değil; §4.19 netler paneli). Kadın-erkek // dağılımı bilinçli olarak yok: YÖK Atlas 2026 SPA'sına geçerken cinsiyet // panelini yayından kaldırdı (bkz. scripts/detay.ts). import { SATIR_BASLIK, SATIR_DUGME_BOYU } from "@/components/liste-satiri"; import { useState } from "react"; import { ListChecks, X } from "lucide-react"; import type { ProgramNetSatiri } from "@/types/yokatlas"; import { olay } from "@/lib/analitik"; import { cn } from "@/lib/utils"; import { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerTitle, DrawerTrigger, } from "@/components/ui/drawer"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; // Ders sırası ÖSYM oturum sırasıyla; max = testteki soru sayısı. const DERSLER: { alan: keyof Omit; etiket: string; max: number; }[] = [ { alan: "tytTrkNet", etiket: "TYT Türkçe", max: 40 }, { alan: "tytSosNet", etiket: "TYT Sosyal Bilimler", max: 20 }, { alan: "tytMatNet", etiket: "TYT Matematik", max: 40 }, { alan: "tytFenNet", etiket: "TYT Fen Bilimleri", max: 20 }, { alan: "aytMatNet", etiket: "AYT Matematik", max: 40 }, { alan: "aytFizNet", etiket: "AYT Fizik", max: 14 }, { alan: "aytKimNet", etiket: "AYT Kimya", max: 13 }, { alan: "aytBioNet", etiket: "AYT Biyoloji", max: 13 }, { alan: "aytTdeNet", etiket: "AYT Türk Dili ve Edebiyatı", max: 24 }, { alan: "aytTrh1Net", etiket: "AYT Tarih-1", max: 10 }, { alan: "aytCog1Net", etiket: "AYT Coğrafya-1", max: 6 }, { alan: "aytTrh2Net", etiket: "AYT Tarih-2", max: 11 }, { alan: "aytCog2Net", etiket: "AYT Coğrafya-2", max: 11 }, { alan: "aytDinNet", etiket: "AYT Din Kültürü", max: 6 }, { alan: "aytFelNet", etiket: "AYT Felsefe Grubu", max: 12 }, { alan: "ydtYdilNet", etiket: "YDT Yabancı Dil", max: 80 }, ]; const net = (n: number) => n.toLocaleString("tr-TR", { maximumFractionDigits: 2 }); type Durum = "bekliyor" | "yukleniyor" | "hazir" | "hata"; export function ProgramNetleriButonu({ programId, isim, universite, className = "", }: { programId: string; isim: string; universite?: string; className?: string; }) { const [durum, setDurum] = useState("bekliyor"); const [netler, setNetler] = useState([]); async function yukle() { setDurum("yukleniyor"); try { const res = await fetch(`/api/netler?id=${programId}`); if (!res.ok) throw new Error(String(res.status)); const veri = (await res.json()) as { netler: ProgramNetSatiri[] }; setNetler(veri.netler); setDurum("hazir"); } catch { setDurum("hata"); } } function acildi(acik: boolean) { if (!acik) return; olay("netler_goruntulendi"); if (durum === "bekliyor" || durum === "hata") yukle(); } return ( {/* Çekmece kabı ve çarpı cta-sira-form.tsx'teki çekmeceyle birebir (§4.10, §4.3) */} e.stopPropagation()} > Kapat
Son yerleşenin netleri {isim} {universite ? ` · ${universite}` : ""} — bölüme en düşük puanla yerleşen adayın sınav netleri (YÖK Atlas).
); } function NetlerIcerik({ durum, netler, }: { durum: Durum; netler: ProgramNetSatiri[]; }) { if (durum === "yukleniyor" || durum === "bekliyor") { return (
{[0, 1, 2, 3, 4].map((i) => (
))}
); } if (durum === "hata") { return (

Netler yüklenemedi. Paneli kapatıp yeniden açmayı dene.

); } if (netler.length === 0) { return (

Bu program için YÖK Atlas'ta net verisi yayınlanmamış.

); } const dersler = DERSLER.filter((d) => netler.some((y) => y[d.alan] != null), ); // En yeni yıl vurgulu (§1.1 "sık bakılan önde"); eski yıllar bağlam. const sonYil = Math.max(...netler.map((y) => y.yil)); const hucre = (yil: number, vurgu = false) => cn( "py-2.5 text-right text-sm tabular-nums", yil === sonYil ? vurgu ? "font-semibold text-slate-900" : "font-semibold text-slate-800" : "text-slate-500", ); return ( Ders {netler.map((y) => ( {y.yil} ))} {dersler.map((d) => ( {d.etiket} / {d.max} {netler.map((y) => { const deger = y[d.alan]; return ( {deger != null ? net(deger) : "—"} ); })} ))} OBP {netler.map((y) => ( {y.obp != null ? net(y.obp) : "—"} ))} Yerleşme puanı {netler.map((y) => ( {y.tabanPuan != null ? net(y.tabanPuan) : "—"} ))}
); }