Employee Validation

Sort by

recency

|

63 Discussions

|

  • + 1 comment

    Adjusted the time to pass test as the date is old.

    import React, { useState } from "react";
    
    function EmployeeValidationForm() {
      //Here I wanted to keep all the value and if an error as a boolean to render easier and more accessible
      const initState = {
        name: { value: "", isValid: false },
        email: { value: "", isValid: false },
        employeeId: { value: "", isValid: false },
        joiningDate: { value: "", isValid: false }
      }
      const [formFields, setFormFields] = useState(initState);
    
      //All the errors 
      const isShort = (input) => input.trim().length < 4 ;
      const isAlpha = (input) => (/^[A-Za-z\s]+$/).test(input);
      const isEmail = (input) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input) ? true : false;
      const isSixDigits = (input) => /^[0-9]{6}$/.test(input) ? true : false;
      const isFutureDate = (input) => new Date(input) <= new Date("2025-01-01") ? true : false;
    
      const validateField = (name, value) => {
        switch (name) {
          case "name":
            return !isShort(value) && isAlpha(value);
          case "email":
            return isEmail(value);
          case "employeeId":
            return isSixDigits(value)
          case "joiningDate":
            return isFutureDate(value)
          default:
            return false
        }
      };
    
      const handleNameInput = (e) => {
        const { name, value } = e.target;
        const isValid = validateField(name, value);
        setFormFields((prev) => ({ ...prev, [name]: { value, isValid } }));
      }
    
      //Check that fields are not empty and that isValid is true
      const isFormValid = Object.values(formFields).every((field) => field.value.trim() !== "" && field.isValid);
    
      const handleSubmit = () => {
        setFormFields(initState)
      }
    
      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"
              placeholder="Name"
              value={formFields.name.value}
              onChange={handleNameInput}
            />
            {!formFields.name.isValid &&
              <p className="error mt-2">
                Name must be at least 4 characters long and only contain letters and spaces
              </p>
            }
          </div>
          <div className="layout-column align-items-start mb-10 w-50" data-testid="input-email">
            <input
              className="w-100"
              type="email"
              name="email"
              value={formFields.email.value}
              placeholder="Email"
              onChange={handleNameInput}
            />
            {!formFields.email.isValid &&
              <p className="error mt-2">Email must be a valid email address</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={formFields.employeeId.value}
              placeholder="Employee ID"
              onChange={handleNameInput}
            />
            {!formFields.employeeId.isValid &&
              <p className="error mt-2">Employee ID must be exactly 6 digits</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={formFields.joiningDate.value}
              placeholder="Joining Date"
              onChange={handleNameInput}
            />
            {!formFields.joiningDate.isValid &&
              <p className="error mt-2">Joining Date cannot be in the future</p>
            }
          </div>
          <button data-testid="submit-btn" type="submit" disabled={!isFormValid} onClick={handleSubmit}>
            Submit
          </button>
        </div>
      );
    }
    
    export default EmployeeValidationForm;
    
  • + 0 comments

    I don't know why people are using useEffect or useReduce, but my following code with only useState is working:

    Note: the day of today in the problem is 12/31/2024 instead of the actual date of today.

    import React, {useState} from "react";
    function EmployeeValidationForm() {
      const [username, setUsername] = useState("");
      const [email, setEmail] = useState("");
      const [employeId, setEmployeeId] = useState("");
      const [joinDate, setJoinDate] = useState("");
      const [validator, setValidator] = useState({
        username:false,
        email:false,
        employeId:false,
        joinDate: false
      })
    
      const handleUserNameChange = (e)=>{
        setUsername(e.target.value);
        const regex = /^[A-Za-z\s]{4,}$/
        if(e!=null){
          setValidator((prev)=>({
            ...prev, username: regex.test(e.target.value)
          }))
        }
        else{
          setValidator((prev)=>({
            ...prev, username:false
          }))
        }
      }
    
      const handleEmailChange = (e)=>{
        setEmail(e.target.value);
        const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
        if(e!=null){
          setValidator((prev)=>({
            ...prev, email: regex.test(e.target.value)
          }))
        }
        else{
          setValidator((prev)=>({
            ...prev, email:false
          }))
        }
      }
    
      const handleEmployeeIdChange = (e)=>{
        setEmployeeId(e.target.value);
        const regex = /^\d{6}$/
        if(e!=null){
          setValidator((prev)=>({
            ...prev, employeId: regex.test(e.target.value)
          }))
        }
        else{
          setValidator((prev)=>({
            ...prev, employeId:false
          }))
        }
      }
    
      const handleJoinDateChange = (e)=>{
        setJoinDate(e.target.value);
        if(e!=null){
          const selectedDate = new Date(e.target.value);
          const today = new Date("12/31/2024");
          if(selectedDate>today){
            setValidator((prev)=>({
              ...prev, joinDate: false
            }))
          }
          else{
            setValidator((prev)=>({
              ...prev, joinDate: true
            }))
          }
        }
        else{
          setValidator((prev)=>({
            ...prev, joinDate:false
          }))
        }
      }
    
      const handleSubmit = (e)=>{
        e.preventDefault();
        if(validator.username && validator.email && validator.employeId && validator.joinDate){
          setValidator({
            username:false,email: false, employeId: false, joinDate: false
          })
          setUsername("")
          setEmail("")
          setJoinDate("")
          setEmployeeId("")
        }
      }
    
      return (
        <form onSubmit={handleSubmit}>
        <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={username}
              placeholder="Name"
              data-testid="input-name-test"
              onChange = {handleUserNameChange}
            />
            {!validator.username && <p className="error mt-2">
              Name must be at least 4 characters long and only contain letters and spaces
            </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={email}
              placeholder="Email"
              onChange = {handleEmailChange}
            />
            {!validator.email && <p className="error mt-2">Email must be a valid email address</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={employeId}
              placeholder="Employee ID"
              onChange = {handleEmployeeIdChange}
            />
            {!validator.employeId && <p className="error mt-2">Employee ID must be exactly 6 digits</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={joinDate}
              placeholder="Joining Date"
              onChange = {handleJoinDateChange}
            />
            {!validator.joinDate && <p className="error mt-2">Joining Date cannot be in the future</p>}
          </div>
          <button data-testid="submit-btn" type="submit" disabled = {!(validator.username && validator.email && validator.joinDate && validator.employeId)}>
            Submit
          </button>
        </div>
        </form>
      );
    }
    
    export default EmployeeValidationForm;
    
  • + 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;