/** * LoginForm Component * Handles user authentication with email and password * Integrates with backend API and auth store */ 'use client'; import { useState } from 'react'; import Link from 'next/link'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Alert } from '@/components/ui/alert'; import { useLogin } from '@/lib/api/hooks/useAuth'; import { getGeneralError, getFieldErrors, isAPIErrorArray } from '@/lib/api/errors'; import config from '@/config/app.config'; // ============================================================================ // 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(8, 'Password must be at least 8 characters') .regex(/[0-9]/, 'Password must contain at least one number') .regex(/[A-Z]/, 'Password must contain at least one uppercase letter'), }); type LoginFormData = z.infer; // ============================================================================ // Component // ============================================================================ interface LoginFormProps { /** Optional callback after successful login */ onSuccess?: () => void; /** Show registration link */ showRegisterLink?: boolean; /** Show password reset link */ showPasswordResetLink?: boolean; /** Custom className for form container */ className?: string; } /** * LoginForm - User authentication form * * Features: * - Email and password validation * - Loading states * - Server error display * - Links to registration and password reset * * @example * ```tsx * router.push('/dashboard')} * /> * ``` */ export function LoginForm({ onSuccess, showRegisterLink = true, showPasswordResetLink = true, className, }: LoginFormProps) { const [serverError, setServerError] = useState(null); const loginMutation = useLogin(); const form = useForm({ resolver: zodResolver(loginSchema), mode: 'onBlur', reValidateMode: 'onChange', defaultValues: { email: '', password: '', }, }); const onSubmit = async (data: LoginFormData) => { try { // Clear previous errors setServerError(null); form.clearErrors(); // Attempt login await loginMutation.mutateAsync(data); // Success callback onSuccess?.(); } catch (error) { // Handle API errors with type guard if (isAPIErrorArray(error)) { // Set general error message const generalError = getGeneralError(error); if (generalError) { setServerError(generalError); } // Set field-specific errors const fieldErrors = getFieldErrors(error); Object.entries(fieldErrors).forEach(([field, message]) => { if (field === 'email' || field === 'password') { form.setError(field, { message }); } }); } else { // Unexpected error format setServerError('An unexpected error occurred. Please try again.'); } } }; const isSubmitting = form.formState.isSubmitting || loginMutation.isPending; return (
{/* Server Error Alert */} {serverError && (

{serverError}

)} {/* Email Field */}
{form.formState.errors.email && (

{form.formState.errors.email.message}

)}
{/* Password Field */}
{showPasswordResetLink && ( Forgot password? )}
{form.formState.errors.password && (

{form.formState.errors.password.message}

)}
{/* Submit Button */} {/* Registration Link */} {showRegisterLink && config.features.enableRegistration && (

Don't have an account?{' '} Sign up

)}
); }