Add il bazlı filtreleme ve Türkiye harita bileşeni

Sonuç sayfasına bölge haritası ile il seçimi eklendi; searchByRank
artık il filtresini destekliyor. Paket adı tercihai olarak güncellendi.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
bilalgursen
2026-07-21 12:05:29 +03:00
parent 87f265ec15
commit 871012e87d
5 changed files with 290 additions and 10 deletions

View File

@@ -2,6 +2,7 @@ import Link from "next/link";
import type { Metadata } from "next";
import {
ArrowLeft,
MapPin,
Minus,
Rocket,
Scale,
@@ -9,6 +10,7 @@ import {
Sparkles,
TrendingDown,
TrendingUp,
X,
} from "lucide-react";
import {
PUAN_TURLERI,
@@ -16,6 +18,7 @@ import {
type Program,
type PuanTuruKey,
} from "@/lib/db";
import { BolgeHaritasi, type IlOzeti } from "@/components/bolge-haritasi";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
@@ -135,7 +138,7 @@ function ProgramTable({ programs }: { programs: Program[] }) {
export default async function SonucPage({
searchParams,
}: {
searchParams: Promise<{ sira?: string; tur?: string }>;
searchParams: Promise<{ sira?: string; tur?: string; il?: string }>;
}) {
const params = await searchParams;
const sira = Number.parseInt(params.sira ?? "", 10);
@@ -143,6 +146,7 @@ export default async function SonucPage({
params.tur && params.tur in PUAN_TURLERI
? (params.tur as PuanTuruKey)
: "say";
const seciliIl = params.il?.trim() || null;
if (!Number.isFinite(sira) || sira < 1 || sira > 4_000_000) {
return (
@@ -163,7 +167,26 @@ export default async function SonucPage({
);
}
const results = searchByRank(sira, turKey);
const results = searchByRank(sira, turKey, {
il: seciliIl ?? undefined,
});
// Harita her zaman filtresiz dağılımı gösterir ki il değiştirilebilsin
const haritaSonuclari = seciliIl ? searchByRank(sira, turKey) : results;
// Harita için il bazında özet (81 il haritada; KKTC/yurtdışı ayrıca listelenir)
const iller: Record<string, IlOzeti> = {};
const dilimler = [
["hayal", haritaSonuclari.hayal],
["dengeli", haritaSonuclari.dengeli],
["garanti", haritaSonuclari.garanti],
] as const;
for (const [dilim, programs] of dilimler) {
for (const p of programs) {
if (!p.il) continue;
iller[p.il] ??= { hayal: 0, dengeli: 0, garanti: 0 };
iller[p.il][dilim]++;
}
}
const sections = [
{
@@ -238,13 +261,58 @@ export default async function SonucPage({
variant={key === turKey ? "default" : "outline"}
className="cursor-pointer"
>
<Link href={`/sonuc?sira=${sira}&tur=${key}`}>
<Link
href={`/sonuc?sira=${sira}&tur=${key}${
seciliIl ? `&il=${encodeURIComponent(seciliIl)}` : ""
}`}
>
{TUR_LABELS[key]}
</Link>
</Button>
))}
</nav>
{seciliIl ? (
<div className="mt-4 flex flex-wrap items-center gap-3 rounded-xl border border-primary/30 bg-primary/5 px-4 py-3">
<MapPin className="size-4 text-primary" aria-hidden />
<p className="text-sm font-medium">
Yalnızca <span className="font-bold">{seciliIl}</span>{" "}
programları gösteriliyor
</p>
<Button
asChild
size="sm"
variant="outline"
className="cursor-pointer"
>
<Link href={`/sonuc?sira=${sira}&tur=${turKey}`}>
<X className="size-3.5" aria-hidden />
Filtreyi kaldır
</Link>
</Button>
</div>
) : null}
{/* Bölge haritası */}
<section aria-labelledby="baslik-harita" className="mt-10">
<h2 id="baslik-harita" className="font-heading text-2xl font-bold">
Nerede okuyacaksın?
</h2>
<p className="mt-1 text-sm text-slate-600">
Aşağıdaki önerilerin illere dağılımı. Koyu renk, o ilde daha fazla
öneri olduğunu gösterir. Bir ile tıklayarak listeyi o ile
daraltabilir, tekrar tıklayarak filtreyi kaldırabilirsin.
</p>
<div className="mt-4 rounded-2xl border border-slate-200 bg-white p-4 sm:p-6">
<BolgeHaritasi
iller={iller}
sira={sira}
turKey={turKey}
seciliIl={seciliIl}
/>
</div>
</section>
<div className="mt-10 space-y-12">
{sections.map((s) => (
<section key={s.key} aria-labelledby={`baslik-${s.key}`}>