Enhance layout and functionality by integrating TercihProfiliKapisiLazy component into layout.tsx, improving user experience with a new section in the RootLayout. Update BolumlerPage and ListemPage for better structure and readability, including adjustments to headings and content organization. Refactor UniversiteIcerik to utilize UniversiteProgramTablosu for displaying program data, and streamline UniversiteKonumHaritasi for improved rendering. Update ManuelListe components for clearer user instructions and enhanced interaction. Overall, these changes aim to improve visual clarity and user engagement across the application.
All checks were successful
Deploy / deploy (push) Successful in 7m25s

This commit is contained in:
bilalgursen
2026-08-01 17:58:38 +03:00
parent 8cf0c3267d
commit 55eb32b22a
21 changed files with 2137 additions and 709 deletions

View File

@@ -34,6 +34,12 @@ export interface SihirbazSecimleri {
oncelikler: string[];
}
export interface TercihProfili {
sira: number;
tur: string;
secimler: SihirbazSecimleri;
}
const UNI_TIPLERI: UniversiteTipi[] = ["devlet", "vakif", "farketmez"];
/**
@@ -90,6 +96,44 @@ export function sihirbazDogrula(girdi: unknown): SihirbazSecimleri | null {
return { kategoriler, iller, universiteTipi, oncelikler };
}
/** localStorage'taki ortak sıra + sihirbaz profilini güvenle doğrular. */
export function tercihProfiliDogrula(girdi: unknown): TercihProfili | null {
if (typeof girdi !== "object" || girdi === null) return null;
const p = girdi as Record<string, unknown>;
const sira = typeof p.sira === "number" ? p.sira : Number(p.sira);
if (!Number.isFinite(sira) || sira < 1 || sira > 4_000_000) return null;
if (typeof p.tur !== "string" || p.tur.trim().length === 0) return null;
const secimler = sihirbazDogrula(p.secimler);
if (!secimler) return null;
return { sira, tur: p.tur, secimler };
}
/** Client'ta SIHIRBAZ_STORAGE_KEY'den doğrulanmış profil okur. */
export function tercihProfiliOku(): TercihProfili | null {
if (typeof window === "undefined") return null;
try {
const ham = localStorage.getItem(SIHIRBAZ_STORAGE_KEY);
if (!ham) return null;
return tercihProfiliDogrula(JSON.parse(ham));
} catch {
return null;
}
}
/** Ortak profili yazar; hero ve AI sihirbazıyla aynı anahtarı kullanır. */
export function tercihProfiliYaz(profil: TercihProfili): void {
if (typeof window === "undefined") return;
const dogru = tercihProfiliDogrula(profil);
if (!dogru) return;
try {
localStorage.setItem(SIHIRBAZ_STORAGE_KEY, JSON.stringify(dogru));
} catch {}
}
export function tercihProfiliTamamlandiMi(): boolean {
return tercihProfiliOku() !== null;
}
/** Prompt'a enjekte edilecek Türkçe özet. */
export function secimOzeti(secimler: SihirbazSecimleri): string {
const satirlar = [

View File

@@ -0,0 +1,127 @@
import { kategoriEslesir } from "./kategoriler";
import { riskHesapla, type RiskSeviyesi } from "./risk";
import type { TercihProfili } from "./sihirbaz";
export type DegerlendirilecekProgram = {
isim: string;
il: string | null;
unitur?: string | null;
efektifSira: number | null;
};
export type TercihDegerlendirmesi = {
risk: RiskSeviyesi | null;
riskEtiketi: "Hayal" | "Dengeli" | "Daha güvenli" | "Veri yetersiz";
riskMetni: string;
olumlu: string[];
celiskiler: string[];
};
function normalize(deger: string): string {
return deger.trim().toLocaleUpperCase("tr-TR");
}
export function tercihDegerlendir(
program: DegerlendirilecekProgram,
profil: TercihProfili,
): TercihDegerlendirmesi {
const risk = riskHesapla(program.efektifSira, profil.sira);
const olumlu: string[] = [];
const celiskiler: string[] = [];
if (kategoriEslesir(program.isim, profil.secimler.kategoriler)) {
olumlu.push("İlgi alanlarınla uyumlu");
} else {
celiskiler.push("Seçtiğin ilgi alanlarının dışında görünüyor");
}
if (profil.secimler.iller.length > 0) {
const seciliIller = new Set(profil.secimler.iller.map(normalize));
if (program.il && seciliIller.has(normalize(program.il))) {
olumlu.push("Tercih ettiğin şehirlerden birinde");
} else {
celiskiler.push("Tercih ettiğin şehirlerin dışında");
}
}
if (profil.secimler.universiteTipi !== "farketmez" && program.unitur) {
const devlet = normalize(program.unitur) === "DEVLET";
const uyuyor =
(profil.secimler.universiteTipi === "devlet" && devlet) ||
(profil.secimler.universiteTipi === "vakif" && !devlet);
if (uyuyor) olumlu.push("Üniversite türü tercihine uyuyor");
else celiskiler.push("Üniversite türü tercihinle uyuşmuyor");
}
if (profil.secimler.oncelikler.includes("Kolay yerleşme")) {
if (risk === "guvenli") {
olumlu.push("Daha güvenli seçenek önceliğini destekliyor");
} else if (risk === "riskli") {
celiskiler.push("Kolay yerleşme önceliğine göre iddialı bir seçim");
}
}
const riskEtiketi =
risk === "riskli"
? "Hayal"
: risk === "az-riskli"
? "Dengeli"
: risk === "guvenli"
? "Daha güvenli"
: "Veri yetersiz";
const riskMetni =
risk === "riskli"
? "Geçen yılın taban sıralaması senin sıralamandan daha yukarıda."
: risk === "az-riskli"
? "Geçmiş taban sıralamasına göre dengeli aralıkta."
: risk === "guvenli"
? "Geçmiş taban sıralamasına göre daha güvenli aralıkta."
: "Yerleşme riskini hesaplamak için yeterli taban sıra verisi yok.";
return {
risk,
riskEtiketi,
riskMetni,
olumlu: olumlu.slice(0, 3),
celiskiler: celiskiler.slice(0, 2),
};
}
export function tercihListesiOzeti(
programlar: DegerlendirilecekProgram[],
profil: TercihProfili,
) {
const degerlendirmeler = programlar.map((p) => tercihDegerlendir(p, profil));
const hayal = degerlendirmeler.filter((d) => d.risk === "riskli").length;
const dengeli = degerlendirmeler.filter(
(d) => d.risk === "az-riskli",
).length;
const dahaGuvenli = degerlendirmeler.filter(
(d) => d.risk === "guvenli",
).length;
const dikkat = degerlendirmeler.filter(
(d) => d.celiskiler.length > 0,
).length;
const gucluUyum = degerlendirmeler.filter(
(d) => d.olumlu.length >= 2 && d.celiskiler.length === 0,
).length;
let oneri = "Yeni seçimler ekledikçe listenin dengesi burada görünecek.";
if (programlar.length > 0 && dahaGuvenli === 0) {
oneri =
"Listen iddialı seçeneklerde yoğunlaşıyor. Birkaç daha güvenli program eklemek riski dağıtabilir.";
} else if (programlar.length > 2 && dengeli === 0) {
oneri =
"Listen için dengeli aralıkta birkaç program eklemek seçeneklerini güçlendirebilir.";
} else if (dikkat > Math.max(1, programlar.length / 2)) {
oneri =
"Seçtiklerinin çoğu profilinle ayrışıyor. Dikkat notlarını birlikte gözden geçir.";
} else if (programlar.length >= 24) {
oneri =
"24 tercihe ulaştın. Şimdi risk dağılımını ve dikkat notlarını gözden geçir.";
} else if (programlar.length > 0) {
oneri = "Listen dengeleniyor; uyum ve risk dağılımını koruyarak ilerle.";
}
return { hayal, dengeli, dahaGuvenli, dikkat, gucluUyum, oneri };
}