diff --git a/src/app/giris/dogrula/page.tsx b/src/app/giris/dogrula/page.tsx
index 9be3acc..5242a9d 100644
--- a/src/app/giris/dogrula/page.tsx
+++ b/src/app/giris/dogrula/page.tsx
@@ -1,30 +1,16 @@
+import { Suspense } from "react";
import type { Metadata } from "next";
-import { redirect } from "next/navigation";
-import { ArrowRight } from "lucide-react";
-import { PixelCorner } from "@/components/pixel-decor";
-import { Button } from "@/components/ui/button";
+import {
+ DogrulaKarti,
+ DogrulaKartiSkeleton,
+} from "@/features/kullanici/components/dogrula-karti";
export const metadata: Metadata = {
title: "Girişini onayla",
robots: { index: false, follow: false },
};
-/** Yalnızca site içi (göreli) callback'lere izin ver — open redirect kalkanı. */
-function guvenliYol(deger: string | undefined, varsayilan: string): string {
- return deger && deger.startsWith("/") && !deger.startsWith("//")
- ? deger
- : varsayilan;
-}
-
-/**
- * Maildeki giriş bağlantısının indiği onay sayfası. Doğrulama ucu
- * (/api/auth/magic-link/verify) GET'lendiği anda token'ı tüketir; mail
- * güvenlik tarayıcıları ve tarayıcı ön-yüklemeleri linki kullanıcıdan önce
- * açıp token'ı yakabildiği için maildeki link token'ı TÜKETMEYEN bu sayfaya
- * gelir. Verify ancak buradaki form gönderilince tetiklenir — tarayıcı botları
- * sayfayı GET'lese bile form'u göndermez, token yanmaz.
- */
-export default async function DogrulaPage({
+export default function DogrulaPage({
searchParams,
}: {
searchParams: Promise<{
@@ -34,68 +20,19 @@ export default async function DogrulaPage({
newUserCallbackURL?: string;
}>;
}) {
- const { token, callbackURL, errorCallbackURL, newUserCallbackURL } =
- await searchParams;
- if (!token) redirect("/giris");
-
- const callback = guvenliYol(callbackURL, "/");
- const hataCallback = guvenliYol(
- errorCallbackURL,
- `/giris?hata=gecersiz-baglanti&callback=${encodeURIComponent(callback)}`,
- );
- const yeniKullaniciCallback = guvenliYol(newUserCallbackURL, callback);
-
return (
-
-
-
Girişini onayla
-
- Bu bağlantı senin için üretildi ve{" "}
- tek kullanımlık. Aşağıdaki
- butona tıkladığında KolayTercih hesabına giriş yapacaksın.
-
-
-
- Bu isteği sen yapmadıysan bu sayfayı kapatabilirsin — butona
- tıklanmadığı sürece hesabında hiçbir şey değişmez.
-
-
-
-
+ }>
+ {searchParams.then((sp) => (
+
+ ))}
+
);
diff --git a/src/app/giris/loading.tsx b/src/app/giris/loading.tsx
deleted file mode 100644
index 0b363f7..0000000
--- a/src/app/giris/loading.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { Skeleton } from "@/components/ui/skeleton";
-
-// /giris açılırken spinner yerine sayfanın kendi iskeleti: kart, başlık,
-// Google butonu, ayraç, e-posta alanı ve gönder butonu aynı yerde belirir —
-// içerik gelince zıplama olmaz.
-export default function GirisLoading() {
- return (
-
-
-
- {/* Başlık + alt metin */}
-
-
-
-
- {/* Google ile devam et */}
-
-
- {/* "veya" ayracı */}
-
-
-
-
-
-
- {/* E-posta alanı + gönder butonu */}
-
-
-
-
- {/* Kart altındaki yasal metin */}
-
-
-
-
-
-
- );
-}
diff --git a/src/app/giris/page.tsx b/src/app/giris/page.tsx
index db2bfe3..c8d2b10 100644
--- a/src/app/giris/page.tsx
+++ b/src/app/giris/page.tsx
@@ -1,95 +1,30 @@
+import { Suspense } from "react";
import type { Metadata } from "next";
-import Link from "next/link";
-import { redirect } from "next/navigation";
-import { getSession } from "@/lib/session";
-import { PixelCorner } from "@/components/pixel-decor";
-import { GirisForm } from "./giris-form";
-import { GirisBaslik } from "./giris-baslik";
+import {
+ GirisKarti,
+ GirisKartiSkeleton,
+} from "@/features/kullanici/components/giris-karti";
export const metadata: Metadata = {
title: "Giriş",
robots: { index: false, follow: true },
};
-export default async function GirisPage({
+export default function GirisPage({
searchParams,
}: {
searchParams: Promise<{ callback?: string; hata?: string }>;
}) {
- const { callback, hata } = await searchParams;
- const callbackURL =
- callback && callback.startsWith("/") ? callback : "/";
- // Magic link doğrulaması başarısız olunca errorCallbackURL buraya düşürür
- // (bkz. giris-form.tsx ve /giris/dogrula) — ham INVALID_TOKEN yerine
- // dostça bir mesaj gösterip yeni bağlantı istemeye yönlendiriyoruz.
- const baglantiHatasi = hata === "gecersiz-baglanti";
-
- const session = await getSession();
- if (session) redirect(callbackURL);
-
- // Sihirbaz funnel'ı: seçimler yapıldı, listeye giriş kaldı
- const funnel = callbackURL.startsWith("/sonuc");
-
return (
// -mb-28: layout'taki ScrollFlow sarmalayıcısının pb-28'ini nötrler —
// kart tam dvh içinde ortalanır, sayfa scroll etmez (sığmazsa scroll açılır).
-
-
- {baglantiHatasi && (
-
-
- Giriş bağlantısı geçersiz ya da süresi dolmuş
-
-
- Bağlantılar 15 dakika geçerli ve tek kullanımlık. Aşağıdan
- yeni bir bağlantı isteyebilirsin.
-
-
- )}
-
-
- {funnel ? (
- <>
- Seçimlerin hazır — giriş yap,{" "}
- 5 deneme kredinle listen
- hemen üretilsin.
- >
- ) : (
- <>
- Kayıt olduğunda{" "}
- 5 deneme kredisi{" "}
- hesabına tanımlanır — Yapay Zeka danışmana ücretsiz soru sorabilirsin.
- >
- )}
-
-
-
-
-
-
- Giriş yaparak verilerinin tercih önerileri üretmek amacıyla{" "}
-
- gizlilik metnindeki
- {" "}
- gibi işlenmesini ve{" "}
-
- kullanım koşullarını
- {" "}
- kabul etmiş olursun. KolayTercih yerleşme garantisi vermez.
-
+ }>
+ {searchParams.then(({ callback, hata }) => (
+
+ ))}
+
);
diff --git a/src/components/site-header.tsx b/src/components/site-header.tsx
index d48bf18..18c75dd 100644
--- a/src/components/site-header.tsx
+++ b/src/components/site-header.tsx
@@ -2,7 +2,7 @@ import { Suspense } from "react";
import Image from "next/image";
import Link from "next/link";
import { KatalogArama } from "@/features/katalog/components/katalog-arama";
-import { UserNav, UserNavFallback } from "@/components/user-nav";
+import { UserNav, UserNavFallback } from "@/features/kullanici/components/user-nav";
import { getAllRehberler } from "@/lib/rehber";
export function SiteHeader() {
diff --git a/src/features/kullanici/components/dogrula-karti.tsx b/src/features/kullanici/components/dogrula-karti.tsx
new file mode 100644
index 0000000..d9f56ee
--- /dev/null
+++ b/src/features/kullanici/components/dogrula-karti.tsx
@@ -0,0 +1,104 @@
+import { redirect } from "next/navigation";
+import { ArrowRight } from "lucide-react";
+import { PixelCorner } from "@/components/pixel-decor";
+import { Button } from "@/components/ui/button";
+import { Skeleton } from "@/components/ui/skeleton";
+
+/** Yalnızca site içi (göreli) callback'lere izin ver — open redirect kalkanı. */
+function guvenliYol(deger: string | undefined, varsayilan: string): string {
+ return deger && deger.startsWith("/") && !deger.startsWith("//")
+ ? deger
+ : varsayilan;
+}
+
+/**
+ * Maildeki giriş bağlantısının indiği onay kartı. Doğrulama ucu
+ * (/api/auth/magic-link/verify) GET'lendiği anda token'ı tüketir; mail
+ * güvenlik tarayıcıları ve tarayıcı ön-yüklemeleri linki kullanıcıdan önce
+ * açıp token'ı yakabildiği için maildeki link token'ı TÜKETMEYEN bu sayfaya
+ * gelir. Verify ancak buradaki form gönderilince tetiklenir — tarayıcı botları
+ * sayfayı GET'lese bile form'u göndermez, token yanmaz.
+ */
+export function DogrulaKarti({
+ token,
+ callbackURL,
+ errorCallbackURL,
+ newUserCallbackURL,
+}: {
+ token?: string;
+ callbackURL?: string;
+ errorCallbackURL?: string;
+ newUserCallbackURL?: string;
+}) {
+ if (!token) redirect("/giris");
+
+ const callback = guvenliYol(callbackURL, "/");
+ const hataCallback = guvenliYol(
+ errorCallbackURL,
+ `/giris?hata=gecersiz-baglanti&callback=${encodeURIComponent(callback)}`,
+ );
+ const yeniKullaniciCallback = guvenliYol(newUserCallbackURL, callback);
+
+ return (
+
+
+
Girişini onayla
+
+ Bu bağlantı senin için üretildi ve{" "}
+ tek kullanımlık. Aşağıdaki
+ butona tıkladığında KolayTercih hesabına giriş yapacaksın.
+
+
+
+ Bu isteği sen yapmadıysan bu sayfayı kapatabilirsin — butona
+ tıklanmadığı sürece hesabında hiçbir şey değişmez.
+
+
+
+
+ );
+}
+
+export function DogrulaKartiSkeleton() {
+ return (
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/giris/giris-baslik.tsx b/src/features/kullanici/components/giris-baslik.tsx
similarity index 100%
rename from src/app/giris/giris-baslik.tsx
rename to src/features/kullanici/components/giris-baslik.tsx
diff --git a/src/app/giris/giris-form.tsx b/src/features/kullanici/components/giris-form.tsx
similarity index 100%
rename from src/app/giris/giris-form.tsx
rename to src/features/kullanici/components/giris-form.tsx
diff --git a/src/features/kullanici/components/giris-karti.tsx b/src/features/kullanici/components/giris-karti.tsx
new file mode 100644
index 0000000..e93f716
--- /dev/null
+++ b/src/features/kullanici/components/giris-karti.tsx
@@ -0,0 +1,122 @@
+import Link from "next/link";
+import { redirect } from "next/navigation";
+import { getSession } from "@/lib/session";
+import { PixelCorner } from "@/components/pixel-decor";
+import { Skeleton } from "@/components/ui/skeleton";
+import { GirisForm } from "./giris-form";
+import { GirisBaslik } from "./giris-baslik";
+
+export async function GirisKarti({
+ callback,
+ hata,
+}: {
+ callback?: string;
+ hata?: string;
+}) {
+ const callbackURL = callback && callback.startsWith("/") ? callback : "/";
+ // Magic link doğrulaması başarısız olunca errorCallbackURL buraya düşürür
+ // (bkz. giris-form.tsx ve /giris/dogrula) — ham INVALID_TOKEN yerine
+ // dostça bir mesaj gösterip yeni bağlantı istemeye yönlendiriyoruz.
+ const baglantiHatasi = hata === "gecersiz-baglanti";
+
+ const session = await getSession();
+ if (session) redirect(callbackURL);
+
+ // Sihirbaz funnel'ı: seçimler yapıldı, listeye giriş kaldı
+ const funnel = callbackURL.startsWith("/sonuc");
+
+ return (
+ <>
+
+
+ {baglantiHatasi && (
+
+
+ Giriş bağlantısı geçersiz ya da süresi dolmuş
+
+
+ Bağlantılar 15 dakika geçerli ve tek kullanımlık. Aşağıdan
+ yeni bir bağlantı isteyebilirsin.
+
+
+ )}
+
+
+ {funnel ? (
+ <>
+ Seçimlerin hazır — giriş yap,{" "}
+ 5 deneme kredinle listen
+ hemen üretilsin.
+ >
+ ) : (
+ <>
+ Kayıt olduğunda{" "}
+ 5 deneme kredisi{" "}
+ hesabına tanımlanır — Yapay Zeka danışmana ücretsiz soru sorabilirsin.
+ >
+ )}
+
+
+
+
+
+
+ Giriş yaparak verilerinin tercih önerileri üretmek amacıyla{" "}
+
+ gizlilik metnindeki
+ {" "}
+ gibi işlenmesini ve{" "}
+
+ kullanım koşullarını
+ {" "}
+ kabul etmiş olursun. KolayTercih yerleşme garantisi vermez.
+
+ >
+ );
+}
+
+// Kart, başlık, Google butonu, ayraç, e-posta alanı ve gönder butonu aynı
+// yerde belirir — içerik gelince zıplama olmaz.
+export function GirisKartiSkeleton() {
+ return (
+ <>
+
+ {/* Başlık + alt metin */}
+
+
+
+
+ {/* Google ile devam et */}
+
+
+ {/* "veya" ayracı */}
+
+
+
+
+
+
+ {/* E-posta alanı + gönder butonu */}
+
+
+
+
+ {/* Kart altındaki yasal metin */}
+
+
+
+
+ >
+ );
+}
diff --git a/src/components/sign-out-button.tsx b/src/features/kullanici/components/sign-out-button.tsx
similarity index 100%
rename from src/components/sign-out-button.tsx
rename to src/features/kullanici/components/sign-out-button.tsx
diff --git a/src/components/user-nav.tsx b/src/features/kullanici/components/user-nav.tsx
similarity index 100%
rename from src/components/user-nav.tsx
rename to src/features/kullanici/components/user-nav.tsx