All checks were successful
		
		
	
	PR Build Check / build (pull_request) Successful in 2m20s
				
			
		
			
				
	
	
		
			116 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			116 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| // app/login/page.tsx
 | ||
| 'use client';
 | ||
| 
 | ||
| import Link from 'next/link';
 | ||
| import React, { useEffect, useState } from 'react';
 | ||
| import { useRouter } from 'next/navigation';
 | ||
| import ComponentsAuthLoginForm from '@/components/auth/components-auth-login-form';
 | ||
| 
 | ||
| export default function LoginPage() {
 | ||
|   const router = useRouter();
 | ||
|   const [ready, setReady] = useState(false); // gate to avoid UI flash
 | ||
| 
 | ||
|   // Use ONE client-exposed API env var everywhere
 | ||
|   const API = process.env.NEXT_PUBLIC_FASTAPI_URL || 'http://127.0.0.1:8000';
 | ||
| 
 | ||
|   useEffect(() => {
 | ||
|     let cancelled = false;
 | ||
|     const controller = new AbortController();
 | ||
| 
 | ||
|     (async () => {
 | ||
|       try {
 | ||
|         const res = await fetch(`${API}/auth/me`, {
 | ||
|           credentials: 'include',
 | ||
|           cache: 'no-store',        // don't reuse a cached 401
 | ||
|           signal: controller.signal,
 | ||
|         });
 | ||
| 
 | ||
|         if (!res.ok) {
 | ||
|           if (!cancelled) setReady(true);
 | ||
|           return;
 | ||
|         }
 | ||
| 
 | ||
|         const user = await res.json().catch(() => null);
 | ||
|         if (user?.id) {
 | ||
|           // already logged in -> go straight to dashboard
 | ||
|           router.replace('/adminDashboard');
 | ||
|           return;
 | ||
|         }
 | ||
| 
 | ||
|         // not logged in -> show form
 | ||
|         if (!cancelled) setReady(true);
 | ||
|       } catch {
 | ||
|         // network/error -> show form
 | ||
|         if (!cancelled) setReady(true);
 | ||
|       }
 | ||
|     })();
 | ||
| 
 | ||
|     return () => {
 | ||
|       cancelled = true;
 | ||
|       controller.abort();
 | ||
|     };
 | ||
|   }, [router, API]);
 | ||
| 
 | ||
|   if (!ready) return null; // or a spinner/skeleton
 | ||
| 
 | ||
|   return (
 | ||
|     <div className="relative min-h-screen overflow-hidden bg-[#060818] text-white">
 | ||
|       {/* Background gradient layer */}
 | ||
|       <div className="absolute inset-0 -z-10">
 | ||
|         <img
 | ||
|           src="/assets/images/auth/bg-gradient.png"
 | ||
|           alt="background gradient"
 | ||
|           className="h-full w-full object-cover"
 | ||
|         />
 | ||
|         <div className="absolute inset-0 bg-black/50 backdrop-blur-sm" />
 | ||
|       </div>
 | ||
| 
 | ||
|       {/* Background decorative objects */}
 | ||
|       <img
 | ||
|         src="/assets/images/auth/coming-soon-object1.png"
 | ||
|         alt="left decor"
 | ||
|         className="absolute left-0 top-1/2 hidden h-full max-h-[893px] -translate-y-1/2 brightness-125 md:block"
 | ||
|       />
 | ||
|       <img
 | ||
|         src="/assets/images/auth/coming-soon-object3.png"
 | ||
|         alt="right decor"
 | ||
|         className="absolute right-0 top-0 hidden h-[300px] brightness-125 md:block"
 | ||
|       />
 | ||
| 
 | ||
|       {/* Centered card wrapper */}
 | ||
|       <div className="relative flex min-h-screen items-center justify-center px-6 py-10 sm:px-16">
 | ||
|         <div
 | ||
|           className="relative w-full max-w-[870px] rounded-2xl p-1
 | ||
|                      bg-[linear-gradient(45deg,#fffbe6_0%,rgba(255,251,230,0)_25%,rgba(255,251,230,0)_75%,#fffbe6_100%)]
 | ||
|                      dark:bg-[linear-gradient(52.22deg,#facc15_0%,rgba(250,204,21,0)_20%,rgba(250,204,21,0)_80%,#facc15_100%)]"
 | ||
|         >
 | ||
|           <div className="relative z-10 rounded-2xl bg-white/10 px-8 py-16 backdrop-blur-lg dark:bg-white/10 lg:min-h-[600px]">
 | ||
|             <div className="mx-auto w-full max-w-[440px] text-center">
 | ||
|               <h1 className="text-4xl font-extrabold uppercase tracking-wide text-yellow-400 mb-2">
 | ||
|                 Sign In
 | ||
|               </h1>
 | ||
|               <p className="text-base font-medium text-gray-200 dark:text-gray-300 mb-8">
 | ||
|                 Enter your email and password to access your account.
 | ||
|               </p>
 | ||
| 
 | ||
|               <ComponentsAuthLoginForm />
 | ||
| 
 | ||
|               <div className="mt-6 text-sm text-gray-200 dark:text-gray-300">
 | ||
|                 Don’t have an account?{' '}
 | ||
|                 <Link
 | ||
|                   href="/register"
 | ||
|                   className="text-yellow-400 font-semibold underline transition hover:text-white"
 | ||
|                 >
 | ||
|                   SIGN UP
 | ||
|                 </Link>
 | ||
|               </div>
 | ||
|             </div>
 | ||
|           </div>
 | ||
|         </div>
 | ||
|       </div>
 | ||
|     </div>
 | ||
|   );
 | ||
| }
 | ||
| 
 | ||
| 
 |