feat(katalog): başlığın altında kompakt sıra giriş satırı (alttaki kart yerinde)

Katalog 464 oturum → 12 sıra girişi; kart tablonun altında kalıyordu. CtaSiraForm'a
varyant="kompakt" + konum prop'u; olay adları aynı, konum: ust|alt özelliği eklendi;
alan kimlikleri useId ile (aynı sayfada iki form).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-09-21 23:34:52 +03:00
parent ea3310ac5b
commit 992a01abf1
3 changed files with 286 additions and 155 deletions

View File

@@ -174,6 +174,9 @@ export function BolumIcerik({ slug, sayfa }: { slug: string; sayfa: number }) {
const ilkSayfa = sayfa === 1; const ilkSayfa = sayfa === 1;
const aralik = siraAraligiMetni(sayfaDilim); const aralik = siraAraligiMetni(sayfaDilim);
const buYol = ilkSayfa ? `/bolum/${slug}` : `/bolum/${slug}/sayfa/${sayfa}`; const buYol = ilkSayfa ? `/bolum/${slug}` : `/bolum/${slug}/sayfa/${sayfa}`;
// Üst satır ve alt kart aynı soruyu sorar; sayfalama sayfalarında da bölüm
// adı geçer (ziyaretçi Google'dan doğrudan /sayfa/N'ye iniyor).
const ctaBaslik = `Sıralaman ${bolum.ad} tabanlarının neresinde?`;
return ( return (
<> <>
@@ -258,6 +261,12 @@ export function BolumIcerik({ slug, sayfa }: { slug: string; sayfa: number }) {
)} )}
</header> </header>
{/* Tek sayfada çıkan ziyaretçi alttaki karta inmiyor: kompakt sıra girişi
başlık bloğunun hemen altında, listenin üstünde. Alttaki kart kalır. */}
<div className="mt-6">
<CtaSiraForm varyant="kompakt" konum="ust" baslik={ctaBaslik} />
</div>
<section aria-labelledby="universite-programlari" className="mt-8"> <section aria-labelledby="universite-programlari" className="mt-8">
<div className="mb-4 flex items-end justify-between gap-4"> <div className="mb-4 flex items-end justify-between gap-4">
<h2 <h2
@@ -286,7 +295,8 @@ export function BolumIcerik({ slug, sayfa }: { slug: string; sayfa: number }) {
{/* Üniversite sayfasıyla aynı konum ve aynı kart: liste + sayfalama altı */} {/* Üniversite sayfasıyla aynı konum ve aynı kart: liste + sayfalama altı */}
<div className="mt-10"> <div className="mt-10">
<CtaSiraForm <CtaSiraForm
baslik={`Sıralaman ${bolum.ad} tabanlarının neresinde?`} konum="alt"
baslik={ctaBaslik}
aciklama={KATALOG_CTA_ACIKLAMA} aciklama={KATALOG_CTA_ACIKLAMA}
/> />
</div> </div>

View File

@@ -169,6 +169,17 @@ export function UniversiteIcerik({
? `/universite/${slug}` ? `/universite/${slug}`
: `/universite/${slug}/sayfa/${sayfa}`; : `/universite/${slug}/sayfa/${sayfa}`;
const yurtdisi = uniUlkeKonum(uni.ad, uni.il); const yurtdisi = uniUlkeKonum(uni.ad, uni.il);
// Üst satır ve alt kart aynı soruyu sorar; sayfalama sayfalarında da
// üniversite adı geçer (ziyaretçi Google'dan doğrudan /sayfa/N'ye iniyor).
const ctaBaslik = `Sıralaman ${uni.ad} tabanlarının neresinde?`;
// Tek sayfada çıkan ziyaretçi alttaki karta inmiyor: kompakt sıra girişi
// özet paragrafının hemen altında, tablonun (ve ilk sayfadaki istatistik
// ızgarasının) üstünde durur. Alttaki kart yerinde kalır.
const ustSiraSatiri = (
<div className="mt-6">
<CtaSiraForm varyant="kompakt" konum="ust" baslik={ctaBaslik} />
</div>
);
return ( return (
<> <>
@@ -276,6 +287,8 @@ export function UniversiteIcerik({
</em> </em>
</p> </p>
{ustSiraSatiri}
<div className="mt-6 grid grid-cols-2 gap-3 lg:grid-cols-[1fr_1fr_1.35fr] lg:grid-rows-2"> <div className="mt-6 grid grid-cols-2 gap-3 lg:grid-cols-[1fr_1fr_1.35fr] lg:grid-rows-2">
<UniversiteKonumHaritasi universite={uni.ad} il={uni.il} /> <UniversiteKonumHaritasi universite={uni.ad} il={uni.il} />
<dl className="contents"> <dl className="contents">
@@ -319,22 +332,25 @@ export function UniversiteIcerik({
</div> </div>
</> </>
) : ( ) : (
<p className="mt-4 max-w-3xl text-sm leading-7 text-slate-600"> <>
{uni.ad} taban puanları tablosunun {sayfa}. sayfası ( <p className="mt-4 max-w-3xl text-sm leading-7 text-slate-600">
{sayi(tumProgramlar.length)} programın{" "} {uni.ad} taban puanları tablosunun {sayfa}. sayfası (
{sayi((sayfa - 1) * SAYFA_BOYU + 1)}– {sayi(tumProgramlar.length)} programın{" "}
{sayi(Math.min(sayfa * SAYFA_BOYU, tumProgramlar.length))}. {sayi((sayfa - 1) * SAYFA_BOYU + 1)}–
satırları, fakülte sırasıyla). {sayi(Math.min(sayfa * SAYFA_BOYU, tumProgramlar.length))}.
{birimler ? ` Bu sayfadaki birimler: ${birimler}.` : ""} Üniversite satırları, fakülte sırasıyla).
özeti ve istatistikler{" "} {birimler ? ` Bu sayfadaki birimler: ${birimler}.` : ""} Üniversite
<Link özeti ve istatistikler{" "}
href={`/universite/${slug}`} <Link
className="font-medium text-primary hover:underline" href={`/universite/${slug}`}
> className="font-medium text-primary hover:underline"
ilk sayfada >
</Link> ilk sayfada
. </Link>
</p> .
</p>
{ustSiraSatiri}
</>
)} )}
<PagePixelDivider seed={57} className="mt-8" /> <PagePixelDivider seed={57} className="mt-8" />
@@ -363,7 +379,8 @@ export function UniversiteIcerik({
<div className="mt-10"> <div className="mt-10">
<CtaSiraForm <CtaSiraForm
baslik={`Sıralaman ${uni.ad} tabanlarının neresinde?`} konum="alt"
baslik={ctaBaslik}
aciklama={KATALOG_CTA_ACIKLAMA} aciklama={KATALOG_CTA_ACIKLAMA}
/> />
</div> </div>

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { useState } from "react"; import { useId, useState } from "react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { import {
@@ -28,6 +28,7 @@ import {
} from "./sihirbaz-adimlar-lazy"; } from "./sihirbaz-adimlar-lazy";
import { authClient } from "@/lib/auth-client"; import { authClient } from "@/lib/auth-client";
import { olay, siraKovasi } from "@/lib/analitik"; import { olay, siraKovasi } from "@/lib/analitik";
import { cn } from "@/lib/utils";
import { onbellekliJsonGetir } from "@/lib/istek-cache"; import { onbellekliJsonGetir } from "@/lib/istek-cache";
import { useTercihProfili } from "@/features/liste/hooks/use-tercih-profili"; import { useTercihProfili } from "@/features/liste/hooks/use-tercih-profili";
import type { SihirbazFacetleri } from "@/types/yokatlas"; import type { SihirbazFacetleri } from "@/types/yokatlas";
@@ -65,16 +66,34 @@ const KANITLAR = [
* profilsiz karttaki paragrafı değiştirir — katalog sayfaları kartı üstündeki * profilsiz karttaki paragrafı değiştirir — katalog sayfaları kartı üstündeki
* tabloya bağlayan köprü cümlesini buradan verir. Başlık ve açıklamalar * tabloya bağlayan köprü cümlesini buradan verir. Başlık ve açıklamalar
* yerleşme vaadi içermez: ürün sıralamaya yakın programları listeler. * yerleşme vaadi içermez: ürün sıralamaya yakın programları listeler.
*
* `varyant="kompakt"`: katalog sayfalarında başlığın hemen altına, tablonun
* ÜSTÜNE konan tek satırlık sürüm. Sıralama alanı çekmecede değil doğrudan
* sayfadadır (tek sayfada çıkan ziyaretçi alttaki karta hiç inmiyor); gönderince
* aynı çekmece sihirbaz adımıyla açılır. Aynı sayfada alttaki kartla birlikte
* durduğu için alan kimlikleri `useId` ile üretilir, analitik olayları da
* `konum` ("ust" | "alt") özelliğiyle ayrışır — olay adları değişmez.
*/ */
export function CtaSiraForm({ export function CtaSiraForm({
baslik, baslik,
aciklama, aciklama,
varyant = "kart",
konum = "alt",
}: { }: {
baslik?: string; baslik?: string;
aciklama?: string; aciklama?: string;
varyant?: "kart" | "kompakt";
/** Yalnız ölçüm içindir: formun sayfadaki yeri (tablonun üstü / altı). */
konum?: "ust" | "alt";
}) { }) {
const profil = useTercihProfili(); const profil = useTercihProfili();
const router = useRouter(); const router = useRouter();
const kompakt = varyant === "kompakt";
// Aynı sayfada iki form (üst satır + alt kart) olabildiği için sabit id yok.
const kimlik = useId();
const alanId = `${kimlik}-siralama`;
const hataId = `${kimlik}-siralama-hata`;
const baslikId = `${kimlik}-baslik`;
const [acik, setAcik] = useState(false); const [acik, setAcik] = useState(false);
const [adim, setAdim] = useState<"sira" | "sihirbaz">("sira"); const [adim, setAdim] = useState<"sira" | "sihirbaz">("sira");
@@ -87,8 +106,14 @@ export function CtaSiraForm({
const [girisli, setGirisli] = useState(false); const [girisli, setGirisli] = useState(false);
// Huni girişi ölçümü: ref yalnızca profilsiz daldaki karta bağlanır; kayıtlı // Huni girişi ölçümü: ref yalnızca profilsiz daldaki karta bağlanır; kayıtlı
// profilli ziyaretçi formu hiç görmediğinden sayılmaz. Sayfa ayrımı için // profilli ziyaretçi formu hiç görmediğinden sayılmaz. Sayfa ayrımı için
// özellik gerekmez — Rybbit olayın pathname'ini zaten yazar. // özellik gerekmez — Rybbit olayın pathname'ini zaten yazar. `konum` hem
const formRef = useGorunumOlayi<HTMLElement>("cta_form_goruntulendi"); // özellik hem tekilleştirme ekidir: üstteki satır olayı atınca alttaki kartın
// gösterimi yutulmasın (oturum başına konum başına en fazla 1).
const formRef = useGorunumOlayi<HTMLElement>(
"cta_form_goruntulendi",
{ konum },
konum,
);
// Yazarken binlik ayracıyla biçimle (85000 → 85.000) // Yazarken binlik ayracıyla biçimle (85000 → 85.000)
function siralamaDegisti(ham: string) { function siralamaDegisti(ham: string) {
@@ -118,13 +143,17 @@ export function CtaSiraForm({
setSira(value); setSira(value);
setFacetler(veri.facetler); setFacetler(veri.facetler);
setAdim("sihirbaz"); setAdim("sihirbaz");
// Kompakt satırda sıralama sayfada girilir; çekmece ancak şimdi,
// doğrudan sihirbaz adımıyla açılır (kartta zaten açıktır).
setAcik(true);
olay("sira_girildi", { olay("sira_girildi", {
kaynak: "cta", kaynak: "cta",
konum,
tur, tur,
sira_kovasi: siraKovasi(value), sira_kovasi: siraKovasi(value),
}); });
} catch { } catch {
olay("sira_form_hata", { kaynak: "cta" }); olay("sira_form_hata", { kaynak: "cta", konum });
setHata("Bir şeyler ters gitti, tekrar dener misin?"); setHata("Bir şeyler ters gitti, tekrar dener misin?");
} finally { } finally {
setYukleniyor(false); setYukleniyor(false);
@@ -146,13 +175,219 @@ export function CtaSiraForm({
function acikDegisti(v: boolean) { function acikDegisti(v: boolean) {
setAcik(v); setAcik(v);
if (!v) { if (!v) {
setHata(null);
// Kompakt satırda çekmecenin sıra adımı yoktur; her gönderim adımı ve
// facet'leri zaten baştan yazar (kapanış animasyonunda içerik boşalmasın).
if (kompakt) return;
// Yeniden açılışta sıfırdan başla; yazılan sıralama kaybolmasın. // Yeniden açılışta sıfırdan başla; yazılan sıralama kaybolmasın.
setAdim("sira"); setAdim("sira");
setFacetler(null); setFacetler(null);
setHata(null);
} }
} }
// Sıra girişi: kartta çekmecenin ilk adımı, kompakt satırda sayfanın kendisi.
// Kompakt sürüm masaüstünde (lg) tek satırdır: çipler · alan · buton.
const siraFormu = (
<form
onSubmit={siraGonder}
className={
kompakt
? "flex flex-col gap-3 lg:flex-row lg:flex-wrap lg:items-center"
: "flex flex-col gap-3"
}
>
<div
role="radiogroup"
aria-label="Puan türü"
className={cn("flex flex-wrap gap-1.5", kompakt && "lg:shrink-0")}
>
{PUAN_TURLERI_SECENEK.map((t) => (
<button
key={t.deger}
type="button"
role="radio"
aria-checked={tur === t.deger}
onClick={() => setTur(t.deger)}
className={
tur === t.deger
? "cursor-pointer rounded-full border border-primary bg-primary px-3 py-1.5 text-xs font-medium text-white transition-colors duration-200"
: "cursor-pointer rounded-full border border-slate-200 bg-white px-3 py-1.5 text-xs text-slate-600 transition-colors duration-200 hover:border-slate-300 hover:bg-slate-50"
}
>
{t.etiket}
</button>
))}
</div>
<label htmlFor={alanId} className="sr-only">
YKS başarı sıralaması
</label>
<div
className={cn(
"flex flex-col gap-3 sm:flex-row",
kompakt && "lg:min-w-0 lg:flex-1",
)}
>
<div className="relative sm:flex-1">
<Trophy
className="pointer-events-none absolute left-4 top-1/2 size-4 -translate-y-1/2 text-slate-400"
aria-hidden
/>
<Input
id={alanId}
inputMode="numeric"
autoComplete="off"
placeholder="YKS başarı sıralaman (ör. 85.000)"
value={siralama}
onChange={(e) => siralamaDegisti(e.target.value)}
onFocus={preloadSihirbazAdimlar}
aria-invalid={hata ? true : undefined}
aria-describedby={hata ? hataId : undefined}
className="h-12 bg-background pl-11 text-base"
/>
</div>
<Button
type="submit"
disabled={yukleniyor}
className="h-12 cursor-pointer bg-orange-500 px-6 text-white transition-colors duration-200 hover:bg-orange-600"
>
{yukleniyor ? "Hazırlanıyor…" : "Programları gör"}
<ArrowRight className="size-4" aria-hidden />
</Button>
</div>
{hata ? (
<p
id={hataId}
role="alert"
className={cn(
"text-sm font-medium text-red-600",
kompakt && "lg:basis-full",
)}
>
{hata}
</p>
) : null}
</form>
);
// Çekmece iki varyantta da aynıdır; kompakt satırda sıra adımı sayfada
// olduğundan çekmece yalnız sihirbazı taşır.
const cekmece = (
<Drawer open={acik} onOpenChange={acikDegisti} handleOnly>
<DrawerContent
className="max-h-[92dvh] bg-white sm:mx-auto sm:max-w-2xl sm:border-x sm:border-slate-200 sm:shadow-2xl"
>
{/* Görünür başlıklar adıma göre değişir; erişilebilir ad sabit kalır. */}
<DrawerTitle className="sr-only">
Sıralamana yakın programlar hangileri?
</DrawerTitle>
<DrawerDescription className="sr-only">
YKS başarı sıralamanı gir; sıralamana uygun programları bu sayfadan
ayrılmadan gör.
</DrawerDescription>
<DrawerClose className="absolute top-3 right-3 z-10 flex size-9 cursor-pointer items-center justify-center rounded-full border border-slate-200 bg-popover text-slate-500 transition-[background-color,transform] duration-150 hover:bg-slate-100 hover:text-slate-800 active:scale-[0.96]">
<X className="size-4" aria-hidden />
<span className="sr-only">Kapat</span>
</DrawerClose>
<div
className="min-h-0 flex-1 overflow-y-auto px-4 pt-5 pb-[max(1.25rem,env(safe-area-inset-bottom))] sm:px-6"
>
{!kompakt && adim === "sira" ? (
<div className="flex flex-col gap-5">
<div>
<SectionEyebrow>Saniyede gör</SectionEyebrow>
<h2 className="mt-3 font-heading text-2xl font-bold text-slate-900">
Sıralamana yakın programlar hangileri?
</h2>
<p className="mt-2 max-w-xl text-sm leading-6 text-slate-600">
Puan türünü seç, başarı sıralamanı yaz; hayal, dengeli ve
güvenli dilimlerindeki programları bu sayfadan ayrılmadan
gör. Ücretsiz, üyelik gerekmez.
</p>
</div>
{siraFormu}
<ul
aria-label="Neler alacaksın"
className="flex flex-wrap gap-x-4 gap-y-2 border-t border-slate-100 pt-4"
>
{KANITLAR.map(({ ikon: Ikon, etiket }) => (
<li
key={etiket}
className="inline-flex items-center gap-1.5 text-xs font-medium text-slate-600"
>
<Ikon className="size-3.5 text-primary" aria-hidden />
{etiket}
</li>
))}
</ul>
</div>
) : facetler && sira != null ? (
<SihirbazAdimlarLazy
key={`${sira}-${tur}`}
sira={sira}
tur={tur}
facetler={facetler}
sonButonEtiketi={
girisli ? "Yapay Zeka listemi kur (3 kredi)" : "Ücretsiz tablonu gör"
}
onTamamla={secimleriTamamla}
/>
) : null}
</div>
</DrawerContent>
</Drawer>
);
if (kompakt) {
// CLS: kayıtlı profil hydration SONRASI bulunur. Satır tablonun üstünde
// olduğundan yüksekliği o anda değişmemeli — form yerinde (görünmez ve
// inert) kalır, profilli kısayol aynı ızgara hücresine bindirilir; hücrenin
// yüksekliğini her iki durumda da form belirler.
return (
<section
aria-labelledby={baslikId}
className="rounded-2xl border border-slate-200 bg-white p-4 sm:p-5"
>
<p className="text-sm leading-6 text-slate-600">
<strong
id={baslikId}
className="font-heading text-base font-bold text-slate-900"
>
{baslik ?? "Sıralaman bu tabanların neresinde?"}
</strong>{" "}
Ücretsiz, üyelik gerekmez.
</p>
<div className="mt-3 grid">
<div
ref={profil ? undefined : formRef}
inert={profil ? true : undefined}
className={cn("col-start-1 row-start-1", profil && "invisible")}
>
{siraFormu}
</div>
{profil ? (
<div className="col-start-1 row-start-1 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<p className="text-sm leading-6 text-slate-600">
Sıralaman kayıtlı ({profil.sira.toLocaleString("tr-TR")}. sıra).
</p>
<Link
href={sonucHref()}
className="inline-flex h-11 items-center justify-center gap-2 rounded-full bg-orange-500 px-6 text-sm font-semibold text-white transition-colors duration-200 hover:bg-orange-600"
>
Sıralamana uygun programları gör
<ArrowRight className="size-4" aria-hidden />
</Link>
</div>
) : null}
</div>
{cekmece}
</section>
);
}
if (profil) { if (profil) {
return ( return (
<section className="rounded-2xl border border-primary/20 bg-primary/5 p-6 sm:p-8"> <section className="rounded-2xl border border-primary/20 bg-primary/5 p-6 sm:p-8">
@@ -198,138 +433,7 @@ export function CtaSiraForm({
<ArrowRight className="size-4" aria-hidden /> <ArrowRight className="size-4" aria-hidden />
</Button> </Button>
<Drawer open={acik} onOpenChange={acikDegisti} handleOnly> {cekmece}
<DrawerContent
className="max-h-[92dvh] bg-white sm:mx-auto sm:max-w-2xl sm:border-x sm:border-slate-200 sm:shadow-2xl"
>
{/* Görünür başlıklar adıma göre değişir; erişilebilir ad sabit kalır. */}
<DrawerTitle className="sr-only">
Sıralamana yakın programlar hangileri?
</DrawerTitle>
<DrawerDescription className="sr-only">
YKS başarı sıralamanı gir; sıralamana uygun programları bu sayfadan
ayrılmadan gör.
</DrawerDescription>
<DrawerClose className="absolute top-3 right-3 z-10 flex size-9 cursor-pointer items-center justify-center rounded-full border border-slate-200 bg-popover text-slate-500 transition-[background-color,transform] duration-150 hover:bg-slate-100 hover:text-slate-800 active:scale-[0.96]">
<X className="size-4" aria-hidden />
<span className="sr-only">Kapat</span>
</DrawerClose>
<div
className="min-h-0 flex-1 overflow-y-auto px-4 pt-5 pb-[max(1.25rem,env(safe-area-inset-bottom))] sm:px-6"
>
{adim === "sira" ? (
<div className="flex flex-col gap-5">
<div>
<SectionEyebrow>Saniyede gör</SectionEyebrow>
<h2 className="mt-3 font-heading text-2xl font-bold text-slate-900">
Sıralamana yakın programlar hangileri?
</h2>
<p className="mt-2 max-w-xl text-sm leading-6 text-slate-600">
Puan türünü seç, başarı sıralamanı yaz; hayal, dengeli ve
güvenli dilimlerindeki programları bu sayfadan ayrılmadan
gör. Ücretsiz, üyelik gerekmez.
</p>
</div>
<form onSubmit={siraGonder} className="flex flex-col gap-3">
<div
role="radiogroup"
aria-label="Puan türü"
className="flex flex-wrap gap-1.5"
>
{PUAN_TURLERI_SECENEK.map((t) => (
<button
key={t.deger}
type="button"
role="radio"
aria-checked={tur === t.deger}
onClick={() => setTur(t.deger)}
className={
tur === t.deger
? "cursor-pointer rounded-full border border-primary bg-primary px-3 py-1.5 text-xs font-medium text-white transition-colors duration-200"
: "cursor-pointer rounded-full border border-slate-200 bg-white px-3 py-1.5 text-xs text-slate-600 transition-colors duration-200 hover:border-slate-300 hover:bg-slate-50"
}
>
{t.etiket}
</button>
))}
</div>
<label htmlFor="cta-siralama" className="sr-only">
YKS başarı sıralaması
</label>
<div className="flex flex-col gap-3 sm:flex-row">
<div className="relative sm:flex-1">
<Trophy
className="pointer-events-none absolute left-4 top-1/2 size-4 -translate-y-1/2 text-slate-400"
aria-hidden
/>
<Input
id="cta-siralama"
inputMode="numeric"
autoComplete="off"
placeholder="YKS başarı sıralaman (ör. 85.000)"
value={siralama}
onChange={(e) => siralamaDegisti(e.target.value)}
onFocus={preloadSihirbazAdimlar}
aria-invalid={hata ? true : undefined}
aria-describedby={
hata ? "cta-siralama-hata" : undefined
}
className="h-12 bg-background pl-11 text-base"
/>
</div>
<Button
type="submit"
disabled={yukleniyor}
className="h-12 cursor-pointer bg-orange-500 px-6 text-white transition-colors duration-200 hover:bg-orange-600"
>
{yukleniyor ? "Hazırlanıyor…" : "Programları gör"}
<ArrowRight className="size-4" aria-hidden />
</Button>
</div>
{hata ? (
<p
id="cta-siralama-hata"
role="alert"
className="text-sm font-medium text-red-600"
>
{hata}
</p>
) : null}
</form>
<ul
aria-label="Neler alacaksın"
className="flex flex-wrap gap-x-4 gap-y-2 border-t border-slate-100 pt-4"
>
{KANITLAR.map(({ ikon: Ikon, etiket }) => (
<li
key={etiket}
className="inline-flex items-center gap-1.5 text-xs font-medium text-slate-600"
>
<Ikon className="size-3.5 text-primary" aria-hidden />
{etiket}
</li>
))}
</ul>
</div>
) : facetler && sira != null ? (
<SihirbazAdimlarLazy
key={`${sira}-${tur}`}
sira={sira}
tur={tur}
facetler={facetler}
sonButonEtiketi={
girisli ? "Yapay Zeka listemi kur (3 kredi)" : "Ücretsiz tablonu gör"
}
onTamamla={secimleriTamamla}
/>
) : null}
</div>
</DrawerContent>
</Drawer>
</section> </section>
); );
} }