2026-03-01 14:19:16 +00:00

299 lines
11 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

import { useState } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAuth } from '@/contexts/AuthContext';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Checkbox } from '@/components/ui/checkbox';
import { toast } from 'sonner';
import { Loader2, MapPin, Rocket, Map, Save, Users, Eye, EyeOff, Shield } from 'lucide-react';
export default function LoginPage() {
const [isLogin, setIsLogin] = useState(true);
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [showPassword, setShowPassword] = useState(false);
const [rememberMe, setRememberMe] = useState(false);
const [loading, setLoading] = useState(false);
const { signInWithUsername, signUpWithUsername, user } = useAuth();
const navigate = useNavigate();
const location = useLocation();
const from = location.state?.from || '/explore';
// Eğer kullanıcı zaten giriş yapmışsa yönlendir
if (user) {
navigate(from, { replace: true });
}
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!username || !password) return;
// Kullanıcı adı validasyonu
if (!/^[a-z0-9_]+$/.test(username)) {
toast.error('Kullanıcı adı sadece harf, rakam ve alt çizgi içerebilir');
return;
}
if (password.length < 6) {
toast.error('Şifre en az 6 karakter olmalıdır');
return;
}
setLoading(true);
try {
if (isLogin) {
const { error } = await signInWithUsername(username, password);
if (error) {
if (error.message.includes('Invalid login credentials')) {
throw new Error('Kullanıcı adı veya şifre hatalı');
}
throw error;
}
toast.success(`Hoşgeldin, ${username}!`);
navigate(from, { replace: true });
} else {
const { error } = await signUpWithUsername(username, password);
if (error) {
if (error.message.includes('already registered')) {
throw new Error('Bu kullanıcı adı zaten kullanılıyor');
}
throw error;
}
toast.success('Hesap oluşturuldu! Giriş yapılıyor...');
// Otomatik giriş yap
const { error: signInError } = await signInWithUsername(username, password);
if (!signInError) {
navigate(from, { replace: true });
}
}
} catch (error: any) {
const errorMessage = error.message || 'Bir hata oluştu. Lütfen tekrar deneyin.';
toast.error(errorMessage);
} finally {
setLoading(false);
}
};
return (
<div className="min-h-screen flex">
{/* Sol Taraf - Hero Section (Sadece Desktop) */}
<div className="hidden lg:flex lg:w-1/2 bg-gradient-to-br from-blue-500 via-blue-600 to-blue-800 p-12 flex-col justify-between text-white relative overflow-hidden">
{/* Dekoratif arka plan */}
<div className="absolute inset-0 opacity-10">
<div className="absolute top-20 left-20 w-72 h-72 bg-white rounded-full blur-3xl" />
<div className="absolute bottom-20 right-20 w-96 h-96 bg-white rounded-full blur-3xl" />
</div>
<div className="relative z-10">
{/* Logo */}
<div className="flex items-center space-x-3 mb-16">
<div className="p-3 bg-white/20 backdrop-blur-sm rounded-2xl">
<MapPin className="h-8 w-8" />
</div>
<span className="text-2xl font-bold">Cappadocia AI</span>
</div>
{/* Ana Başlık */}
<div className="space-y-6 max-w-md">
<h1 className="text-5xl font-bold leading-tight">
Kapadokya'ya Hoşgeldin
</h1>
<p className="text-xl text-blue-100">
Yapay zeka rehberliğinde unutulmaz deneyimler yarat
</p>
{/* Özellikler Listesi */}
<div className="space-y-4 pt-8">
<div className="flex items-center space-x-3">
<div className="p-2 bg-white/20 backdrop-blur-sm rounded-lg">
<Rocket className="h-5 w-5" />
</div>
<span className="text-lg">AI Destekli Planlama</span>
</div>
<div className="flex items-center space-x-3">
<div className="p-2 bg-white/20 backdrop-blur-sm rounded-lg">
<Map className="h-5 w-5" />
</div>
<span className="text-lg">Gerçek Zamanlı Haritalar</span>
</div>
<div className="flex items-center space-x-3">
<div className="p-2 bg-white/20 backdrop-blur-sm rounded-lg">
<Save className="h-5 w-5" />
</div>
<span className="text-lg">Planlarını Kaydet</span>
</div>
<div className="flex items-center space-x-3">
<div className="p-2 bg-white/20 backdrop-blur-sm rounded-lg">
<Users className="h-5 w-5" />
</div>
<span className="text-lg">Arkadaşlarınla Paylaş</span>
</div>
</div>
</div>
</div>
{/* Alt Bilgi */}
<div className="relative z-10 flex items-center space-x-2 text-sm text-blue-100">
<Shield className="h-4 w-4" />
<span>Güvenlik: Verileriniz 256-bit SSL ile korunur</span>
</div>
</div>
{/* Sağ Taraf - Login Form */}
<div className="w-full lg:w-1/2 flex items-center justify-center p-8 bg-background">
<div className="w-full max-w-md space-y-8">
{/* Mobile Logo */}
<div className="lg:hidden flex justify-center mb-8">
<div className="flex items-center space-x-2">
<MapPin className="h-8 w-8 text-primary" />
<span className="text-2xl font-bold">Cappadocia AI</span>
</div>
</div>
{/* Form Header */}
<div className="space-y-2 text-center lg:text-left">
<h2 className="text-3xl font-bold tracking-tight">
{isLogin ? 'Giriş Yap' : 'Hesap Oluştur'}
</h2>
<p className="text-muted-foreground">
{isLogin ? 'Rotanızı yönetin ve seyahatinizi planlayın' : 'Kapadokya maceranıza başlayın'}
</p>
</div>
{/* Form */}
<form onSubmit={handleSubmit} className="space-y-6">
{/* Kullanıcı Adı */}
<div className="space-y-2">
<Label htmlFor="username" className="text-sm font-semibold">
Kullanıcı Adı
</Label>
<Input
id="username"
placeholder="kullaniciadi"
required
value={username}
onChange={e => setUsername(e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, ''))}
className="h-11 text-base"
autoComplete="username"
/>
<p className="text-xs text-muted-foreground">
Sadece harf, rakam ve alt çizgi kullanılabilir
</p>
</div>
{/* Şifre */}
<div className="space-y-2">
<div className="flex items-center justify-between">
<Label htmlFor="password" className="text-sm font-semibold">
Şifre
</Label>
{isLogin && (
<button
type="button"
className="text-xs text-primary hover:underline"
onClick={() => toast.info('Şifre sıfırlama özelliği yakında eklenecek')}
>
Şifremi unuttum
</button>
)}
</div>
<div className="relative">
<Input
id="password"
type={showPassword ? 'text' : 'password'}
placeholder="••••••••"
required
value={password}
onChange={e => setPassword(e.target.value)}
className="h-11 text-base pr-10"
autoComplete={isLogin ? 'current-password' : 'new-password'}
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
>
{showPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
</button>
</div>
{!isLogin && password && (
<p className="text-xs text-muted-foreground">
{password.length < 6 ? ' En az 6 karakter gerekli' : ' Şifre uygun'}
</p>
)}
</div>
{/* Beni Hatırla */}
{isLogin && (
<div className="flex items-center space-x-2">
<Checkbox
id="remember"
checked={rememberMe}
onCheckedChange={(checked) => setRememberMe(checked as boolean)}
/>
<Label
htmlFor="remember"
className="text-sm font-normal cursor-pointer"
>
Beni hatırla
</Label>
</div>
)}
{/* Submit Button */}
<Button
type="submit"
className="w-full h-11 text-base font-semibold"
disabled={loading}
>
{loading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
{isLogin ? 'Giriş yapılıyor...' : 'Hesap oluşturuluyor...'}
</>
) : (
isLogin ? 'Giriş Yap' : 'Hesap Oluştur'
)}
</Button>
</form>
{/* Divider */}
<div className="relative">
<div className="absolute inset-0 flex items-center">
<span className="w-full border-t" />
</div>
<div className="relative flex justify-center text-xs uppercase">
<span className="bg-background px-2 text-muted-foreground">veya</span>
</div>
</div>
{/* Toggle Login/Signup */}
<div className="text-center">
<button
type="button"
onClick={() => {
setIsLogin(!isLogin);
setPassword('');
}}
className="text-sm text-muted-foreground hover:text-primary transition-colors"
>
{isLogin ? (
<>
Hesabınız yok mu?{' '}
<span className="font-semibold text-primary">Kayıt ol</span>
</>
) : (
<>
Zaten hesabınız var mı?{' '}
<span className="font-semibold text-primary">Giriş yap</span>
</>
)}
</button>
</div>
</div>
</div>
</div>
);
}