All files / src/components Login.tsx

84.61% Statements 22/26
87.5% Branches 7/8
100% Functions 4/4
84% Lines 21/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119              143x       143x 143x 143x 143x     118x 118x       5x 5x 5x     5x 5x                 5x     3x 3x         2x   5x       143x             2x                               24x                                         143x                                            
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { useAuth } from "../contexts/AuthContext";
import { apiClient } from "../services/api";
import { validatePassword, validateUsername } from "../utils/validation";
 
export const Login: React.FC = () => {
  const [formData, setFormData] = useState({
    username: "",
    password: "",
  });
  const [errors, setErrors] = useState<string[]>([]);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const navigate = useNavigate();
  const { login } = useAuth();
 
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    setFormData((prev) => ({ ...prev, [name]: value }));
  };
 
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setIsSubmitting(true);
    setErrors([]);
 
    // Validate inputs
    const usernameValidation = validateUsername(formData.username);
    const passwordValidation = validatePassword(formData.password);
 
    if (!usernameValidation.isValid || !passwordValidation.isValid) {
      setErrors([...usernameValidation.errors, ...passwordValidation.errors]);
      setIsSubmitting(false);
      return;
    }
 
    try {
      const response = await apiClient.login(formData);
 
      if (response.data.success) {
        login(response.data.token);
        navigate("/dashboard");
      } else {
        setErrors([response.data.message]);
      }
    } catch (error: any) {
      setErrors([error.response?.data?.message || "Login failed"]);
    } finally {
      setIsSubmitting(false);
    }
  };
 
  return (
    <div className="login-container" data-testid="login-page">
      <h2>Login</h2>
      <form onSubmit={handleSubmit} className="login-form">
        {errors.length > 0 && (
          <div className="error-message" data-testid="login-error">
            {errors.map((error, index) => (
              <div key={index}>{error}</div>
            ))}
          </div>
        )}
 
        <div className="form-group">
          <label htmlFor="username">Username</label>
          <input
            type="text"
            id="username"
            name="username"
            value={formData.username}
            onChange={handleChange}
            data-testid="username-input"
          />
          {validateUsername(formData.username).errors.map((error, index) => (
            <div
              key={index}
              className="field-error"
              data-testid="username-error"
            >
              {error}
            </div>
          ))}
        </div>
 
        <div className="form-group">
          <label htmlFor="password">Password</label>
          <input
            type="password"
            id="password"
            name="password"
            value={formData.password}
            onChange={handleChange}
            data-testid="password-input"
          />
          {validatePassword(formData.password).errors.map((error, index) => (
            <div
              key={index}
              className="field-error"
              data-testid="password-error"
            >
              {error}
            </div>
          ))}
        </div>
 
        <button
          type="submit"
          disabled={isSubmitting}
          className="login-button"
          data-testid="login-button"
        >
          {isSubmitting ? "Logging in..." : "Login"}
        </button>
      </form>
    </div>
  );
};