Files
kolaytercih/src/features/pazarlama/landing-verisi.ts
bilalgursen 3c995402c6 feat(ui): Arc bileşenleri, landing bölümleri ve bildirim yığını
Sonner/vaul yerine kendi bildirim yığını ve alt sayfa; çip grubu, kart
destesi, kaydırma eylemi, yazı dönüşümü, bölme tutamacı; landing'e program
duvarı, süzülen haplar ve veri akışı; yaylar tek dosyada (lib/hareket.ts).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 17:12:53 +03:00

130 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import "server-only";
// Ana sayfadaki iki etkileşimli parçanın verisi (sunucuda, build/istek anında):
// - Kart destesi demosu (DESIGN.md §4.27): örnek bir sıralamaya göre GERÇEK
// programlar. Uydurma taban sıralaması gösterilmez; veri okunamazsa bölüm
// hiç çizilmez.
// - Süzülen haplar (§4.30): yalnız katalogda sayfası olan bölüm ve şehirler.
import { dilimAra } from "@/lib/db";
import { bolumSlugFromIsim, getIlBySlug } from "@/lib/katalog";
import { ozelKontenjanSatiriMi } from "@/lib/rapor-havuzu";
import { riskHesapla, type RiskSeviyesi } from "@/lib/risk";
import { bolumBazAdi, ilSayfaHref, trBaslikDuzeni, turkishSlugify } from "@/lib/slug";
import type { DilimKey } from "@/types/yokatlas";
/** Demonun örnek öğrencisi: Sayısal, 85.000. sıra (§10.1'deki örnekle aynı). */
export const ORNEK_SIRA = 85_000;
const ORNEK_TUR = "say" as const;
export interface OrnekProgram {
id: string;
isim: string;
universite: string;
il: string | null;
tabanSira: number;
risk: RiskSeviyesi;
}
/**
* Her dilimden birkaç program: sınıra yapışık olanlar yerine dilimin içine
* yayılmış (riskli / az riskli / güvenli farkı kartta görünsün), her üniversite
* ve her bölüm adı en çok bir kez.
*/
export function ornekProgramlar(): OrnekProgram[] {
try {
const gorulenUni = new Set<string>();
const gorulenBolum = new Set<string>();
const sec = (dilim: DilimKey, adet: number, adim: number): OrnekProgram[] => {
const { programlar } = dilimAra(ORNEK_SIRA, ORNEK_TUR, dilim, {
uniturGrubu: "devlet",
barajDisiHaric: true,
limit: 600,
});
const secilen: OrnekProgram[] = [];
for (let i = adim; i < programlar.length && secilen.length < adet; i += adim) {
const p = programlar[i];
const bolum = bolumBazAdi(p.isim);
const risk = riskHesapla(p.efektifSira, ORNEK_SIRA);
if (
p.efektifSira == null ||
!risk ||
ozelKontenjanSatiriMi(p.isim) ||
/\(/.test(p.isim) ||
gorulenUni.has(p.universite) ||
gorulenBolum.has(bolum)
) {
// Elenen satırın bir sonrakine bak; adım bozulmasın diye geri al
i -= adim - 1;
continue;
}
gorulenUni.add(p.universite);
gorulenBolum.add(bolum);
secilen.push({
id: p.id,
isim: p.isim,
universite: trBaslikDuzeni(p.universite),
il: p.il ? trBaslikDuzeni(p.il) : null,
tabanSira: p.efektifSira,
risk,
});
}
return secilen;
};
const hayal = sec("hayal", 2, 60);
const dengeli = sec("dengeli", 3, 45);
const guvenli = sec("garanti", 2, 90);
// Sıra karışık: aynı risk art arda gelmesin
return [dengeli[0], hayal[0], guvenli[0], dengeli[1], hayal[1], dengeli[2], guvenli[1]].filter(
(p): p is OrnekProgram => Boolean(p),
);
} catch {
return [];
}
}
export interface KatalogHapi {
etiket: string;
href: string;
tur: "bolum" | "sehir";
}
const HAP_BOLUMLERI = [
"Tıp",
"Hukuk",
"Bilgisayar Mühendisliği",
"Psikoloji",
"Diş Hekimliği",
"Hemşirelik",
"Mimarlık",
"Yazılım Mühendisliği",
"Eczacılık",
"İşletme",
];
const HAP_SEHIRLERI = ["İstanbul", "Ankara", "İzmir", "Eskişehir", "Bursa", "Antalya"];
/** Bölüm ve şehir hapları; katalogda karşılığı olmayan ad sessizce düşer. */
export function katalogHaplari(): KatalogHapi[] {
try {
const bolumler: KatalogHapi[] = HAP_BOLUMLERI.flatMap((ad) => {
const slug = bolumSlugFromIsim(ad);
return slug ? [{ etiket: ad, href: `/bolum/${slug}`, tur: "bolum" as const }] : [];
});
const sehirler: KatalogHapi[] = HAP_SEHIRLERI.flatMap((ad) =>
getIlBySlug(turkishSlugify(ad))
? [{ etiket: ad, href: ilSayfaHref(ad), tur: "sehir" as const }]
: [],
);
// Bölüm ve şehir karışık dizilsin: her üç bölümden sonra bir şehir
const sonuc: KatalogHapi[] = [];
let s = 0;
bolumler.forEach((b, i) => {
sonuc.push(b);
if (i % 2 === 1 && s < sehirler.length) sonuc.push(sehirler[s++]);
});
return [...sonuc, ...sehirler.slice(s)];
} catch {
return [];
}
}