diff --git a/src/components/program-liste-verileri.tsx b/src/components/program-liste-verileri.tsx index a91029e..a4dde16 100644 --- a/src/components/program-liste-verileri.tsx +++ b/src/components/program-liste-verileri.tsx @@ -1,30 +1,37 @@ import { TrendingDown, TrendingUp } from "lucide-react"; -import type { Program } from "@/types/yokatlas"; +import { ILK_YIL } from "@/lib/veri-yillari"; -/** Taban sıra sütunlarının yapısal alt kümesi: hem DB programı hem de - * rapordaki kaydedilmiş sıra geçmişi (bkz. raporSiraSerisi) bu tipe uyar. */ -export type SiraSerisi = Pick< - Program, - "sira2021" | "sira2022" | "sira2023" | "sira2024" | "sira2025" ->; +/** Taban sıra geçmişinin yapısal alt kümesi: hem DB programı hem de rapordaki + * kaydedilmiş sıra geçmişi (bkz. raporSiraSerisi) bu tipe uyar. Dizi `ilkYil`'a + * (yoksa veri penceresinin ilk yılına) demirlidir: eleman yılı + * `ilkYil + indeks`. Uzunluk sabit DEĞİL — eski kayıtlı raporlar daha kısa + * dizi taşır; yardımcılar dizinin kendi son iki elemanıyla çalışır. */ +export type SiraSerisi = { + siraGecmisi: readonly (number | null)[]; + ilkYil?: number; +}; -/** Rapordaki [2021..2025] dizisini sütunlu seriye çevirir. */ -export function raporSiraSerisi(gecmis?: (number | null)[]): SiraSerisi { - const g = gecmis ?? []; - return { - sira2021: g[0] ?? null, - sira2022: g[1] ?? null, - sira2023: g[2] ?? null, - sira2024: g[3] ?? null, - sira2025: g[4] ?? null, - }; +/** Rapordaki kayıtlı diziyi seriye çevirir. Dizi DOLDURULMAZ: 5 elemanlı eski + * kayıt 5 elemanlı kalır, "son iki yıl" kaydın kendi son iki yılıdır. */ +export function raporSiraSerisi( + gecmis?: (number | null)[], + ilkYil?: number, +): SiraSerisi { + return { siraGecmisi: gecmis ?? [], ilkYil }; +} + +/** Serinin son iki yılı: [bir önceki, son]. */ +function sonIkiSira(program: SiraSerisi): [number | null, number | null] { + const g = program.siraGecmisi; + return [g[g.length - 2] ?? null, g[g.length - 1] ?? null]; } export function programEtkinSira(program: SiraSerisi): number | null { - return program.sira2025 ?? program.sira2024; + const [onceki, son] = sonIkiSira(program); + return son ?? onceki; } -/** 2021–2025 taban sıralamasını sonuç listesindeki kompakt çizgiyle gösterir. */ +/** Taban sıralaması geçmişini sonuç listesindeki kompakt çizgiyle gösterir. */ export function ProgramSiraGecmisi({ program }: { program: SiraSerisi }) { // Satır başına render edilen bileşen: filter/map/min/max/map/map'in 6 ayrı // geçişi tek döngüde toplanır (js-combine-iterations, js-min-max-loop) @@ -32,14 +39,10 @@ export function ProgramSiraGecmisi({ program }: { program: SiraSerisi }) { let min = Infinity; let max = -Infinity; const ozetParcalari: string[] = []; - for (const [yil, sira] of [ - [2021, program.sira2021], - [2022, program.sira2022], - [2023, program.sira2023], - [2024, program.sira2024], - [2025, program.sira2025], - ] as const) { + const ilkYil = program.ilkYil ?? ILK_YIL; + for (const [indeks, sira] of program.siraGecmisi.entries()) { if (sira == null) continue; + const yil = ilkYil + indeks; yillar.push([yil, sira]); if (sira < min) min = sira; if (sira > max) max = sira; @@ -89,12 +92,13 @@ export function ProgramSiraGecmisi({ program }: { program: SiraSerisi }) { /** Son iki yılın tabanı %10'dan fazla değiştiğinde yönü işaretler. */ export function ProgramTabanTrendi({ program }: { program: SiraSerisi }) { - if (program.sira2025 == null || program.sira2024 == null) return null; + const [onceki, son] = sonIkiSira(program); + if (son == null || onceki == null) return null; - const oran = (program.sira2024 - program.sira2025) / program.sira2024; + const oran = (onceki - son) / onceki; if (Math.abs(oran) < 0.1) return null; - const gecis = `${program.sira2024.toLocaleString("tr-TR")} → ${program.sira2025.toLocaleString("tr-TR")}`; + const gecis = `${onceki.toLocaleString("tr-TR")} → ${son.toLocaleString("tr-TR")}`; if (oran > 0) { return ( n.toLocaleString("tr-TR"); @@ -65,20 +71,20 @@ function bolumSayfaDilimi(bolum: BolumDetay, sayfa: number) { let minSira: number | null = null; let maxSira: number | null = null; let verisiz = 0; - // Sırası 2025'te olmayıp 2024'ten gelen satırlar: aralık metni yılı dürüstçe - // söylesin (tablonun Sıralama sütunu bu satırlarda "—" gösterir). - let yalniz2024 = 0; + // Sırası son yılda olmayıp bir önceki yıldan gelen satırlar: aralık metni + // yılı dürüstçe söylesin (tablonun Sıralama sütunu bu satırlarda "—" gösterir). + let yalnizOnceki = 0; for (const p of dilim) { - const efektif = p.sira2025 ?? p.sira2024; + const efektif = p.efektifSira; if (efektif == null) { verisiz += 1; continue; } - if (p.sira2025 == null) yalniz2024 += 1; + if (p.siraSon == null) yalnizOnceki += 1; if (minSira == null || efektif < minSira) minSira = efektif; if (maxSira == null || efektif > maxSira) maxSira = efektif; } - return { tumProgramlar, dilim, minSira, maxSira, verisiz, yalniz2024 }; + return { tumProgramlar, dilim, minSira, maxSira, verisiz, yalnizOnceki }; } /** için kısa sıra: 2.425.061 → "2,43 mn", 95.400 → "95 bin". */ @@ -99,13 +105,13 @@ function siraAraligiMetni({ minSira, maxSira, verisiz, - yalniz2024, + yalnizOnceki, }: ReturnType<typeof bolumSayfaDilimi>): string | null { if (dilim.length === 0) return null; if (minSira == null || maxSira == null) { return "taban verisi olmayan programlar"; } - const yil = siraYiliEtiketi(yalniz2024, dilim.length - verisiz); + const yil = siraYiliEtiketi(yalnizOnceki, dilim.length - verisiz); const aralik = minSira === maxSira ? `${yil} taban sırası ${sayi(minSira)} olan programlar` @@ -134,8 +140,8 @@ export function bolumSayfaMetadata(slug: string, sayfa: number): Metadata { const meta = sayfaMetadata({ title: baslik, description: aralik - ? `${bolum.ad} taban puanları, sayfa ${sayfa}: ${aralik}. Toplam ${stats.toplam} programın son yerleştirme verileri (2025; 2025'te verisi olmayanlarda 2024) — taban puanı, başarı sıralaması ve kontenjan.` - : `${bolum.ad} taban puanları ve başarı sıralamaları tablosunun ${sayfa}. sayfası — toplam ${stats.toplam} programın 2025 yerleştirme verileri.`, + ? `${bolum.ad} taban puanları, sayfa ${sayfa}: ${aralik}. Toplam ${stats.toplam} programın son yerleştirme verileri (${SON_YIL}; o yıl verisi olmayanlarda ${ONCEKI_YIL}) — taban puanı, başarı sıralaması ve kontenjan.` + : `${bolum.ad} taban puanları ve başarı sıralamaları tablosunun ${sayfa}. sayfası — toplam ${stats.toplam} programın ${SON_YIL} yerleştirme verileri.`, path: `/bolum/${slug}/sayfa/${sayfa}`, openGraph: { images: ustSegmentOgGorseli( @@ -151,8 +157,8 @@ export function bolumSayfaMetadata(slug: string, sayfa: number): Metadata { ? ` En iyi taban sıralaması ${sayi(stats.minSira)}.` : ""; return sayfaMetadata({ - title: `${bolum.ad} Taban Puanları ve Başarı Sıralamaları 2026`, - description: `${bolum.ad} 2025 yerleştirme verileri: ${stats.toplam} programın taban puanı ve sıralaması, ${stats.devlet} devlet / ${stats.vakif} vakıf.${enIyi} 2026 tercih rehberi.`, + title: `${bolum.ad} Taban Puanları ve Başarı Sıralamaları ${BASLIK_YILI}`, + description: `${bolum.ad} ${SON_YIL} yerleştirme verileri: ${stats.toplam} programın taban puanı ve sıralaması, ${stats.devlet} devlet / ${stats.vakif} vakıf.${enIyi} ${TERCIH_YILI} tercih rehberi.`, path: `/bolum/${slug}`, }); } @@ -230,7 +236,7 @@ export function BolumIcerik({ slug, sayfa }: { slug: string; sayfa: number }) { </h1> {ilkSayfa ? ( <p className="mt-3 max-w-2xl text-sm leading-6 text-muted-foreground sm:text-base"> - {sayi(tumProgramlar.length)} üniversite programının 2025 taban + {sayi(tumProgramlar.length)} üniversite programının {SON_YIL} taban puanlarını, başarı sıralamalarını ve kontenjanlarını incele. </p> ) : ( diff --git a/src/features/katalog/components/bolum-program-listesi.tsx b/src/features/katalog/components/bolum-program-listesi.tsx index 2051159..f95057a 100644 --- a/src/features/katalog/components/bolum-program-listesi.tsx +++ b/src/features/katalog/components/bolum-program-listesi.tsx @@ -5,6 +5,7 @@ import Link from "next/link"; import { ChevronDown, ChevronUp } from "lucide-react"; import type { Program } from "@/types/yokatlas"; import { trBaslikDuzeni } from "@/lib/slug"; +import { VERI_YIL_SAYISI } from "@/lib/veri-yillari"; import { Sayfalama, SAYFA_BOYU } from "./sayfalama"; import { ProgramSiraGecmisi, @@ -24,14 +25,14 @@ import { const sayi = (n: number) => n.toLocaleString("tr-TR"); -type SiralamaAlani = "sira2025" | "puan2025" | "kontenjan2025"; +type SiralamaAlani = "siraSon" | "puanSon" | "kontenjanSon"; type SiralamaYonu = "artan" | "azalan"; export type BolumProgrami = Program & { universiteSlug: string | null }; const ALAN_ETIKETLERI: Record<SiralamaAlani, string> = { - sira2025: "Sıralama", - puan2025: "Puan", - kontenjan2025: "Kontenjan", + siraSon: "Sıralama", + puanSon: "Puan", + kontenjanSon: "Kontenjan", }; function SiralamaDugmesi({ @@ -157,11 +158,11 @@ export function BolumProgramListesi({ <TableRow> <TableHead>Üniversite</TableHead> <TableHead className="hidden text-right md:table-cell"> - Son 5 yıl + Son {VERI_YIL_SAYISI} yıl </TableHead> <TableHead className="hidden text-right lg:table-cell"> <SiralamaDugmesi - alan="puan2025" + alan="puanSon" aktifAlan={aktifAlan} yon={yon} onSirala={sirala} @@ -169,7 +170,7 @@ export function BolumProgramListesi({ </TableHead> <TableHead className="hidden text-right sm:table-cell"> <SiralamaDugmesi - alan="kontenjan2025" + alan="kontenjanSon" aktifAlan={aktifAlan} yon={yon} onSirala={sirala} @@ -177,7 +178,7 @@ export function BolumProgramListesi({ </TableHead> <TableHead className="text-right"> <SiralamaDugmesi - alan="sira2025" + alan="siraSon" aktifAlan={aktifAlan} yon={yon} onSirala={sirala} @@ -243,17 +244,17 @@ export function BolumProgramListesi({ <ProgramSiraGecmisi program={p} /> </TableCell> <TableCell className="hidden text-right text-xs tabular-nums text-slate-500 lg:table-cell"> - {p.puan2025 != null - ? p.puan2025.toFixed(2).replace(".", ",") + {p.puanSon != null + ? p.puanSon.toFixed(2).replace(".", ",") : "—"} </TableCell> <TableCell className="hidden text-right text-xs tabular-nums text-slate-500 sm:table-cell"> - {p.kontenjan2025 != null ? `${sayi(p.kontenjan2025)} kişi` : "—"} + {p.kontenjanSon != null ? `${sayi(p.kontenjanSon)} kişi` : "—"} </TableCell> <TableCell className="text-right text-xs tabular-nums text-slate-500"> <span className="inline-flex items-center gap-1"> <ProgramTabanTrendi program={p} /> - {p.sira2025 != null ? `~${sayi(p.sira2025)}.` : "—"} + {p.siraSon != null ? `~${sayi(p.siraSon)}.` : "—"} </span> </TableCell> <TableCell className="pr-3 text-right"> diff --git a/src/features/katalog/components/sayfalama.tsx b/src/features/katalog/components/sayfalama.tsx index a7e56d3..bf2c546 100644 --- a/src/features/katalog/components/sayfalama.tsx +++ b/src/features/katalog/components/sayfalama.tsx @@ -1,6 +1,7 @@ import type { ReactNode } from "react"; import Link from "next/link"; import { ChevronLeft, ChevronRight } from "lucide-react"; +import { ONCEKI_YIL, SON_YIL } from "@/lib/veri-yillari"; /** Programatik tablo sayfaları için satır dilimi boyutu. */ export const SAYFA_BOYU = 50; @@ -13,10 +14,19 @@ export function sayfaDilimi<T>(liste: readonly T[], sayfa: number): T[] { return liste.slice((sayfa - 1) * SAYFA_BOYU, sayfa * SAYFA_BOYU); } -/** Aralıktaki sıraların hangi yıldan geldiği: hepsi 2025 / hepsi 2024 / karışık. */ -export function siraYiliEtiketi(yalniz2024: number, siraliSayi: number): string { - if (yalniz2024 === 0) return "2025"; - return yalniz2024 === siraliSayi ? "2024" : "2024–2025"; +/** + * Aralıktaki sıraların hangi yıldan geldiği: hepsi son yıl / hepsi bir önceki + * yıl / karışık. `yalnizOnceki`: sırası son yılda olmayıp bir önceki yıldan + * gelen satır sayısı; `siraliSayi`: sırası olan toplam satır. + */ +export function siraYiliEtiketi( + yalnizOnceki: number, + siraliSayi: number, +): string { + if (yalnizOnceki === 0) return String(SON_YIL); + return yalnizOnceki === siraliSayi + ? String(ONCEKI_YIL) + : `${ONCEKI_YIL}–${SON_YIL}`; } /** diff --git a/src/features/katalog/components/universite-icerik.tsx b/src/features/katalog/components/universite-icerik.tsx index 50821ab..90da09d 100644 --- a/src/features/katalog/components/universite-icerik.tsx +++ b/src/features/katalog/components/universite-icerik.tsx @@ -34,6 +34,7 @@ import { UniLogo } from "@/components/uni-logo"; import { uniLogoYolu } from "@/lib/uni-logolar"; import { Skeleton } from "@/components/ui/skeleton"; import type { Program } from "@/types/yokatlas"; +import { BASLIK_YILI, SON_YIL, TERCIH_YILI } from "@/lib/veri-yillari"; const sayi = (n: number) => n.toLocaleString("tr-TR"); @@ -91,13 +92,13 @@ function fakulteOzeti({ if (adlar.length === 0) return null; if (adlar.length === 1) { const siralar = dilim - .map((p) => p.sira2025 ?? p.sira2024) + .map((p) => p.efektifSira) .filter((n): n is number => n != null); if (siralar.length === 0) return adlar[0]; const min = Math.min(...siralar); const max = Math.max(...siralar); const yil = siraYiliEtiketi( - dilim.filter((p) => p.sira2025 == null && p.sira2024 != null).length, + dilim.filter((p) => p.siraSon == null && p.efektifSira != null).length, siralar.length, ); return min === max @@ -116,10 +117,10 @@ export function uniSayfaMetadata(slug: string, sayfa: number): Metadata { // farklılaştırıcı (o sayfadaki birimler) açıklamaya ve gövdeye gider. const birimler = fakulteOzeti(uniSayfaDilimi(uni, sayfa)); return sayfaMetadata({ - title: `${uni.ad} Taban Puanları 2026 (Sayfa ${sayfa})`, + title: `${uni.ad} Taban Puanları ${BASLIK_YILI} (Sayfa ${sayfa})`, description: birimler - ? `${uni.ad} taban puanları, sayfa ${sayfa}: ${birimler}. Toplam ${uni.programSayisi} programın 2025 yerleştirme verileri — taban puanı, başarı sıralaması ve kontenjan.` - : `${uni.ad} taban puanları ve başarı sıralamaları tablosunun ${sayfa}. sayfası — toplam ${uni.programSayisi} programın 2025 yerleştirme verileri.`, + ? `${uni.ad} taban puanları, sayfa ${sayfa}: ${birimler}. Toplam ${uni.programSayisi} programın ${SON_YIL} yerleştirme verileri — taban puanı, başarı sıralaması ve kontenjan.` + : `${uni.ad} taban puanları ve başarı sıralamaları tablosunun ${sayfa}. sayfası — toplam ${uni.programSayisi} programın ${SON_YIL} yerleştirme verileri.`, path: `/universite/${slug}/sayfa/${sayfa}`, openGraph: { images: ustSegmentOgGorseli( @@ -130,8 +131,8 @@ export function uniSayfaMetadata(slug: string, sayfa: number): Metadata { }); } return sayfaMetadata({ - title: `${uni.ad} Taban Puanları ve Başarı Sıralamaları 2026`, - description: `${uni.ad} 2025 yerleştirme verileri: ${uni.programSayisi} programın taban puanları, başarı sıralamaları ve kontenjanları${uni.il ? ` (${trBaslikDuzeni(uni.il)})` : ""}. 2026 tercih rehberi.`, + title: `${uni.ad} Taban Puanları ve Başarı Sıralamaları ${BASLIK_YILI}`, + description: `${uni.ad} ${SON_YIL} yerleştirme verileri: ${uni.programSayisi} programın taban puanları, başarı sıralamaları ve kontenjanları${uni.il ? ` (${trBaslikDuzeni(uni.il)})` : ""}. ${TERCIH_YILI} tercih rehberi.`, path: `/universite/${slug}`, }); } @@ -241,7 +242,7 @@ export function UniversiteIcerik({ <div className="mt-4 flex items-center gap-4"> <UniLogo slug={slug} ad={uni.ad} boy="lg" /> <h1 className="font-heading text-3xl font-bold text-slate-900 sm:text-4xl"> - {uni.ad} Taban Puanları 2026 + {uni.ad} Taban Puanları {BASLIK_YILI} {ilkSayfa ? "" : ` — Sayfa ${sayfa}`} </h1> </div> @@ -250,7 +251,7 @@ export function UniversiteIcerik({ <> <p className="mt-4 max-w-3xl text-sm leading-7 text-slate-600"> {uni.ad} - {uni.il ? ` (${trBaslikDuzeni(uni.il)})` : ""}, 2025 YKS + {uni.il ? ` (${trBaslikDuzeni(uni.il)})` : ""}, {SON_YIL} YKS yerleştirme sonuçlarına göre{" "} <strong>{sayi(uni.programSayisi)} programda</strong> öğrenci aldı {uni.fakulteSayisi > 1 @@ -267,10 +268,11 @@ export function UniversiteIcerik({ {uni.stats.toplamKontenjan > 0 ? ( <> Toplam kontenjan {sayi(uni.stats.toplamKontenjan)}.</> ) : null}{" "} - Aşağıdaki tablolar 2026 tercihleri için rehber niteliğindedir;{" "} + Aşağıdaki tablolar {TERCIH_YILI} tercihleri için rehber + niteliğindedir;{" "} <em> - 2026 taban puanları ve sıralamaları, yerleştirme sonuçları - açıklandığında netleşir. + {TERCIH_YILI} taban puanları ve sıralamaları, yerleştirme + sonuçları açıklandığında netleşir. </em> </p> diff --git a/src/features/katalog/components/universite-program-tablosu.tsx b/src/features/katalog/components/universite-program-tablosu.tsx index 34f35b3..eb7408d 100644 --- a/src/features/katalog/components/universite-program-tablosu.tsx +++ b/src/features/katalog/components/universite-program-tablosu.tsx @@ -2,6 +2,7 @@ import Link from "next/link"; import type { Program } from "@/types/yokatlas"; +import { SON_YIL, VERI_YIL_SAYISI } from "@/lib/veri-yillari"; import { ProgramSiraGecmisi, ProgramTabanTrendi, @@ -48,10 +49,10 @@ export function UniversiteProgramTablosu({ <TableRow> <TableHead>Program</TableHead> <TableHead className="hidden text-right md:table-cell"> - Son 5 yıl + Son {VERI_YIL_SAYISI} yıl </TableHead> <TableHead className="hidden text-right lg:table-cell"> - 2025 puan + {SON_YIL} puan </TableHead> <TableHead className="hidden text-right sm:table-cell"> Kontenjan @@ -93,13 +94,13 @@ export function UniversiteProgramTablosu({ <ProgramSiraGecmisi program={p} /> </TableCell> <TableCell className="hidden text-right text-xs tabular-nums text-slate-500 lg:table-cell"> - {p.puan2025 != null - ? p.puan2025.toFixed(2).replace(".", ",") + {p.puanSon != null + ? p.puanSon.toFixed(2).replace(".", ",") : "—"} </TableCell> <TableCell className="hidden text-right text-xs tabular-nums text-slate-500 sm:table-cell"> - {p.kontenjan2025 != null - ? `${sayi(p.kontenjan2025)} kişi` + {p.kontenjanSon != null + ? `${sayi(p.kontenjanSon)} kişi` : "—"} </TableCell> <TableCell className="text-right text-xs tabular-nums text-slate-500"> diff --git a/src/features/liste/components/program-ekle-butonu.tsx b/src/features/liste/components/program-ekle-butonu.tsx index 95613cc..7cf0bd1 100644 --- a/src/features/liste/components/program-ekle-butonu.tsx +++ b/src/features/liste/components/program-ekle-butonu.tsx @@ -24,8 +24,7 @@ type ProgramOzet = Pick< | "il" | "unitur" | "tur" - | "sira2025" - | "sira2024" + | "efektifSira" >; const PROFILSIZ_EKLEME_TOAST_ID = "profilsiz-ekleme"; diff --git a/src/features/liste/components/program-tablosu.tsx b/src/features/liste/components/program-tablosu.tsx index e71c009..c889950 100644 --- a/src/features/liste/components/program-tablosu.tsx +++ b/src/features/liste/components/program-tablosu.tsx @@ -22,6 +22,7 @@ import type { } from "@/types/yokatlas"; import { DILIM_ETIKET, riskHesapla, type RiskSeviyesi } from "@/lib/risk"; import { bolumSayfaSlug, uniSayfaSlug } from "@/lib/slug"; +import { VERI_YIL_SAYISI } from "@/lib/veri-yillari"; import { ProgramSiraGecmisi, ProgramTabanTrendi, @@ -239,7 +240,7 @@ export function ProgramTablosu({ <TableHead className="w-8" /> <TableHead>Program</TableHead> <TableHead className="hidden text-right md:table-cell"> - Son 5 yıl + Son {VERI_YIL_SAYISI} yıl </TableHead> <TableHead className="hidden text-right sm:table-cell"> Kontenjan @@ -357,19 +358,19 @@ function ProgramSatiri({ <TableCell className="hidden text-right text-xs tabular-nums text-slate-500 sm:table-cell" title={ - p.kontenjan2025 != null && p.yerlesen2025 != null - ? `${p.kontenjan2025} kontenjan, ${p.yerlesen2025} yerleşen` + p.kontenjanSon != null && p.yerlesenSon != null + ? `${p.kontenjanSon} kontenjan, ${p.yerlesenSon} yerleşen` : undefined } > - {p.kontenjan2025 != null ? ( + {p.kontenjanSon != null ? ( <span className="inline-flex items-center gap-1.5"> - {p.yerlesen2025 != null && p.yerlesen2025 < p.kontenjan2025 ? ( + {p.yerlesenSon != null && p.yerlesenSon < p.kontenjanSon ? ( <span className="rounded bg-amber-50 px-1 py-px text-[10px] font-medium leading-4 text-amber-600"> boş kaldı </span> ) : null} - {p.kontenjan2025.toLocaleString("tr-TR")} kişi + {p.kontenjanSon.toLocaleString("tr-TR")} kişi </span> ) : ( "—" diff --git a/src/features/rapor/components/rapor-listesi.tsx b/src/features/rapor/components/rapor-listesi.tsx index b8af439..0a59dc7 100644 --- a/src/features/rapor/components/rapor-listesi.tsx +++ b/src/features/rapor/components/rapor-listesi.tsx @@ -2,7 +2,7 @@ // 24'lük listenin gövdesi. Görsel dil sonuç sayfasındaki ham program // tablosuyla birebir aynıdır (bkz. program-tablosu.tsx): aynı beyaz kart, -// aynı satır düzeni, aynı "Son 5 yıl" / "Taban sıra" sütunları. Buradaki fark +// aynı satır düzeni, aynı "Son N yıl" / "Taban sıra" sütunları. Buradaki fark // içerik: satır sırası tercih numarası, risk sütunu Yapay Zeka'dan gelir ve // satır açıldığında gerekçe/risk notu görünür. Program adı ve tabanlar herkese // açık; Yapay Zeka katmanı kilitliBaslangic sonrasında ücretlidir (metin @@ -27,6 +27,7 @@ import { TableRow, } from "@/components/ui/table"; import { bolumSayfaSlug, uniSayfaSlug } from "@/lib/slug"; +import { VERI_YIL_SAYISI } from "@/lib/veri-yillari"; import type { RaporSonuc } from "@/features/rapor/types/rapor"; import { DILIM_ETIKET, @@ -47,7 +48,7 @@ const RISK_STIL: Record<RiskSeviyesi, { nokta: string; icon: typeof Rocket }> = guvenli: { nokta: "bg-emerald-500", icon: ShieldCheck }, }; -// Sütun sayısı: # · Program · Son 5 yıl · Risk · Taban sıra · detay oku +// Sütun sayısı: # · Program · Son N yıl · Risk · Taban sıra · detay oku const SUTUN_SAYISI = 6; /** @@ -161,6 +162,19 @@ export function RaporListesi({ return iller.size === 1 ? [...iller][0] : null; }, [rapor]); + // Sütun başlığı kaydın KENDİ penceresini söyler: eski raporların sıra + // geçmişi üretildiği günün yıl sayısını taşır (dizi doldurulmaz), başlık + // çizgide olmayan bir yılı vaat etmesin. Geçmişi hiç olmayan kayıtta + // bugünkü pencereye düşer. + const yilSayisi = useMemo(() => { + let enUzun = 0; + for (const t of rapor.tercihler) { + const n = rapor.programlar[t.programId]?.siraGecmisi?.length ?? 0; + if (n > enUzun) enUzun = n; + } + return enUzun > 0 ? enUzun : VERI_YIL_SAYISI; + }, [rapor]); + const satir = (t: RaporSonuc["tercihler"][number], index: number) => { const p = rapor.programlar[t.programId]; const analizKilitli = index >= kilitIdx; @@ -168,7 +182,7 @@ export function RaporListesi({ (adaySira != null ? riskHesapla(p?.efektifSira, adaySira) : null) ?? dilimdenRisk(t.dilim); const stil = RISK_STIL[risk]; - const seri = raporSiraSerisi(p?.siraGecmisi); + const seri = raporSiraSerisi(p?.siraGecmisi, p?.ilkYil); const taban = p?.efektifSira ?? programEtkinSira(seri); const acikMi = acik.has(t.sira); const devlet = p?.unitur === "DEVLET"; @@ -366,7 +380,7 @@ export function RaporListesi({ <TableHead className="w-8 pl-4 pr-0">#</TableHead> <TableHead>Program</TableHead> <TableHead className="hidden text-right md:table-cell"> - Son 5 yıl + Son {yilSayisi} yıl </TableHead> <TableHead> <span className="hidden sm:inline">Yapay Zeka </span>Risk diff --git a/src/features/rapor/components/tadimlik-satiri.tsx b/src/features/rapor/components/tadimlik-satiri.tsx index 592984a..bc72ea8 100644 --- a/src/features/rapor/components/tadimlik-satiri.tsx +++ b/src/features/rapor/components/tadimlik-satiri.tsx @@ -105,7 +105,7 @@ export function TadimlikSatiri({ const p = satir.program; const risk = riskHesapla(p.efektifSira, sira) ?? dilimdenRisk(satir.dilim); - const seri = raporSiraSerisi(p.siraGecmisi); + const seri = raporSiraSerisi(p.siraGecmisi, p.ilkYil); const taban = p.efektifSira ?? programEtkinSira(seri); const devlet = p.unitur === "DEVLET"; const girisUrl = `/giris?callback=${encodeURIComponent(sonucHref())}`;