import { useMemo, useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import axios from "axios"; import Swal from "sweetalert2"; import { Eye, EyeOff, LogIn, Mail, Lock } from "lucide-react"; import { motion } from "framer-motion"; import "../../Styles/authentication/login.css"; import { useSession } from "../context/SessionContext"; import BASE_URL from "@backend/server/config"; import useRoles from "../authentication/useRoles"; import userImage from "../assets/user.png"; import ModernButton from "../components/ui/ModernButton"; import { getBrandContextHeaders, hydrateBrandSelection, } from "../components/utils/axiosInstance"; import VerseOfTheDay from "./VerseOfTheDay"; export default function Login() { const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [passwordVisible, setPasswordVisible] = useState(false); const [loading, setLoading] = useState(false); const navigate = useNavigate(); const { user, setUser } = useSession(); const { roles, loading: rolesLoading } = useRoles(); // Prevent authenticated users from accessing the login page useEffect(() => { if (user?.isLoggedIn && user?.role) { const roleName = String(user.role).toUpperCase(); navigate(roleName === "EMPLOYEE" ? "/employee/dashboard" : "/dashboard", { replace: true }); } }, [user, navigate]); /** * Important: * This prevents this error: * TypeError: (t || []).map is not a function * * Because sometimes backend returns: * { success: true, data: [...] } * * Instead of: * [...] */ const safeRoles = useMemo(() => { if (Array.isArray(roles)) return roles; if (Array.isArray(roles?.data)) return roles.data; if (Array.isArray(roles?.roles)) return roles.roles; if (Array.isArray(roles?.records)) return roles.records; return []; }, [roles]); const getRoleName = (role) => { return String(role?.role_name || role?.name || role?.role || "") .trim() .toUpperCase(); }; const handleLogin = async (e) => { e.preventDefault(); if (rolesLoading || loading) return; setLoading(true); try { const response = await axios.post( `${BASE_URL}/api/login`, { username, password }, { headers: { "Content-Type": "application/json", ...getBrandContextHeaders(), }, withCredentials: true, }, ); if (response.data?.message === "Login successful") { const userRole = String(response.data?.role || "") .trim() .toUpperCase(); const actualFullName = response.data?.full_name || response.data?.username || username; const allowedBrands = Array.isArray(response.data?.allowed_brands) ? response.data.allowed_brands : response.data?.current_brand ? [response.data.current_brand] : []; const currentBrand = response.data?.current_brand || null; const backendSelectedBrandCode = response.data?.selectedBrandCode || currentBrand?.brand_code || ""; const selectedBrandCode = hydrateBrandSelection( allowedBrands, currentBrand, backendSelectedBrandCode, ); const userObject = { user_id: response.data?.user_id || null, username: response.data?.username || username, full_name: response.data?.full_name || actualFullName, role: userRole, status: response.data?.status || "active", allowed_brands: allowedBrands, current_brand: currentBrand, selectedBrandCode, token: response.data?.token || null, isLoggedIn: true, }; setUser(userObject); Swal.fire({ icon: "success", title: "Welcome!", text: `Hello, ${actualFullName}!`, timer: 1500, showConfirmButton: false, }); const employeeRoles = safeRoles .filter((r) => getRoleName(r) === "EMPLOYEE") .map((r) => getRoleName(r)); const adminRoles = safeRoles .filter((r) => getRoleName(r) !== "EMPLOYEE") .map((r) => getRoleName(r)) .filter(Boolean); setTimeout(() => { if (employeeRoles.includes(userRole)) { navigate("/employee/dashboard"); } else if (adminRoles.includes(userRole)) { navigate("/dashboard"); } else { /** * Fallback: * If roles API failed or returned empty, still route common roles properly. */ if (userRole === "EMPLOYEE") { navigate("/employee/dashboard"); } else if (userRole) { navigate("/dashboard"); } else { navigate("/unauthorized"); } } }, 1400); } else { Swal.fire({ icon: "error", title: "Login Failed", text: response.data?.message || "Invalid username or password", }); } } catch (error) { console.error("Login error:", error); Swal.fire({ icon: "warning", title: "Server Issue", text: error?.response?.data?.message || "Hostinger might be under high load. Please check their status page.", footer: `Check Hostinger Status`, }); } finally { setLoading(false); } }; if (rolesLoading) { return (

Loading roles...

); } return (
{/* LEFT PANEL */}
HorizonHR
{/* RIGHT PANEL */}
User

Welcome back

Sign in to continue to Horizon HR

setUsername(e.target.value)} className="w-full pl-10 pr-4 py-2.5 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-sky-400 focus:border-transparent transition" required />
setPassword(e.target.value)} className="w-full pl-10 pr-12 py-2.5 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-sky-400 focus:border-transparent transition" required />
} className="font-semibold" > Sign in
POWERED BY{" "} Central Juan I.T. Solutions
); }