Liste store'unun sunucu snapshot'ı her zaman boş liste döner (liste-store.ts:86), kayıtlı manuel liste ancak hidrasyondan sonra okunur. Harita sayfanın tepesindeyken kayıtlı listesi olan dönüş ziyaretçisinde ~368 px yüksekliğinde sonradan beliriyor ve tadımlık ile tabloyu aşağı itiyordu; main'in ilk çocuğu olduğu için impact fraction ~1, CLS eşiğinin çok üstü. Silinen placeholder bunu yeri sunucuda rezerve ederek engelliyordu. Harita tablonun altına alındı: sonradan belirdiğinde yalnızca sihirbaz ile dipnotu iter, ikisi de katlanın altında. Bilgi mimarisi olarak da doğru sıra — harita, tablodan kurulan listenin görselleştirmesi. Yeni sıra: tadımlık → tablo → harita → sihirbaz → dipnot. Sıraya bağlı stiller yeni sıraya göre doğrulandı: tadımlığın first:mt-0'ı artık her durumda geçerli (üstünde kardeş kalmadı), harita kendi mt-16'sını alıyor (tablo section'ı ve sihirbaz kartlarıyla aynı ritim — eskiden üst boşluğu main'in py-12'sinden geliyordu). Bulgu: 36-tasarimci-g1-ve-navbar.md B1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
156 lines
6.5 KiB
TypeScript
156 lines
6.5 KiB
TypeScript
import { Suspense } from "react";
|
||
import type { Metadata } from "next";
|
||
import { cookies } from "next/headers";
|
||
import { PUAN_TURLERI, type PuanTuruKey } from "@/types/yokatlas";
|
||
import {
|
||
cerezdenTercihProfili,
|
||
PROFIL_CEREZ_ADI,
|
||
} from "@/features/sihirbaz/sihirbaz-sabitler";
|
||
import {
|
||
SonucProgramTablosu,
|
||
SonucProgramTablosuSkeleton,
|
||
} from "@/features/liste/components/sonuc-program-tablosu";
|
||
import { ManuelHarita } from "@/features/liste/components/manuel-harita";
|
||
import { TadimlikBolumu } from "@/features/rapor/components/tadimlik-bolumu";
|
||
import { SonucSihirbazi } from "@/features/sihirbaz/components/sihirbaz-bolumu";
|
||
import { SiraGerekli } from "@/features/sihirbaz/components/sira-gerekli";
|
||
import { SiteFooter } from "@/components/site-footer";
|
||
import { Skeleton } from "@/components/ui/skeleton";
|
||
|
||
export const metadata: Metadata = {
|
||
title: "Tercih Listeni Kur",
|
||
// İçerik profil çerezine göre kişisel (eski linklerde param uzayı sonsuz):
|
||
// indexlenmez ama link değeri follow ile geri akar. robots.txt'te
|
||
// ENGELLEME — noindex'in görülebilmesi için sayfa taranabilir kalmalı.
|
||
robots: { index: false, follow: true },
|
||
};
|
||
|
||
export default function SonucPage({
|
||
searchParams,
|
||
}: {
|
||
searchParams: Promise<{
|
||
sira?: string;
|
||
tur?: string;
|
||
sihirbaz?: string;
|
||
kaynak?: string;
|
||
hazir?: string;
|
||
il?: string | string[];
|
||
tip?: string;
|
||
}>;
|
||
}) {
|
||
return (
|
||
// Tablo değişken boylu olduğundan altındaki tadımlık, sihirbaz, dipnot ve
|
||
// footer aynı sınırda gruplu — bugünkü tek await'li akışla birebir aynı
|
||
// anda beliriyorlar, ara durumda zıplama yok.
|
||
<Suspense
|
||
fallback={
|
||
<main className="mx-auto w-full max-w-6xl px-4 py-10">
|
||
<Skeleton className="h-6 w-40 rounded-full" />
|
||
<Skeleton className="mt-4 h-9 w-3/4 max-w-xl" />
|
||
<Skeleton className="mt-3 h-5 w-2/3 max-w-lg" />
|
||
<Skeleton className="mt-8 h-36 w-full rounded-2xl" />
|
||
<SonucProgramTablosuSkeleton />
|
||
</main>
|
||
}
|
||
>
|
||
{Promise.all([searchParams, cookies()]).then(([params, cerezler]) => {
|
||
// Profil (sıra/tür/il/tip) normalde PROFIL_CEREZ_ADI çerezinden gelir;
|
||
// URL param taşımaz (bkz. sonucHref). Query'de sira varsa eski
|
||
// paylaşılan/yer imli link demektir — açık URL niyeti çerezi ezer,
|
||
// eski linkler çalışmayı sürdürür.
|
||
const eskiLinkSira = Number.parseInt(params.sira ?? "", 10);
|
||
const eskiLink = Number.isFinite(eskiLinkSira);
|
||
const profil = eskiLink
|
||
? null
|
||
: cerezdenTercihProfili(cerezler.get(PROFIL_CEREZ_ADI)?.value);
|
||
|
||
const sira = eskiLink ? eskiLinkSira : (profil?.sira ?? Number.NaN);
|
||
const turHam = eskiLink ? params.tur : profil?.tur;
|
||
const turKey: PuanTuruKey =
|
||
turHam && turHam in PUAN_TURLERI ? (turHam as PuanTuruKey) : "say";
|
||
// Tablo filtreleri: il en fazla 5 tekrarsız, tip devlet|vakif
|
||
// allowlist'li (çerez tarafı tercihProfiliDogrula'dan zaten geçmiş
|
||
// olsa da iki kaynak aynı süzgeçten akar).
|
||
const hamIller = eskiLink
|
||
? Array.isArray(params.il)
|
||
? params.il
|
||
: params.il
|
||
? [params.il]
|
||
: []
|
||
: (profil?.secimler.iller ?? []);
|
||
const iller = [
|
||
...new Set(hamIller.filter((i) => i.trim().length > 0)),
|
||
].slice(0, 5);
|
||
const tipHam = eskiLink ? params.tip : profil?.secimler.universiteTipi;
|
||
const uniturGrubu =
|
||
tipHam === "devlet" || tipHam === "vakif" ? tipHam : undefined;
|
||
|
||
if (!Number.isFinite(sira) || sira < 1 || sira > 4_000_000) {
|
||
return (
|
||
<>
|
||
<SiraGerekli />
|
||
<SiteFooter />
|
||
</>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className="min-h-screen bg-slate-50 text-slate-900">
|
||
<main className="mx-auto max-w-4xl px-4 py-12">
|
||
{/* Sayfa hiyerarşisi: tadımlık → ham tablo → manuel listenin
|
||
haritası. Tadımlık, ödeme öncesi gösterebildiğimiz TEK gerçek
|
||
önizleme olduğu için ilk ekranda durur.
|
||
|
||
Harita neden TABLONUN ALTINDA: liste store'unun sunucu
|
||
snapshot'ı her zaman boş liste döner (liste-store.ts), kayıtlı
|
||
liste ancak hidrasyondan sonra okunur. Harita yukarıda olsaydı
|
||
dönüş ziyaretçisinde sayfa açıldıktan saniyeler sonra ~368 px
|
||
yüksekliğinde belirip tadımlığı ve tabloyu aşağı itecekti
|
||
(impact fraction ~1, CLS eşiğinin çok üstü). Aşağıda belirince
|
||
yalnızca sihirbaz ile dipnotu iter, ikisi de katlanın altında.
|
||
Bilgi mimarisi olarak da doğru sıra: harita, tablodan kurulan
|
||
listenin görselleştirmesidir. Liste boşken hiç render edilmez
|
||
(bkz. manuel-harita.tsx); store'a abone olduğu için tablodan
|
||
"+" ile eklenenler buraya canlı yansır. */}
|
||
|
||
{/* Girişsiz tadımlık: gerçek rapor satırı formatında tek örnek.
|
||
Havuzda içerik yoksa bileşen hiç render edilmez. */}
|
||
<TadimlikBolumu sira={sira} tur={turKey} />
|
||
|
||
{/* Yapay Zeka'dan bağımsız ham tablo — sayfanın ana gövdesi;
|
||
puan türü navbar'daki sıralama rozetinden değiştirilir.
|
||
Sihirbaz seçimleri (il, devlet/vakıf) profil çerezinden
|
||
tabloya uygulanır. */}
|
||
<SonucProgramTablosu
|
||
sira={sira}
|
||
tur={turKey}
|
||
iller={iller}
|
||
uniturGrubu={uniturGrubu}
|
||
/>
|
||
|
||
<ManuelHarita />
|
||
|
||
{/* Sihirbaz akışı (CTA + modal) — üretim ve liste /listem'de
|
||
yaşar, burada yalnızca funnel kartları render edilir */}
|
||
<SonucSihirbazi
|
||
sira={sira}
|
||
tur={turKey}
|
||
otomatikAc={params.sihirbaz === "1"}
|
||
kaynak={params.kaynak}
|
||
secimlerHazir={params.hazir === "1"}
|
||
/>
|
||
|
||
<p className="mt-10 text-center text-xs leading-relaxed text-slate-500">
|
||
Veriler resmî YÖK Atlas kaynağından derlenmiştir. KolayTercih
|
||
bir karar destek aracıdır; yerleşme garantisi vermez, tercih
|
||
sorumluluğu adaya aittir.
|
||
</p>
|
||
</main>
|
||
<SiteFooter />
|
||
</div>
|
||
);
|
||
})}
|
||
</Suspense>
|
||
);
|
||
}
|