import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import type { ReactElement } from 'react'; import { Shield } from 'lucide-react'; import { useAppDispatch, useAppSelector } from '@/hooks/redux-hooks'; import { loginAsync, clearError } from '@/store/authSlice'; import { FormField } from '@/components/shared'; import { PrimaryButton } from '@/components/shared'; import type { LoginError } from '@/services/auth-service'; import { showToast } from '@/utils/toast'; // Zod validation schema const loginSchema = z.object({ email: z .string() .min(1, 'Email is required') .email('Please enter a valid email address'), password: z .string() .min(1, 'Password is required') .min(6, 'Password must be at least 6 characters'), }); type LoginFormData = z.infer; const Login = (): ReactElement => { const navigate = useNavigate(); const dispatch = useAppDispatch(); const { isLoading, error, isAuthenticated } = useAppSelector((state) => state.auth); const { register, handleSubmit, setError, formState: { errors }, clearErrors, } = useForm({ resolver: zodResolver(loginSchema), mode: 'onBlur', // Validate on blur for better UX }); const [generalError, setGeneralError] = useState(''); // Redirect if already authenticated useEffect(() => { if (isAuthenticated) { navigate('/dashboard'); } }, [isAuthenticated, navigate]); // Clear errors only on component mount, not on every auth state change useEffect(() => { // Only clear errors on initial mount dispatch(clearError()); setGeneralError(''); clearErrors(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // Empty dependency array - only run on mount const onSubmit = async (data: LoginFormData): Promise => { // Clear previous errors setGeneralError(''); clearErrors(); dispatch(clearError()); try { const result = await dispatch(loginAsync(data)).unwrap(); if (result) { const message = result.message || 'Login successful'; const description = result.message ? undefined : 'Welcome back!'; showToast.success(message, description); // Only navigate on success navigate('/dashboard'); } } catch (error: any) { // Clear Redux error state since we're handling errors locally dispatch(clearError()); // Handle error from unwrap() - error is the rejected value from rejectWithValue const loginError = error as LoginError; if (loginError && typeof loginError === 'object') { // Check for validation errors with details array if ('details' in loginError && Array.isArray(loginError.details)) { // Validation errors from server - set field-specific errors loginError.details.forEach((detail) => { if (detail.path === 'email' || detail.path === 'password') { setError(detail.path as keyof LoginFormData, { type: 'server', message: detail.message, }); } else { // If error is for a field we don't handle, show as general error setGeneralError(detail.message); } }); } else if ('error' in loginError) { // Check if error is an object with message property if (typeof loginError.error === 'object' && loginError.error !== null && 'message' in loginError.error) { // General error from server with object structure setGeneralError(loginError.error.message || 'Login failed'); } else if (typeof loginError.error === 'string') { // Error is a string setGeneralError(loginError.error); } else { setGeneralError('Login failed. Please check your credentials.'); } } else { // Fallback for unknown error structure setGeneralError('An unexpected error occurred. Please try again.'); } } else if (error?.message) { // Network error or other error setGeneralError(error.message); } else { // Complete fallback setGeneralError('Login failed. Please check your credentials and try again.'); } } }; return (
{/* Login Card */}
{/* Logo Section */}
QAssure

Welcome Back 1

Sign in to your account to continue

{/* General Error Message - Prioritize local error over Redux error */} {generalError && (

{generalError}

)} {/* Show Redux error only if no local error and no field errors */} {!generalError && error && !errors.email && !errors.password && (

{error}

)}
{ e.preventDefault(); e.stopPropagation(); handleSubmit(onSubmit)(e); }} className="space-y-4" noValidate > {/* Email Field */} {/* Password Field */} {/* Forgot Password Link */} {/* Submit Button */}
{isLoading ? 'Signing in...' : 'Sign In'}
{/* Footer */}

© 2026 QAssure. All rights reserved.

); }; export default Login;