doctor-mail/apps/web/src/app/auth/page.tsx

146 lines
6.3 KiB
TypeScript
Raw Normal View History

2025-01-22 23:19:58 +08:00
import React, { useState, useRef, useEffect } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { toast } from "react-hot-toast";
import { AnimatePresence, motion } from "framer-motion";
import { useForm } from "react-hook-form";
import { useAuth } from "@web/src/providers/auth-provider";
import { RegisterForm } from "./register";
import { LoginForm } from "./login";
import { LoginFormInputs, RegisterFormInputs } from "./types";
import { Button } from "@web/src/components/common/element/Button";
const AuthPage: React.FC = () => {
const [showLogin, setShowLogin] = useState(true);
const [isLoading, setIsLoading] = useState(false);
const { login, isAuthenticated, signup } = useAuth();
const location = useLocation();
const navigate = useNavigate();
const loginForm = useForm<LoginFormInputs>({
mode: "onChange"
});
const registerForm = useForm<RegisterFormInputs>({
mode: "onChange"
});
const onSubmitLogin = async (data: LoginFormInputs) => {
try {
setIsLoading(true);
console.log(data)
await login(data.username, data.password);
toast.success("Welcome back!");
} catch (err: any) {
toast.error(err?.response?.data?.message || "Invalid credentials");
} finally {
setIsLoading(false);
}
};
const onSubmitRegister = async (data: RegisterFormInputs) => {
try {
setIsLoading(true);
await signup(data);
toast.success("Registration successful!");
setShowLogin(true);
} catch (err: any) {
toast.error(err?.response?.data?.message);
} finally {
setIsLoading(false);
}
};
useEffect(() => {
if (isAuthenticated) {
const params = new URLSearchParams(location.search);
const redirectUrl = params.get("redirect_url") || "/";
navigate(redirectUrl, { replace: true });
}
}, [isAuthenticated, location]);
return (
<div className="min-h-screen bg-gradient-to-br from-[#1B2735] to-[#090A0F] flex items-center justify-center p-4">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="w-full max-w-5xl bg-[#1C2C41]/90 backdrop-blur-xl rounded-lg shadow-2xl overflow-hidden border border-[#2A4562]"
>
<div className="flex flex-col md:flex-row h-full">
{/* Left Panel */}
<motion.div
className="md:w-1/2 p-8 lg:p-12 text-white relative"
initial={false}
animate={{ x: 0, opacity: 1 }}
transition={{
type: "spring",
stiffness: 100,
damping: 20
}}
>
<motion.div
className="space-y-8"
animate={{ opacity: 1, scale: 1 }}
initial={{ opacity: 0, scale: 0.95 }}
key={showLogin ? "login" : "register"}
transition={{ duration: 0.3 }}
>
{/* Logo Section */}
<div className="relative">
<div className="flex flex-col items-center space-y-4">
<img
src="/usaf-logo.svg"
alt="United States Air Force Logo"
className="w-28 h-28 mx-auto filter drop-shadow-lg"
/>
<div className="absolute inset-0 bg-gradient-to-t from-[#1B2735]/40 to-transparent rounded-full blur-2xl" />
</div>
</div>
{/* Title Section */}
<div className="space-y-4">
<h1 className="text-3xl lg:text-4xl font-bold text-center tracking-tight">
<span className="bg-gradient-to-r from-[#E6E9F0] to-[#B4C3D8] bg-clip-text text-transparent">
USAF Leadership Portal
</span>
</h1>
<p className="text-[#A3B8D3] text-center text-base lg:text-lg font-medium">
{showLogin
? "Access your secure USAF portal"
: "Create your authorized account"}
</p>
</div>
{/* Switch Form Button */}
<Button variant="soft-primary" fullWidth
onClick={() => setShowLogin(!showLogin)}
aria-label={showLogin ? "Switch to registration form" : "Switch to login form"}
>
{showLogin ? "New User Registration" : "Return to Login"}
</Button>
</motion.div>
</motion.div>
{/* Right Panel - Forms */}
<div className="md:w-1/2 bg-[#1C2C41]/30 p-8 lg:p-12 backdrop-blur-sm relative">
<AnimatePresence mode="wait">
{showLogin ? (
<LoginForm
form={loginForm}
onSubmit={onSubmitLogin}
isLoading={isLoading}
/>
) : (
<RegisterForm
form={registerForm}
onSubmit={onSubmitRegister}
isLoading={isLoading}
/>
)}
</AnimatePresence>
</div>
</div>
</motion.div>
</div>
);
};
export default AuthPage;