Thursday, April 17, 2025

ReactTS: Employee Management System: ADD EMPLOYEE with VALIDATION

What are Hooks in React with TypeScript?

Hooks are functions that let you "hook into" React state and lifecycle features from function components. In TypeScript, hooks are strongly typed to provide better developer experience and type safety.


Core React Hooks:

  1. useState - Manages component state

  2. useEffect - Handles side effects

  3. useContext - Accesses context values

  4. useReducer - Manages complex state logic

  5. useCallback - Memoizes functions

  6. useMemo - Memoizes values

  7. useRef - Creates mutable references

  8. useLayoutEffect - Similar to useEffect but fires synchronously after DOM mutations


Why Use Hooks in React with TypeScript?

1. Type Safety

TypeScript adds static typing to hooks, catching errors at compile time:

2. Better Organization

Hooks allow you to organize logic by concern rather than lifecycle:

3. Reusable Logic

Custom hooks encapsulate and share logic across components:


AddEmployee.tsx component 

Imports Section




import React, { useState, useEffect, ChangeEvent, FormEvent } from "react";
// React core imports including hooks and event types

import axios from "axios";
// HTTP client for making API requests

import { Form, Button, Container, Alert } from "react-bootstrap";
// Bootstrap components for UI

import { useNavigate, Link } from "react-router-dom";
// Routing utilities for navigation

import Header from "../components/Header";
// Custom header component

import { Employee } from "../models/Employee";
import { Department } from "../models/Department";
// Type definitions for Employee and Department


Interface Definition


interface ValidationErrors {
    [key: string]: string;
}
// Defines a type for validation errors where keys are strings and values are error messages


Component Definition




const AddEmployee: React.FC = () => {
    // Main component definition as a Function Component


State Management



    
const [employee, setEmployee] = useState<Employee>({
        empId: 0,
        empName: "",
        designation: "",
        dateOfJoining: "",
        salary: 0,
        empPhoneNumber: "",
        isActive: true,
        deptId: 0
    });
    // State for employee form data, initialized with default values

    const [departments, setDepartments] = useState<Department[]>([]);
    // State for storing department list fetched from API

    const [error, setError] = useState<string>("");
    // State for general error messages

    const [validationErrors, setValidationErrors] = useState<ValidationErrors>({});
    // State for form validation errors

    const navigate = useNavigate();
    // Hook for programmatic navigation


API Configuration



   
   const EMPLOYEE_API_URL = "http://localhost:9090/api/employees";
    const DEPARTMENT_API_URL = "http://localhost:9090/api/departments";
    // API endpoint URLs


Effect Hook for Data Fetching



    
 useEffect(() => {
        const fetchDepartments = async () => {
            try {
                const response = await axios.get<Department[]>(DEPARTMENT_API_URL);
                setDepartments(response.data);
            } catch (error) {
                console.error("Error fetching departments:", error);
                setError("Failed to load departments.");
            }
        };

        fetchDepartments();
    }, []);
    // Fetches departments on component mount and stores them in state


Form Validation



    
       const validateForm = (): boolean => {
        const errors: ValidationErrors = {};

        if (!employee.empName.trim()) errors.empName = "Name is required.";
        if (!employee.designation.trim()) errors.designation = "Designation is required.";
        if (!employee.dateOfJoining) errors.dateOfJoining = "Date of Joining is required.";
        if (employee.salary <= 0) errors.salary = "Salary must be greater than 0.";
        if (!employee.empPhoneNumber.trim()) {
            errors.empPhoneNumber = "Phone Number is required.";
        } else if (!/^\d{10}$/.test(employee.empPhoneNumber)) {
            errors.empPhoneNumber = "Phone Number must be 10 digits.";
        }
        if (!employee.deptId) errors.deptId = "Department is required.";

        setValidationErrors(errors);
        return Object.keys(errors).length === 0;
    };
    // Validates form fields and returns true if all validations pass


Form Submission Handler



 
   const handleSubmit = async (e: FormEvent) => {
        e.preventDefault();
        if (!validateForm()) return;

        try {
            const response = await axios.post(EMPLOYEE_API_URL, employee);
            if (response.status === 200 || response.status === 201) {
                navigate("/");
            }
        } catch (error) {
            setError("Error adding employee. Please try again.");
            console.error("Error adding employee:", error);
        }
    };
    // Handles form submission, validates, sends data to API, and navigates on success


Input Change Handlers



    
       const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const { name, value, type } = e.target;

        setEmployee((prev) => ({
            ...prev,
            [name]: type === "number" ? Number(value) : value,
        }));

        setValidationErrors((prev) => ({
            ...prev,
            [name]: "",
        }));
    };
    // Handles changes for input fields, converts to number if needed, clears validation errors

    const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
        const { name, value } = e.target;

        setEmployee((prev) => ({
            ...prev,
            [name]: Number(value),
        }));

        setValidationErrors((prev) => ({
            ...prev,
            [name]: "",
        }));
    };
    // Handles changes for select fields, converts value to number, clears validation errors


User Data (Hardcoded for Demo)



    
   const user = "Sanjay";
    // Hardcoded user name for demo purposes


JSX Rendering



   
  return (
        <div className="container-fluid mt-4">
            <div className="card shadow p-4">
                <Header loginName={user} />
                <Container>
                    <div className="d-flex justify-content-between align-items-center mb-4">
                        <h1>Add Employee</h1>
                        <Link to="/" className="btn btn-secondary">
                            <i className="fas fa-arrow-left"></i> Employees List
                        </Link>
                    </div>

                    {error && <Alert variant="danger">{error}</Alert>}

                    <Form onSubmit={handleSubmit}>
                        {/* Form fields for each employee property */}
                        {/* Each field includes validation feedback */}

                        {/* Name Field */}
                        <Form.Group className="mb-3">
                            <Form.Label>Name</Form.Label>
                            <Form.Control
                                type="text"
                                name="empName"
                                value={employee.empName}
                                onChange={handleInputChange}
                                isInvalid={!!validationErrors.empName}
                            />
                            <Form.Control.Feedback type="invalid">
                                {validationErrors.empName}
                            </Form.Control.Feedback>
                        </Form.Group>

                        {/* Other form fields follow similar pattern */}
                        {/* Designation, Date of Joining, Salary, Phone, Department, Active Status */}

                        {/* Submit Button */}
                        <Button variant="primary" type="submit">
                            Save Employee
                        </Button>
                    </Form>
                </Container>
            </div>
        </div>
    );
};

export default AddEmployee;


Key Features:

  1. Type Safety: Uses TypeScript interfaces for Employee and Department

  2. Form Validation: Client-side validation with clear error messages

  3. API Integration: Fetches departments and posts new employee data

  4. Error Handling: Catches and displays API errors

  5. Routing: Uses React Router for navigation

  6. Bootstrap UI: Clean, responsive form layout with Bootstrap components

  7. State Management: Uses React hooks for all state needs

  8. Modular Design: Separates concerns with clear component structure

No comments:

Post a Comment