Employee Validation

Sort by

recency

|

61 Discussions

|

  • + 0 comments

    A much simpler implementation without useEffect. This is using useReducer which is much preferred in cases like creating forms.

    import React from "react";
    
    const ACTIONS = {
      UPDATE_FIELD: 'updateField',
      RESET_FORM: 'resetForm',
    }
    
    const FORM_FIELDS = {
      USERNAME: 'username',
      EMAIL: 'email',
      EMPLOYEE_ID: 'employeeId',
      JOINED_DATE: 'joinedDate',
    }
    
    const initialArgs = {
      username: '',
      email: '',
      employeeId: '',
      joinedDate: '',
      errors: {
        username: 'initial',
        email: 'initial',
        employeeId: 'initial',
        joinedDate: 'initial',
      },
    }
    
    // getting current year
    const getCurrentDate = () => {
      const date = new Date()
    
      return date.getFullYear()
    }
    
    const validateInput = (formField, value) => {
      switch(formField) {
        case FORM_FIELDS.USERNAME: {
          const alphabetSpacesRegex = /^[A-Za-z\s]*$/
          if (alphabetSpacesRegex.test(value) && value.length > 3) {
            return ''
          } else {
            return 'Name must be at least 4 characters long and only contain letters and spaces.'
          }
        }
        case FORM_FIELDS.EMAIL: {
          const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
    
          if (emailRegex.test(value)) {
            return ''
          } else {
            return 'Email must be a valid email address'
          }
        }
        case FORM_FIELDS.EMPLOYEE_ID: {
          if (typeof value === "number" && `${value}`.length === 6) {
            return ''
          } else {
            return 'Employee ID must be exactly 6 digits.'
          }
        }
        case FORM_FIELDS.JOINED_DATE: {
          const currentYear = getCurrentDate()
          const [yearValue, _m, _d] = value.split("-")
    
          if (parseInt(yearValue) < parseInt(currentYear, 10)) {
            return ''
          } else {
            return 'Joining Date cannot be in the future'
          }
          
        }
    
        default: {
          return ''
        }
      }
    }
    
    const reducer = (state, action) => {
      try {
        if (!Object.hasOwn(action, 'type')) {
          throw Error('"type" not found');
        }
    
        switch(action.type) {
          case ACTIONS.UPDATE_FIELD: {
            // Expecting action to have field and value prop
            if (!Object.hasOwn(action, 'field')) {
              throw Error('"field" is required to update a form field')
            }
    
            const error = validateInput(action.field, action.value)
    
            return {
              ...state,
              [action.field]: action?.value || "",
              errors: {
                ...state.errors,
                [action.field]: error
              },
              formStates: {
                ...state.formStates,
                isDirty: true
              }
            }
          }
    
          case ACTIONS.RESET_FORM: {
            return initialArgs
          }
    
          default: {
            throw Error('Unknown action.');
          }
        }
      } catch(e) {
        console.log(`ERROR: ${e}`)
        return state
      }
      
    }
    
    const isAllInputValid = (state) => {
      try {
        const inputFieldsErrors = Object.values(state.errors)
    
        return inputFieldsErrors.every(value => !value)
      } catch(e) {
        console.log("Validation: Type ERROR")
      }
      
    }
    
    
    function EmployeeValidationForm() {
      const [employeeForm, dispatch] = React.useReducer(reducer, initialArgs)
      const isFormValid = isAllInputValid(employeeForm)
    
      const updateInput = (formField, event, transformInput) => {
        let inputValue = event.target.value
        if (transformInput) {
          inputValue = transformInput(inputValue)
        }
        dispatch({type: ACTIONS.UPDATE_FIELD, field: formField, value: inputValue})
      }
    
      return (
        <div className="layout-column align-items-center mt-20 ">
          <div className="layout-column align-items-start mb-10 w-50" data-testid="input-name">
            <input
              className="w-100"
              type="text"
              name="name"
              value={employeeForm.username}
              onChange={(e) => updateInput(FORM_FIELDS.USERNAME, e)}
              placeholder="Name"
              data-testid="input-name-test"
            />
            {
              employeeForm.errors.username ? <p className="error mt-2">
                Name must be at least 4 characters long and only contain letters and spaces
              </p> : null
            }
    
          </div>
          <div className="layout-column align-items-start mb-10 w-50" data-testid="input-email">
            <input
              className="w-100"
              type="text"
              name="email"
              value={employeeForm.email}
              onChange={(e) => updateInput(FORM_FIELDS.EMAIL, e)}
              placeholder="Email"
            />
            {employeeForm.errors.email ? <p className="error mt-2">Email must be a valid email address</p> : null}
            
          </div>
          <div className="layout-column align-items-start mb-10 w-50" data-testid="input-employee-id">
            <input
              className="w-100"
              type="text"
              name="employeeId"
              value={employeeForm.employeeId}
              onChange={(e) => updateInput(FORM_FIELDS.EMPLOYEE_ID, e, (v) => parseInt(v, 10))}
              placeholder="Employee ID"
            />
            {employeeForm.errors.employeeId ? <p className="error mt-2">Employee ID must be exactly 6 digits</p> : null}
          
          </div>
          <div className="layout-column align-items-start mb-10 w-50" data-testid="input-joining-date">
            <input
              className="w-100"
              type="date"
              name="joiningDate"
              value={employeeForm.joinedDate}
              onChange={(e) => updateInput(FORM_FIELDS.JOINED_DATE, e)}
              placeholder="Joining Date"
            />
            {
              employeeForm.errors.joinedDate ? <p className="error mt-2">Joining Date cannot be in the future</p> : null
            }
          </div>
          <button data-testid="submit-btn" type="button" onClick={() => dispatch({type: ACTIONS.RESET_FORM})} disabled={!isFormValid}>
            Submit
          </button>
        </div>
      );
    }
    
    export default EmployeeValidationForm;
    
  • + 1 comment

    test data should be updated, since it is using old joining date value to check future date or not.

    Thanks

  • + 1 comment

    import React,{useEffect, useState} from "react";

    function EmployeeValidationForm() { const [user, setUser] = useState({name:"",email:"",employeeId:"",joiningDate:""}); const [error, setError] = useState({name:"",email:"",employeeId:"",joiningDate:""}); const [isFormValid, setIsFormValid] = useState(true);

    useEffect(()=>{ if(validation()){ setIsFormValid(false); } },[user]);

    const validation =()=>{ let isValid=true; let newError = {name:"",email:"",employeeId:"",joiningDate:""};

    if(!user.name.trim() || user.name.trim().length < 4){ newError.name="Name must be at least 4 characters long and only contain letters and spaces"; isValid=false; } const emailRegex = /^[^\s@]+@[^\s@]+.[^\s@]+Undefined control sequence \d/; if(!empIdRegex.test(user.employeeId)){ newError.employeeId = "Employee ID must be exactly 6 digits" isValid=false; } if(!user.joiningDate.trim() || user.joiningDate > "2024-12-31"){ newError.joiningDate = "Joining Date cannot be in the future" isValid=false; } setError(newError); return isValid; }

    const handleChange=(e)=>{ e.preventDefault(); const {name, value}=e.target; setUser((prev)=>({ ...prev, }));

    };

    const handleSubmit =()=>{ if(validation()){ setUser({name:"",email:"",employeeId:"",joiningDate:""}); setError({name:"",email:"",employeeId:"",joiningDate:""}); setIsFormValid(false); }else{ console.log("Validation Failed."); } }; return ( {error.name && {error.name}

    } {error.email && {error.email}

    } {error.employeeId && {error.employeeId}

    } {error.joiningDate && {error.joiningDate}

    } Submit ); }

    export default EmployeeValidationForm;

  • + 0 comments

    There are some error in the test cases for date. Until somebody from HackerRank fix it use the below code for your purpose.

    All test cases passed ✅.

    import React,{useEffect, useState} from "react";
    
    function EmployeeValidationForm() {
    const [user, setUser] = useState({name:"",email:"",employeeId:"",joiningDate:""});
    const [error, setError] = useState({name:"",email:"",employeeId:"",joiningDate:""});
    const [isFormValid, setIsFormValid] = useState(true);
    
    useEffect(()=>{
    if(validation()){
      setIsFormValid(false);
    }
    },[user]);
    
    const validation =()=>{
      let isValid=true;
      let newError = {name:"",email:"",employeeId:"",joiningDate:""};
    
      if(!user.name.trim() || user.name.trim().length < 4){
        newError.name="Name must be at least 4 characters long and only contain letters and spaces";
        isValid=false;
      }
      const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
      if(!user.email.trim() || !emailRegex.test(user.email)){
        newError.email = "Email must be a valid email address";
        isValid=false;
      }
      const empIdRegex = /^\d{6}$/;
      if(!empIdRegex.test(user.employeeId)){
        newError.employeeId = "Employee ID must be exactly 6 digits"
        isValid=false;
      }
      if(!user.joiningDate.trim() || user.joiningDate > "2024-12-31"){
       newError.joiningDate = "Joining Date cannot be in the future"
       isValid=false;
      }
      setError(newError);
      return isValid;
    }
    
    const handleChange=(e)=>{
      e.preventDefault();
      const {name, value}=e.target;
    setUser((prev)=>({
      ...prev,
      [name]:value
    }));
    
    };
    
    const handleSubmit =()=>{
      if(validation()){
        setUser({name:"",email:"",employeeId:"",joiningDate:""});
        setError({name:"",email:"",employeeId:"",joiningDate:""});
        setIsFormValid(false);
      }else{
       console.log("Validation Failed.");
      }
    };
      return (
        <div className="layout-column align-items-center mt-20 ">
          <div className="layout-column align-items-start mb-10 w-50" data-testid="input-name">
            <input
              className="w-100"
              type="text"
              name="name"
              value={user.name}
              placeholder="Name"
              data-testid="input-name-test"
              onChange={handleChange}
            />
            {error.name && 
            <p className="error mt-2">
              {error.name}
            </p>}
          </div>
          <div className="layout-column align-items-start mb-10 w-50" data-testid="input-email">
            <input
              className="w-100"
              type="text"
              name="email"
              value={user.email}
              placeholder="Email"
              onChange={handleChange}
            />
            {error.email &&
            <p className="error mt-2">{error.email}</p>
            }
          </div>
          <div className="layout-column align-items-start mb-10 w-50" data-testid="input-employee-id">
            <input
              className="w-100"
              type="text"
              name="employeeId"
              value={user.employeeId}
              placeholder="Employee ID"
              onChange={handleChange}
            />
            {error.employeeId &&
            <p className="error mt-2">{error.employeeId}</p>
            }
          </div>
          <div className="layout-column align-items-start mb-10 w-50" data-testid="input-joining-date">
            <input
              className="w-100"
              type="date"
              name="joiningDate"
              value={user.joiningDate}
              placeholder="Joining Date"
              onChange={handleChange}
            />
            {error.joiningDate &&
            <p className="error mt-2">{error.joiningDate}</p>
            }
          </div>
          <button data-testid="submit-btn" type="submit" onClick={handleSubmit} disabled={isFormValid}>
            Submit
          </button>
        </div>
      );
    }
    
    export default EmployeeValidationForm;
    
  • + 2 comments

    The test case is failing because it hardcodes a fixed date ("2025-04-12"). This is not a best practice.

    describe("Input fields functionality", () => {
      it("should display no error for name input field's if criteria is met", () => {
        changeInputFields("UserA", "user-email.com", 123, "2025-04-12");
        expect(inputName.children).toHaveLength(1);
        expect(inputEmail.children).toHaveLength(2);
        expect(inputEmployeeId.children).toHaveLength(2);
        expect(inputJoiningDate.children).toHaveLength(2);
        expect(inputEmail.children[1]).toHaveTextContent("Email must be a valid email address");
        expect(inputEmployeeId.children[1]).toHaveTextContent("Employee ID must be exactly 6 digits");
        expect(inputJoiningDate.children[1]).toHaveTextContent("Joining Date cannot be in the future");
      });
    
      it("should display no error for email input field's if criteria is met", () => {
        changeInputFields("UserA", "user@email.com", 123, "2025-04-12");
        expect(inputName.children).toHaveLength(1);
        expect(inputEmail.children).toHaveLength(1);
        expect(inputEmployeeId.children).toHaveLength(2);
        expect(inputJoiningDate.children).toHaveLength(2);
        expect(inputEmployeeId.children[1]).toHaveTextContent("Employee ID must be exactly 6 digits");
        expect(inputJoiningDate.children[1]).toHaveTextContent("Joining Date cannot be in the future");
      });
    
      it("should display no error for employee ID input field's if criteria is met", () => {
        changeInputFields("Use", "user@email.com", 123456, "2025-04-12");
        expect(inputName.children).toHaveLength(2);
        expect(inputEmail.children).toHaveLength(1);
        expect(inputEmployeeId.children).toHaveLength(1);
        expect(inputJoiningDate.children).toHaveLength(2);
        expect(inputName.children[1]).toHaveTextContent(
          "Name must be at least 4 characters long and only contain letters and spaces"
        );
    		});
        expect(inputJoiningDate.children[1]).toHaveTextContent("Joining Date cannot be in the future");
      });