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"}