Files
next-fiber/app/auth/register/page.tsx
Beyhan Oğur b2825e1698 first commit
2026-04-26 22:14:08 +03:00

228 lines
7.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import React, { useRef, useState } from "react";
import Link from "next/link";
import { Turnstile, type TurnstileRef } from "nextjs-turnstile";
import { Loader2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { register } from "@/lib/auth-api";
import { AuthSocialButtons } from "@/components/auth-social-buttons";
import { cn } from "@/lib/utils";
const TURNSTILE_SITE_KEY =
process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY ?? process.env.NEXT_PUBLIC_CLOUD_FLARE_SITE_KEY ?? "";
export default function RegisterPage() {
const turnstileRef = useRef<TurnstileRef>(null);
const [email, setEmail] = useState("");
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [turnstileToken, setTurnstileToken] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState<string | null>(null);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError(null);
setSuccess(null);
if (!email.trim()) {
setError("E-posta gerekli.");
return;
}
if (!firstName.trim()) {
setError("Ad gerekli.");
return;
}
if (!lastName.trim()) {
setError("Soyad gerekli.");
return;
}
if (!username.trim()) {
setError("Kullanıcı adı gerekli.");
return;
}
if (password.length < 6) {
setError("Şifre en az 6 karakter olmalıdır.");
return;
}
if (TURNSTILE_SITE_KEY && !turnstileToken) {
setError("Lütfen doğrulamayı tamamlayın.");
return;
}
setLoading(true);
try {
const res = await register({
email: email.trim(),
first_name: firstName.trim(),
last_name: lastName.trim(),
username: username.trim(),
password,
});
setSuccess(
res.message ?? "Kayıt başarılı. Giriş yapmadan önce e-posta doğrulaması yapın."
);
turnstileRef.current?.reset();
setTurnstileToken(null);
} catch (err) {
setError(err instanceof Error ? err.message : "Kayıt oluşturulamadı.");
turnstileRef.current?.reset();
setTurnstileToken(null);
} finally {
setLoading(false);
}
};
return (
<div className="flex min-h-[calc(100vh-4rem)] items-center justify-center bg-zinc-50 px-4 py-12 dark:bg-neutral-950">
<div className="w-full max-w-md animate-in fade-in duration-300">
<div className="rounded-2xl border border-neutral-200 bg-white p-8 shadow-sm dark:border-neutral-800 dark:bg-neutral-900">
<h1 className="text-2xl font-bold text-neutral-900 dark:text-white">
Kayıt ol
</h1>
<p className="mt-1 text-sm text-neutral-500 dark:text-neutral-400">
Yeni hesap oluşturun
</p>
<form onSubmit={handleSubmit} className="mt-6 space-y-4">
{error && (
<div
className="rounded-lg bg-red-50 px-3 py-2 text-sm text-red-700 dark:bg-red-950/50 dark:text-red-400"
role="alert"
>
{error}
</div>
)}
{success && (
<div
className="rounded-lg bg-green-50 px-3 py-2 text-sm text-green-800 dark:bg-green-950/50 dark:text-green-300"
role="status"
>
{success}
</div>
)}
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="reg-first">Ad</Label>
<Input
id="reg-first"
type="text"
autoComplete="given-name"
placeholder="Ad"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
disabled={loading}
className="rounded-lg border-neutral-200 dark:border-neutral-700"
/>
</div>
<div className="space-y-2">
<Label htmlFor="reg-last">Soyad</Label>
<Input
id="reg-last"
type="text"
autoComplete="family-name"
placeholder="Soyad"
value={lastName}
onChange={(e) => setLastName(e.target.value)}
disabled={loading}
className="rounded-lg border-neutral-200 dark:border-neutral-700"
/>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="reg-username">Kullanıcı adı</Label>
<Input
id="reg-username"
type="text"
autoComplete="username"
placeholder="kullanici_adi"
value={username}
onChange={(e) => setUsername(e.target.value)}
disabled={loading}
className={cn(
"w-full rounded-lg border-neutral-200 dark:border-neutral-700"
)}
/>
</div>
<div className="space-y-2">
<Label htmlFor="reg-email">E-posta</Label>
<Input
id="reg-email"
type="email"
autoComplete="email"
placeholder="ornek@email.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
disabled={loading}
className="w-full rounded-lg border-neutral-200 dark:border-neutral-700"
/>
</div>
<div className="space-y-2">
<Label htmlFor="reg-password">Şifre</Label>
<Input
id="reg-password"
type="password"
autoComplete="new-password"
placeholder="En az 6 karakter"
value={password}
onChange={(e) => setPassword(e.target.value)}
disabled={loading}
className="w-full rounded-lg border-neutral-200 dark:border-neutral-700"
/>
</div>
{TURNSTILE_SITE_KEY && (
<div className="flex justify-center [&_iframe]:max-w-full">
<Turnstile
ref={turnstileRef}
siteKey={TURNSTILE_SITE_KEY}
theme="auto"
onSuccess={setTurnstileToken}
onExpire={() => setTurnstileToken(null)}
onError={() => setTurnstileToken(null)}
/>
</div>
)}
<Button
type="submit"
className="w-full rounded-lg"
size="lg"
disabled={loading}
>
{loading ? (
<>
<Loader2 className="size-4 animate-spin" />
Kaydediliyor...
</>
) : (
"Kayıt ol"
)}
</Button>
<AuthSocialButtons callbackUrl="/" disabled={loading} />
</form>
<p className="mt-6 text-center text-sm text-neutral-600 dark:text-neutral-400">
Zaten hesabınız var mı?{" "}
<Link
href="/auth/login"
className="font-medium text-blue-600 hover:underline dark:text-blue-400"
>
Giriş yapın
</Link>
</p>
</div>
</div>
</div>
);
}