import React, { useState, useCallback } from 'react'; import { useAuthStore } from '../store/authStore'; import { Loader2, User, Mail, Lock, AlertCircle, CheckCircle, XCircle } from 'lucide-react'; const API_BASE = ''; interface AuthPageProps { onSuccess?: () => void; } const AuthPage: React.FC = ({ onSuccess }) => { const [isLogin, setIsLogin] = useState(true); const [username, setUsername] = useState(''); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); const [localError, setLocalError] = useState(''); // Real-time availability checks const [usernameStatus, setUsernameStatus] = useState<'idle' | 'checking' | 'available' | 'taken'>('idle'); const [emailStatus, setEmailStatus] = useState<'idle' | 'checking' | 'available' | 'taken'>('idle'); const { login, register, isLoading, error, clearError } = useAuthStore(); // Check username availability const checkUsername = useCallback(async (value: string) => { if (!value.trim() || value.length < 2) { setUsernameStatus('idle'); return; } setUsernameStatus('checking'); try { const res = await fetch(`${API_BASE}/api/auth/check-username/${encodeURIComponent(value)}`); const data = await res.json(); setUsernameStatus(data.available ? 'available' : 'taken'); } catch { setUsernameStatus('idle'); } }, []); // Check email availability const checkEmail = useCallback(async (value: string) => { if (!value.trim() || !value.includes('@')) { setEmailStatus('idle'); return; } setEmailStatus('checking'); try { const res = await fetch(`${API_BASE}/api/auth/check-email/${encodeURIComponent(value)}`); const data = await res.json(); setEmailStatus(data.available ? 'available' : 'taken'); } catch { setEmailStatus('idle'); } }, []); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setLocalError(''); clearError(); // Validation if (!username.trim()) { setLocalError('Username is required'); return; } if (!password) { setLocalError('Password is required'); return; } if (!isLogin) { if (!email.trim()) { setLocalError('Email is required'); return; } if (password !== confirmPassword) { setLocalError('Passwords do not match'); return; } if (password.length < 6) { setLocalError('Password must be at least 6 characters'); return; } if (usernameStatus === 'taken') { setLocalError('Username is already taken'); return; } if (emailStatus === 'taken') { setLocalError('Email is already registered'); return; } } try { if (isLogin) { await login(username, password); onSuccess?.(); } else { await register(username, email, password); // Auto-login after successful registration await login(username, password); onSuccess?.(); } } catch (err) { // Error is handled by the store } }; const switchMode = () => { setIsLogin(!isLogin); setLocalError(''); clearError(); setPassword(''); setConfirmPassword(''); setUsernameStatus('idle'); setEmailStatus('idle'); }; const displayError = localError || error; return (
{/* Background pattern */}
{/* Logo/Brand */}

ContextFlow

{isLogin ? 'Welcome back!' : 'Create your account'}

{/* Card */}
{/* Error Message */} {displayError && (

{displayError}

)}
{/* Username */}
{ setUsername(e.target.value); if (!isLogin) setUsernameStatus('idle'); }} onBlur={() => !isLogin && checkUsername(username)} placeholder="Enter your username" className={`w-full pl-10 pr-10 py-3 bg-gray-900/50 border rounded-lg text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all ${ !isLogin && usernameStatus === 'taken' ? 'border-red-500' : !isLogin && usernameStatus === 'available' ? 'border-green-500' : 'border-gray-700' }`} autoComplete="username" /> {!isLogin && usernameStatus !== 'idle' && (
{usernameStatus === 'checking' && } {usernameStatus === 'available' && } {usernameStatus === 'taken' && }
)}
{!isLogin && usernameStatus === 'taken' && (

This username is already taken

)}
{/* Email (only for register) */} {!isLogin && (
{ setEmail(e.target.value); setEmailStatus('idle'); }} onBlur={() => checkEmail(email)} placeholder="Enter your email" className={`w-full pl-10 pr-10 py-3 bg-gray-900/50 border rounded-lg text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all ${ emailStatus === 'taken' ? 'border-red-500' : emailStatus === 'available' ? 'border-green-500' : 'border-gray-700' }`} autoComplete="email" /> {emailStatus !== 'idle' && (
{emailStatus === 'checking' && } {emailStatus === 'available' && } {emailStatus === 'taken' && }
)}
{emailStatus === 'taken' && (

This email is already registered

)}
)} {/* Password */}
setPassword(e.target.value)} placeholder="Enter your password" className="w-full pl-10 pr-4 py-3 bg-gray-900/50 border border-gray-700 rounded-lg text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all" autoComplete={isLogin ? "current-password" : "new-password"} />
{/* Confirm Password (only for register) */} {!isLogin && (
setConfirmPassword(e.target.value)} placeholder="Confirm your password" className="w-full pl-10 pr-4 py-3 bg-gray-900/50 border border-gray-700 rounded-lg text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all" autoComplete="new-password" />
)} {/* Submit Button */}
{/* Switch Mode */}

{isLogin ? "Don't have an account? " : "Already have an account? "}

{/* Footer */}

Visual LLM Conversation Graph Editor

); }; export default AuthPage;