import { useState, useEffect } from "react"; const API_BASE = import.meta.env.VITE_API_BASE || ""; import { useNavigate, Link, useLocation } from "react-router-dom"; import { aethexUserService } from "@/lib/aethex-database-adapter"; import { useAuth } from "@/contexts/AuthContext"; import { useDiscordActivity } from "@/contexts/DiscordActivityContext"; import { useAethexToast } from "@/hooks/use-aethex-toast"; import { initiateFoundationLogin } from "@/lib/foundation-oauth"; import Layout from "@/components/Layout"; import SEO from "@/components/SEO"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import LoadingScreen from "@/components/LoadingScreen"; import { LogIn, ArrowRight, Shield, Sparkles, Github, Mail, Lock, User, Info, Wallet, } from "lucide-react"; const DiscordIcon = () => ( ); import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose, } from "@/components/ui/dialog"; export default function Login() { const [isLoading, setIsLoading] = useState(false); const [isSignUp, setIsSignUp] = useState(false); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [fullName, setFullName] = useState(""); const [manualVerificationLink, setManualVerificationLink] = useState< string | null >(null); const [showReset, setShowReset] = useState(false); const [resetEmail, setResetEmail] = useState(""); const [errorFromUrl, setErrorFromUrl] = useState(null); const [discordLinkedEmail, setDiscordLinkedEmail] = useState( null, ); const navigate = useNavigate(); const location = useLocation(); const { signIn, signUp, signInWithOAuth, user, profile, loading, profileComplete, requestPasswordReset, } = useAuth(); const { info: toastInfo, error: toastError } = useAethexToast(); const { isActivity } = useDiscordActivity(); // Check for error messages and success messages from URL query parameters (e.g., from OAuth callbacks) useEffect(() => { const params = new URLSearchParams(location.search); const errorType = params.get("error"); const errorMessage = params.get("message"); const discordLinked = params.get("discord_linked"); const discordEmail = params.get("email"); // Handle Discord linking success if (discordLinked === "true" && discordEmail) { setDiscordLinkedEmail(decodeURIComponent(discordEmail)); toastInfo({ title: "Discord Linked!", description: `Discord account linked to ${decodeURIComponent(discordEmail)}. Please sign in to continue.`, }); } if (errorType && errorMessage) { setErrorFromUrl(decodeURIComponent(errorMessage)); // Show in toast as well if (errorType === "account_exists") { toastError({ title: "Account Already Exists", description: errorMessage, }); } else if (errorType === "auth_create") { toastError({ title: "Authentication Error", description: errorMessage, }); } else if (errorType === "discord_no_match") { toastError({ title: "Discord Email Not Found", description: decodeURIComponent(errorMessage) || "Your Discord email doesn't match any existing AeThex account. Please sign in with your email first.", }); } } }, [location.search, toastError, toastInfo]); // After auth resolves and a user exists, navigate to next path or dashboard useEffect(() => { if (!loading && user) { const params = new URLSearchParams(location.search); const next = params.get("next"); // Check if there's an OAuth redirect destination stored (e.g., from staff login) const oauthRedirect = sessionStorage.getItem("oauth_redirect_to"); // New logic: if profile exists (even if incomplete), go to Dashboard // Otherwise send to Onboarding for new users const profileExists = profile !== null; const redirectDest = (next && next.startsWith("/") ? next : null) || oauthRedirect || (profileExists ? "/dashboard" : "/onboarding"); // Clear the stored redirect after using it if (oauthRedirect) { sessionStorage.removeItem("oauth_redirect_to"); } navigate(redirectDest, { replace: true, }); } }, [user, profile, loading, navigate, location.search]); // Pre-fill email if Discord was just linked useEffect(() => { if (discordLinkedEmail) { setEmail(discordLinkedEmail); } }, [discordLinkedEmail]); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setIsLoading(true); try { if (isSignUp) { const result = await signUp(email, password, { data: { full_name: fullName, }, }); if (result?.user) { toastInfo({ title: "Account created", description: result?.identities?.length === 0 ? "Please verify your email to log in" : "Redirecting to onboarding...", }); await aethexUserService.ensureUserProfile(result.user); navigate("/onboarding", { replace: true }); } } else { // Sign in with email/password const result = await signIn(email, password); if (result?.user) { // Don't navigate immediately - let Auth context update and the useEffect below handle redirect // This ensures profile data is fetched and profileComplete is properly calculated toastInfo({ title: "Signing you in", description: "Redirecting...", }); } } } catch (error: any) { console.error("Auth error:", error); const message = error?.message || (isSignUp ? "Failed to create account" : "Failed to sign in"); toastError({ title: isSignUp ? "Signup failed" : "Login failed", description: message, }); } finally { setIsLoading(false); } }; const handleSocialLogin = async (provider: string) => { try { await signInWithOAuth(provider); } catch (error) { console.error("OAuth error:", error); } }; const handleWeb3Login = async () => { try { const nonce = await fetch(`${API_BASE}/api/web3/nonce`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ address: "", }), }) .then((r) => (r.ok ? r.json() : null)) .catch(() => null); if (!nonce?.nonce) { toastError({ title: "Web3 login unavailable", description: "Please try again later", }); return; } const message = `Sign this message to verify your Ethereum wallet:\n\nNonce: ${nonce.nonce}`; const address = (window as any).ethereum?.selectedAddress; if (!address || !(window as any).ethereum) { toastError({ title: "Wallet not connected", description: "Please install MetaMask or another Ethereum wallet extension", }); return; } const signature = await (window as any).ethereum.request({ method: "personal_sign", params: [message, address], }); const result = await fetch(`${API_BASE}/api/web3/verify`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ address, nonce: nonce.nonce, signature, redirectTo: window.location.origin + (profile ? "/dashboard" : "/onboarding"), }), }) .then((r) => (r.ok ? r.json() : null)) .catch(() => null); if (result?.url) { window.location.href = result.url; } } catch (error: any) { console.error("Web3 error:", error); toastError({ title: "Web3 verification failed", description: error?.message || "Could not verify your wallet signature", }); } }; if (loading) { return ; } return ( <>
{/* Floating particles effect */}
{[...Array(20)].map((_, i) => (
))}
{isSignUp ? "Create Account" : "Welcome Back"} {isSignUp ? "Join AeThex and unlock your creative potential" : "Access your dashboard and continue your journey"}
Secure Login End-to-End Encrypted
{errorFromUrl ? ( Error {errorFromUrl} ) : null} {manualVerificationLink ? ( Manual verification required

We couldn't send the verification email automatically. Use the link below to confirm your account:

{manualVerificationLink}

) : null} {/* Social Login Buttons */}

Quick Sign In

Connect with Foundation

Other Options

{/* Divider */}
Or continue with email
{/* Email/Password Form */}
{isSignUp && (
setFullName(e.target.value)} placeholder="Enter your full name" className="pl-10 bg-background/50 border-border/50 focus:border-aethex-400" required={isSignUp} />
)}
setEmail(e.target.value)} placeholder="Enter your email" className="pl-10 bg-background/50 border-border/50 focus:border-aethex-400" required />
setPassword(e.target.value)} placeholder={ isSignUp ? "Create a password" : "Enter your password" } className="pl-10 bg-background/50 border-border/50 focus:border-aethex-400" required minLength={isSignUp ? 6 : undefined} />
{isSignUp && (

Password must be at least 6 characters long

)}
{!isSignUp && (
)}

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

{/* Security Notice */}

🔒 Your data is protected with enterprise-grade security

); }