- src/components/manuel-liste/ → src/features/liste/: kayitli-liste-actions → liste-actions, store → liste-store, dogrula → liste-dogrula, giris-url → liste-giris-url, oturum-sinyali → liste-oturum-sinyali, profil-kapisi-store → hooks/use-tercih-profili; 12 tsx → components/ - program-tablosu.tsx ve tercih-haritasi.tsx da features/liste/components'a geldi (rapor ve katalog cross-import ediyor) - app/layout.tsx'in 3 global mount'u (ListeCekmecesiLazy, KaydetBannerLazy, TercihProfiliKapisiLazy) yeni feature yollarından import ediliyor - liste-queries.ts /sonuc dönüşümüyle Faz 9'da gelecek - Davranış değişikliği yok; store/localStorage anahtarları aynı Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
86 lines
2.5 KiB
TypeScript
86 lines
2.5 KiB
TypeScript
// Rapordan Türkiye haritası pinleri türetir — /sonuc ve /listem ortak kullanır.
|
||
|
||
import type { RaporSonuc } from "@/features/rapor/types/rapor";
|
||
import type { HaritaPin } from "@/features/liste/components/tercih-haritasi";
|
||
import { ilKonum, uniAdiNormalize, uniKonum } from "@/lib/harita";
|
||
import { dilimdenRisk, riskHesapla, type RiskSeviyesi } from "@/lib/risk";
|
||
|
||
const RISK_AGIRLIK: Record<RiskSeviyesi, number> = {
|
||
guvenli: 0,
|
||
"az-riskli": 1,
|
||
riskli: 2,
|
||
};
|
||
|
||
/**
|
||
* Rapordan harita pinleri türetir. Açık satırlar üniversite bazında gruplanır
|
||
* (kampüs konumunda, adıyla); kilitli satırlar il başına tek adsız "?" pinine
|
||
* toplanır — maskeli veride üniversite adı zaten client'a inmediği için
|
||
* harita paywall'ı delemez. Haritada karşılığı olmayan tercihler sayılır.
|
||
*/
|
||
export function pinleriTuret(
|
||
rapor: RaporSonuc,
|
||
adaySira: number,
|
||
kilitliBaslangic: number,
|
||
): { pinler: HaritaPin[]; haritaDisi: number } {
|
||
const gruplar = new Map<string, HaritaPin>();
|
||
let haritaDisi = 0;
|
||
|
||
rapor.tercihler.forEach((t, i) => {
|
||
const p = rapor.programlar[t.programId];
|
||
if (!p) return;
|
||
const risk = riskHesapla(p.efektifSira, adaySira) ?? dilimdenRisk(t.dilim);
|
||
const kilitli = i >= kilitliBaslangic;
|
||
|
||
if (kilitli) {
|
||
const konum = ilKonum(p.il);
|
||
if (!konum) {
|
||
haritaDisi += 1;
|
||
return;
|
||
}
|
||
const key = `kilit|${p.il}`;
|
||
const mevcut = gruplar.get(key);
|
||
if (mevcut) {
|
||
mevcut.tercihSiralari.push(t.sira);
|
||
if (RISK_AGIRLIK[risk] > RISK_AGIRLIK[mevcut.risk]) mevcut.risk = risk;
|
||
} else {
|
||
// Açık pinlerle üst üste binmesin diye il merkezinin hafif altına
|
||
gruplar.set(key, {
|
||
id: key,
|
||
universite: "",
|
||
il: p.il,
|
||
x: konum.x,
|
||
y: konum.y + 9,
|
||
tercihSiralari: [t.sira],
|
||
risk,
|
||
kilitli: true,
|
||
});
|
||
}
|
||
return;
|
||
}
|
||
|
||
const konum = uniKonum(p.universite, p.il);
|
||
if (!konum) {
|
||
haritaDisi += 1;
|
||
return;
|
||
}
|
||
const key = `${uniAdiNormalize(p.universite)}|${p.il ?? ""}`;
|
||
const mevcut = gruplar.get(key);
|
||
if (mevcut) {
|
||
mevcut.tercihSiralari.push(t.sira);
|
||
if (RISK_AGIRLIK[risk] > RISK_AGIRLIK[mevcut.risk]) mevcut.risk = risk;
|
||
} else {
|
||
gruplar.set(key, {
|
||
id: key,
|
||
universite: p.universite,
|
||
il: p.il,
|
||
x: konum.x,
|
||
y: konum.y,
|
||
tercihSiralari: [t.sira],
|
||
risk,
|
||
});
|
||
}
|
||
});
|
||
|
||
return { pinler: [...gruplar.values()], haritaDisi };
|
||
}
|