Compare commits
8 Commits
9bd448bd16
...
e3519a50cc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3519a50cc | ||
|
|
e9126650c3 | ||
|
|
d2e11908ba | ||
|
|
2373a9a526 | ||
|
|
72ef3b8669 | ||
|
|
5311459073 | ||
|
|
552d5ce5f1 | ||
|
|
daa232c3c1 |
@@ -97,15 +97,30 @@ export default function SonucPage({
|
|||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-slate-50 text-slate-900">
|
<div className="min-h-screen bg-slate-50 text-slate-900">
|
||||||
<main className="mx-auto max-w-4xl px-4 py-12">
|
<main className="mx-auto max-w-4xl px-4 py-12">
|
||||||
{/* Sayfa hiyerarşisi: önce Türkiye haritası, sonra liste. Manuel
|
{/* Sayfa hiyerarşisi: tadımlık → ham tablo → manuel listenin
|
||||||
liste store'una abone olduğundan tablodan "+" ile eklenenler
|
haritası. Tadımlık, ödeme öncesi gösterebildiğimiz TEK gerçek
|
||||||
buraya canlı yansır. */}
|
önizleme olduğu için ilk ekranda durur.
|
||||||
<ManuelHarita />
|
|
||||||
|
|
||||||
{/* Yapay Zeka'dan bağımsız ham tablo — haritanın hemen altında,
|
Harita neden TABLONUN ALTINDA: liste store'unun sunucu
|
||||||
sayfanın ana gövdesi; puan türü navbar'daki sıralama
|
snapshot'ı her zaman boş liste döner (liste-store.ts), kayıtlı
|
||||||
rozetinden değiştirilir. Sihirbaz seçimleri (il, devlet/
|
liste ancak hidrasyondan sonra okunur. Harita yukarıda olsaydı
|
||||||
vakıf) profil çerezinden tabloya uygulanır. */}
|
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
|
<SonucProgramTablosu
|
||||||
sira={sira}
|
sira={sira}
|
||||||
tur={turKey}
|
tur={turKey}
|
||||||
@@ -113,9 +128,7 @@ export default function SonucPage({
|
|||||||
uniturGrubu={uniturGrubu}
|
uniturGrubu={uniturGrubu}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Girişsiz tadımlık: gerçek rapor satırı formatında tek örnek.
|
<ManuelHarita />
|
||||||
Havuzda içerik yoksa bileşen hiç render edilmez. */}
|
|
||||||
<TadimlikBolumu sira={sira} tur={turKey} />
|
|
||||||
|
|
||||||
{/* Sihirbaz akışı (CTA + modal) — üretim ve liste /listem'de
|
{/* Sihirbaz akışı (CTA + modal) — üretim ve liste /listem'de
|
||||||
yaşar, burada yalnızca funnel kartları render edilir */}
|
yaşar, burada yalnızca funnel kartları render edilir */}
|
||||||
|
|||||||
@@ -64,23 +64,18 @@ export function ManuelHarita() {
|
|||||||
};
|
};
|
||||||
}, [liste]);
|
}, [liste]);
|
||||||
|
|
||||||
// Liste boşken 197 KB'lık il geometrisi hiç inmesin: aynı oranlı
|
// Liste boşken hiç yer tutulmaz: boş harita /sonuc'un ilk ekranını işgal
|
||||||
// placeholder alanı rezerve eder, ilk eklemede lazy harita yerine oturur.
|
// ediyordu, oysa ödeme öncesi ilk ekranda durması gereken şey tadımlık.
|
||||||
if (liste.length === 0) {
|
// İlk "+" ile liste dolunca harita kendiliğinden belirir; 197 KB'lık il
|
||||||
return (
|
// geometrisi yine ancak o anda iner (TercihHaritasiLazy zaten `dynamic`).
|
||||||
<div>
|
if (liste.length === 0) return null;
|
||||||
<div className="flex aspect-[1050/447] w-full items-center justify-center rounded-xl bg-slate-100/60">
|
|
||||||
<p className="max-w-xs px-4 text-center text-xs text-slate-500">
|
|
||||||
Tablodan <span aria-hidden>+</span> ile ekledikçe üniversiteler
|
|
||||||
haritada belirir.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// mt-16: /sonuc'ta harita artık tablonun ALTINDA duruyor (bkz. sonuc/page.tsx)
|
||||||
|
// ve sayfanın bölüm ritmini paylaşıyor — tablo <section>'ı ve sihirbaz
|
||||||
|
// kartları da mt-16 kullanır. Eskiden main'in ilk çocuğu olduğu için üst
|
||||||
|
// boşluğu main'in py-12'sinden alıyordu, kendi margin'i yoktu.
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="mt-16">
|
||||||
<TercihHaritasiLazy
|
<TercihHaritasiLazy
|
||||||
pinler={pinler}
|
pinler={pinler}
|
||||||
seciliIl={seciliIl}
|
seciliIl={seciliIl}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import { useGorunumOlayi } from "@/components/use-gorunum-olayi";
|
|||||||
import { olay, siraKovasi } from "@/lib/analitik";
|
import { olay, siraKovasi } from "@/lib/analitik";
|
||||||
import { dilimdenRisk, riskHesapla } from "@/lib/risk";
|
import { dilimdenRisk, riskHesapla } from "@/lib/risk";
|
||||||
import { turkishSlugify } from "@/lib/slug";
|
import { turkishSlugify } from "@/lib/slug";
|
||||||
import { PROFIL_DEGISTI_EVENT, sonucHref } from "@/features/sihirbaz/sihirbaz-sabitler";
|
import { listemUretHref, PROFIL_DEGISTI_EVENT } from "@/features/sihirbaz/sihirbaz-sabitler";
|
||||||
import { tercihProfiliOku } from "@/features/sihirbaz/sihirbaz-profil";
|
import { tercihProfiliOku } from "@/features/sihirbaz/sihirbaz-profil";
|
||||||
import type { TadimlikSatir, TadimlikTip } from "@/lib/tadimlik-havuzu";
|
import type { TadimlikSatir, TadimlikTip } from "@/lib/tadimlik-havuzu";
|
||||||
|
|
||||||
@@ -97,6 +97,13 @@ export function TadimlikSatiri({
|
|||||||
return () => window.removeEventListener(PROFIL_DEGISTI_EVENT, guncelle);
|
return () => window.removeEventListener(PROFIL_DEGISTI_EVENT, guncelle);
|
||||||
}, [sira, tur, ilk]);
|
}, [sira, tur, ilk]);
|
||||||
|
|
||||||
|
// SERİ KIRILMASI (22 Eyl 2026): bu olay bu değişiklikten önce /sonuc'un
|
||||||
|
// ~2.200 px altında, tablonun arkasında yaşıyordu; artık tadımlık ilk
|
||||||
|
// ekranda. Adet bir gecede 0'dan yukarı fırlayacak — kırık ölçüm değil,
|
||||||
|
// kazanılan payda. Öncesi ve sonrası KARŞILAŞTIRILAMAZ; anlamlı ölçüt
|
||||||
|
// bundan sonra "tadımlık CTA tıklaması / tadımlık görüntülenmesi" oranıdır.
|
||||||
|
// (Not analitik.ts'e değil buraya yazıldı: o dosya aynı gece başka bir
|
||||||
|
// dalın altında — CTO şartnamesi, çakışma kararı #1.)
|
||||||
const gorunumRef = useGorunumOlayi<HTMLElement>("tadimlik_goruntulendi", {
|
const gorunumRef = useGorunumOlayi<HTMLElement>("tadimlik_goruntulendi", {
|
||||||
kova: siraKovasi(sira),
|
kova: siraKovasi(sira),
|
||||||
});
|
});
|
||||||
@@ -108,18 +115,32 @@ export function TadimlikSatiri({
|
|||||||
const seri = raporSiraSerisi(p.siraGecmisi, p.ilkYil);
|
const seri = raporSiraSerisi(p.siraGecmisi, p.ilkYil);
|
||||||
const taban = p.efektifSira ?? programEtkinSira(seri);
|
const taban = p.efektifSira ?? programEtkinSira(seri);
|
||||||
const devlet = p.unitur === "DEVLET";
|
const devlet = p.unitur === "DEVLET";
|
||||||
const girisUrl = `/giris?callback=${encodeURIComponent(sonucHref())}`;
|
// Giriş dönüşü kullanıcıyı /sonuc'a geri bırakmaz: callback doğrudan
|
||||||
|
// üretimin koştuğu /listem'e iner, liste ek tık olmadan orada başlar.
|
||||||
|
const girisUrl = `/giris?callback=${encodeURIComponent(listemUretHref("tadimlik"))}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section ref={gorunumRef} className="mt-16 min-w-0">
|
// first:mt-0 — /sonuc'ta bu <section> main'in ilk DOM çocuğudur (harita
|
||||||
|
// artık tablonun altında, üstte hiçbir kardeş yok; JSX yorumları düğüm
|
||||||
|
// üretmez): main'in py-12'si tek başına yeterli üst boşluğu verir.
|
||||||
|
// Tadımlığın render edilmediği durumlarda (girişli kullanıcı, boş havuz)
|
||||||
|
// bu bileşen hiç dönmediği için kural ilk gerçek bölüme geçer.
|
||||||
|
<section ref={gorunumRef} className="mt-16 min-w-0 first:mt-0">
|
||||||
<div className="flex flex-col items-center text-center">
|
<div className="flex flex-col items-center text-center">
|
||||||
<SectionEyebrow>Yapay zekâdan örnek satır</SectionEyebrow>
|
<SectionEyebrow>Yapay zekâdan örnek satır</SectionEyebrow>
|
||||||
<h2 className="mt-4 font-heading text-2xl font-bold sm:text-3xl">
|
<h2 className="mt-4 font-heading text-2xl font-bold sm:text-3xl">
|
||||||
Yapay zekâ listendeki her satırı böyle anlatır
|
Yapay zekâ listendeki her satırı böyle anlatır
|
||||||
</h2>
|
</h2>
|
||||||
|
{/* "ilk üçü" = rapor-maske.ts içindeki ACIK_SATIR (3). O dosya
|
||||||
|
`server-only`, bu dosya "use client" — sabit buraya import
|
||||||
|
edilemiyor, sayı elle yazıldı. ACIK_SATIR değişirse bu cümle de
|
||||||
|
aynı commit'te değişmeli. Cümle kasten "her satır bu formatta
|
||||||
|
kurulur"u sınırlıyor: maske girişsiz/paketsiz kullanıcıya 3 satır
|
||||||
|
açıyor, kalan 21'in gerekçe/risk/trend metni maskeli geliyor. */}
|
||||||
<p className="mx-auto mt-3 max-w-xl text-slate-600">
|
<p className="mx-auto mt-3 max-w-xl text-slate-600">
|
||||||
Sıralamana uygun bir programın gerekçesi, yerleşme riski ve taban
|
Sıralamana uygun bir programın gerekçesi, yerleşme riski ve taban
|
||||||
trendi — 24 tercihlik listenin her satırı bu formatta kurulur.
|
trendi — 24 tercihlik listenin her satırı bu formatta kurulur, ilk
|
||||||
|
üçü hemen açılır.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -172,7 +193,8 @@ export function TadimlikSatiri({
|
|||||||
<p className="text-sm text-slate-600">
|
<p className="text-sm text-slate-600">
|
||||||
Bu, 24 satırlık Yapay Zeka listenden yalnızca bir örnek.
|
Bu, 24 satırlık Yapay Zeka listenden yalnızca bir örnek.
|
||||||
<span className="block text-xs text-slate-500">
|
<span className="block text-xs text-slate-500">
|
||||||
Kredi kartı gerekmez · Google ya da e-posta ile 30 saniyede
|
Kredi kartı gerekmez · Google ya da e-posta ile 30 saniyede ·
|
||||||
|
Giriş sonrası liste hemen üretilir
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<Button
|
<Button
|
||||||
@@ -183,7 +205,10 @@ export function TadimlikSatiri({
|
|||||||
href={girisUrl}
|
href={girisUrl}
|
||||||
onClick={() => olay("giris_cta_tiklandi", { kaynak: "tadimlik" })}
|
onClick={() => olay("giris_cta_tiklandi", { kaynak: "tadimlik" })}
|
||||||
>
|
>
|
||||||
24 satırın tamamı için giriş yap — 5 deneme kredin hazır
|
{/* Buton metni listenin tamamını vaat etmez: maske girişsiz
|
||||||
|
kullanıcıya 24 satırdan yalnız ilk birkaçının analizini
|
||||||
|
açıyor (rapor-maske.ts), gerisi teslim edilmiyor. */}
|
||||||
|
Kendi listemi oluştur
|
||||||
<ArrowRight className="size-4" aria-hidden />
|
<ArrowRight className="size-4" aria-hidden />
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ const IZINLI_KAYNAKLAR = new Set([
|
|||||||
"giris_donusu",
|
"giris_donusu",
|
||||||
"bos_durum",
|
"bos_durum",
|
||||||
"odeme_sonrasi",
|
"odeme_sonrasi",
|
||||||
|
// /sonuc'taki girişsiz tadımlık CTA'sı (tadimlik-satiri.tsx).
|
||||||
|
"tadimlik",
|
||||||
// /sonuc'ta ?sihirbaz=1 ile otomatik başlayan üretimin gerçek yüzeyleri.
|
// /sonuc'ta ?sihirbaz=1 ile otomatik başlayan üretimin gerçek yüzeyleri.
|
||||||
// Eskiden hepsi "giris_donusu" sayılıyordu (güvenlik denetimi G3).
|
// Eskiden hepsi "giris_donusu" sayılıyordu (güvenlik denetimi G3).
|
||||||
"hero",
|
"hero",
|
||||||
|
|||||||
@@ -11,20 +11,14 @@ import { PixelField } from "@/components/pixel-decor";
|
|||||||
import { useGorunumOlayi } from "@/components/use-gorunum-olayi";
|
import { useGorunumOlayi } from "@/components/use-gorunum-olayi";
|
||||||
import { olay, olayBirKez, siraKovasi } from "@/lib/analitik";
|
import { olay, olayBirKez, siraKovasi } from "@/lib/analitik";
|
||||||
import type { SihirbazFacetleri } from "@/types/yokatlas";
|
import type { SihirbazFacetleri } from "@/types/yokatlas";
|
||||||
import { SIHIRBAZ_AC_EVENT, SIHIRBAZ_STORAGE_KEY, sihirbazDogrula, type SihirbazSecimleri } from "@/features/sihirbaz/sihirbaz-sabitler";
|
import { listemUretHref, SIHIRBAZ_AC_EVENT, SIHIRBAZ_STORAGE_KEY, sihirbazDogrula, type SihirbazSecimleri } from "@/features/sihirbaz/sihirbaz-sabitler";
|
||||||
import { tercihProfiliYaz } from "@/features/sihirbaz/sihirbaz-profil";
|
import { tercihProfiliYaz } from "@/features/sihirbaz/sihirbaz-profil";
|
||||||
import { SihirbazModal } from "./sihirbaz-modal";
|
import { SihirbazModal } from "./sihirbaz-modal";
|
||||||
|
|
||||||
// Üretim /listem'de koşar (bkz. listem/liste-uretici.tsx); sihirbaz
|
// Üretim /listem'de koşar (bkz. listem/liste-uretici.tsx); sihirbaz
|
||||||
// tamamlanınca seçimler storage'a yazılıp kullanıcı buraya yönlendirilir.
|
// tamamlanınca seçimler storage'a yazılıp kullanıcı buraya yönlendirilir.
|
||||||
// `kaynak` denemenin hangi yüzeyden başladığını ölçer (bkz.
|
// Hedef URL'i `listemUretHref` kurar (sihirbaz-sabitler.ts) — `uret=1`
|
||||||
// rapor/components/uretim-basladi-olayi.tsx — izinli değerler orada).
|
// parametre sırası sözleşmesi ve izinli `kaynak` değerleri orada yazılı.
|
||||||
// `uret=1` HER ZAMAN ilk parametre kalmalı: giris-karti.tsx:31 funnel
|
|
||||||
// metnini `callbackURL.startsWith("/listem?uret=1")` ile seçiyor, sıra
|
|
||||||
// bozulursa girişteki "Seçimlerin hazır" metni kaybolur.
|
|
||||||
function listemUretHref(kaynak: string) {
|
|
||||||
return `/listem?uret=1&kaynak=${kaynak}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SSR'da false, client'ta true — storage'a ancak mount sonrası dokunuruz
|
// SSR'da false, client'ta true — storage'a ancak mount sonrası dokunuruz
|
||||||
const bosAbone = () => () => {};
|
const bosAbone = () => () => {};
|
||||||
|
|||||||
@@ -168,6 +168,20 @@ export function sonucHref(ekstra?: Record<string, string>): string {
|
|||||||
return `/sonuc?${new URLSearchParams(girdiler)}`;
|
return `/sonuc?${new URLSearchParams(girdiler)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Üretimin koştuğu /listem URL'i. `kaynak` denemenin hangi yüzeyden
|
||||||
|
* başladığını ölçer (izinli değerler:
|
||||||
|
* rapor/components/uretim-basladi-olayi.tsx — yeni yüzeyi önce oraya ekle).
|
||||||
|
*
|
||||||
|
* `uret=1` HER ZAMAN ilk parametre kalmalı: giris-karti.tsx funnel metnini
|
||||||
|
* `callbackURL.startsWith("/listem?uret=1")` ile seçiyor, sıra bozulursa
|
||||||
|
* girişteki "Seçimlerin hazır" metni sessizce kaybolur. Bu sözleşmenin
|
||||||
|
* literal kopyası çoğalmasın diye tek kaynak burası.
|
||||||
|
*/
|
||||||
|
export function listemUretHref(kaynak: string): string {
|
||||||
|
return `/listem?uret=1&kaynak=${kaynak}`;
|
||||||
|
}
|
||||||
|
|
||||||
/** Prompt'a enjekte edilecek Türkçe özet. */
|
/** Prompt'a enjekte edilecek Türkçe özet. */
|
||||||
export function secimOzeti(secimler: SihirbazSecimleri): string {
|
export function secimOzeti(secimler: SihirbazSecimleri): string {
|
||||||
const satirlar = [
|
const satirlar = [
|
||||||
|
|||||||
Reference in New Issue
Block a user