Building a Modern Employee Management System with React.js and Django

Share on LinkedIn
Share on X
Share on Facebook
Share on WhatsApp
Share on Telegram
Share via Email
Copy Link

Efficiently managing employees is crucial for any organization's success. From tracking attendance and managing payroll to overseeing performance and ensuring effective communication, an employee management system (EMS) can significantly streamline these tasks.

In this article, we'll walk you through creating a robust and user-friendly Employee Management System using two powerful technologies: React.js for the front end and Django for the back end. React.js, a popular JavaScript library, allows us to build interactive and dynamic user interfaces, while Django, a high-level Python web framework, provides a solid and scalable foundation for the back end.

This guide will cover the essential CRUD (Create, Read, Update, Delete) functionalities, ensuring that our EMS can handle the fundamental operations needed for managing employee data. We'll also focus on creating a robust backend that can support these operations securely and efficiently.

Article image

It's important to note that this project is a demo and may not be fully optimized for user-friendliness. However, it serves as a comprehensive starting point for anyone looking to build a more sophisticated EMS tailored to their organization's specific needs.

Whether you're a seasoned developer looking to expand your tech stack or a novice eager to dive into full-stack development, this guide will offer insights and practical steps to help you build an EMS that can handle the complexities of modern workforce management. So, let's roll up our sleeves and start building a system that can make employee management more efficient, transparent, and enjoyable for everyone involved.

Before we dive into coding, we need to set up our development environment and create the Django project. Follow these steps to get started:

First, ensure you have Python installed on your machine. You can download it from the official Python website.

Next, install virtualenv to create an isolated Python environment for your project:

pip install virtualenv

Create a new directory for your project and navigate into it:

mkdir employee_management_system
cd employee_management_system

Create and activate a virtual environment:

python -m venv venv
source venv/bin/activate  # On Windows use `venv\Scripts\activate`

You should now see (venv) at the beginning of your command prompt, indicating that the virtual environment is active.

With the virtual environment activated, install Django:

pip install django
pip install djangorestframework
pip install django-cors-headers

Create a new Django project called DjangoAPI:

django-admin startproject DjangoAPI
cd DjangoAPI

Run the development server to ensure everything is set up correctly:

python manage.py runserver

Open your browser and navigate to http://127.0.0.1:8000/. You should see the Django welcome page, indicating that your Django project is up and running.

Now, let's update the Django settings to configure paths, security, installed apps, middleware, templates, and logging. Here's an example of a comprehensive settings.py file for our Employee Management System:

1from pathlib import Path
2import os
3import secrets
4
5# Paths
6BASE_DIR = Path(__file__).resolve(strict=True).parent.parent
7MEDIA_URL = '/Photos/'
8MEDIA_ROOT = BASE_DIR / "Photos"
9
10# Security
11SECRET_KEY_FILE = BASE_DIR / 'secret_key.txt'
12
13if SECRET_KEY_FILE.exists():
14    with open(SECRET_KEY_FILE) as f:
15        SECRET_KEY = f.read().strip()
16else:
17    SECRET_KEY = secrets.token_urlsafe(50)
18    with open(SECRET_KEY_FILE, 'w') as f:
19        f.write(SECRET_KEY)
20
21DEBUG = True
22ALLOWED_HOSTS = []
23
24# Applications
25INSTALLED_APPS = [
26    'django.contrib.admin',
27    'django.contrib.auth',
28    'django.contrib.contenttypes',
29    'django.contrib.sessions',
30    'django.contrib.messages',
31    'django.contrib.staticfiles',
32    'rest_framework',
33    'corsheaders',
34    'EmployeeApp.apps.EmployeeappConfig'
35]
36
37CORS_ORIGIN_ALLOW_ALL = True
38
39# Middleware
40MIDDLEWARE = [
41    'corsheaders.middleware.CorsMiddleware',
42    'django.middleware.security.SecurityMiddleware',
43    'django.contrib.sessions.middleware.SessionMiddleware',
44    'django.middleware.common.CommonMiddleware',
45    'django.middleware.csrf.CsrfViewMiddleware',
46    'django.contrib.auth.middleware.AuthenticationMiddleware',
47    'django.contrib.messages.middleware.MessageMiddleware',
48    'django.middleware.clickjacking.XFrameOptionsMiddleware',
49]
50
51# URL Configuration
52ROOT_URLCONF = 'DjangoAPI.urls'
53
54# Templates
55TEMPLATES = [
56    {
57        'BACKEND': 'django.template.backends.django.DjangoTemplates',
58        'DIRS': [],
59        'APP_DIRS': True,
60        'OPTIONS': {
61            'context_processors': [
62                'django.template.context_processors.debug',
63                'django.template.context_processors.request',
64                'django.contrib.auth.context_processors.auth',
65                'django.contrib.messages.context_processors.messages',
66            ],
67        },
68    },
69]
70
71# WSGI
72WSGI_APPLICATION = 'DjangoAPI.wsgi.application'
73
74# Database
75DATABASES = {
76    'default': {
77        'ENGINE': 'django.db.backends.sqlite3',
78        'NAME': BASE_DIR / 'db.sqlite3',
79    }
80}
81
82# Password Validation
83AUTH_PASSWORD_VALIDATORS = [
84    {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
85    {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'},
86    {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
87    {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
88]
89
90# Internationalization
91LANGUAGE_CODE = 'en-us'
92TIME_ZONE = 'UTC'
93USE_I18N = True
94USE_L10N = True
95USE_TZ = True
96
97# Static Files
98STATIC_URL = '/static/'
99
100# Default Primary Key Field Type
101DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
102
103# Logging
104LOGGING = {
105    'version': 1,
106    'disable_existing_loggers': False,
107    'handlers': {
108        'file': {
109            'level': 'DEBUG',
110            'class': 'logging.FileHandler',
111            'filename': 'debug.log',
112        },
113    },
114    'loggers': {
115        'django': {
116            'handlers': ['file'],
117            'level': 'DEBUG',
118            'propagate': True,
119        },
120    },
121}
122
  1. Paths:
    • BASE_DIR defines the base directory for the project.
    • MEDIA_URL and MEDIA_ROOT configure the media files directory for storing employee photos.
  2. Security:
    • SECRET_KEY is generated and stored securely in a file to ensure it remains consistent across sessions.
  3. Applications:
    • INSTALLED_APPS lists the installed applications, including rest_framework for building APIs and corsheaders for handling Cross-Origin Resource Sharing.
  4. Middleware:
    • MIDDLEWARE includes necessary middleware components for handling security, sessions, authentication, and CORS.
  5. URL Configuration:
    • ROOT_URLCONF points to the URL configuration module for routing.
  6. Templates:
    • TEMPLATES configuration for rendering HTML templates.
  7. WSGI:
    • WSGI_APPLICATION specifies the WSGI application used by Django's development server and any WSGI-compatible web server.
  8. Database:
    • DATABASES configuration using SQLite for simplicity in this demo.
  9. Password Validation:
    • AUTH_PASSWORD_VALIDATORS ensures password strength and security.
  10. Internationalization:
    • Settings for language and timezone.
  11. Static Files:
    • Configuration for serving static files.
  12. Logging:
    • A simple logging configuration to log debug messages to a file named debug.log.

With the Django project set up, the next step is to create the necessary components for our Employee Management System. We will follow a structured approach to build models, views, serializers, tests, URLs, and admin configurations.

First, create a new Django application called EmployeeApp:

python manage.py startapp EmployeeApp

Add EmployeeApp to the INSTALLED_APPS list in settings.py:

# DjangoAPI/settings.py
INSTALLED_APPS = [
    ...
    'rest_framework',
    'corsheaders',
    'EmployeeApp',
]

Open EmployeeApp/models.py and define the Employee model

Models in Django are used to define the structure of the database tables. They represent the data and the logic that revolves around the data.

1# EmployeeApp/models.py
2from django.db import models
3
4class Departments(models.Model):
5    DepartmentId = models.AutoField(primary_key=True)
6    DepartmentName = models.CharField(max_length=500)
7
8    def __str__(self):
9        return self.DepartmentName
10
11class Employees(models.Model):
12    EmployeeId = models.AutoField(primary_key=True)
13    EmployeeName = models.CharField(max_length=500)
14    Department = models.CharField(max_length=500)
15    DateOfJoining = models.DateField()
16    PhotoFileName = models.CharField(max_length=500)
17
18    def __str__(self):
19        return self.EmployeeName
20
  • DepartmentId: An auto-incrementing integer field that serves as the primary key.
  • DepartmentName: A character field with a maximum length of 500 characters, used to store the name of the department.
  • EmployeeId: An auto-incrementing integer field that serves as the primary key.
  • EmployeeName: A character field with a maximum length of 500 characters, used to store the name of the employee.
  • Department: A character field with a maximum length of 500 characters, used to store the department name of the employee.
  • DateOfJoining: A date field used to store the date the employee joined the company.
  • PhotoFileName: A character field with a maximum length of 500 characters, used to store the file name of the employee's photo.

Run the following commands to create and apply migrations:

python manage.py makemigrations EmployeeApp
python manage.py migrate

Create serializers for Departments and Employees in EmployeeApp/serializers.py

Serializers in Django REST Framework are used to convert complex data types, such as querysets and model instances, into native Python datatypes that can then be easily rendered into JSON, XML, or other content types. They also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.

1# EmployeeApp/serializers.py
2from rest_framework import serializers
3from EmployeeApp.models import Departments, Employees
4
5class DepartmentSerializer(serializers.ModelSerializer):
6    class Meta:
7        model = Departments
8        fields = ('DepartmentId', 'DepartmentName')
9
10class EmployeeSerializer(serializers.ModelSerializer):
11    class Meta:
12        model = Employees
13        fields = ('EmployeeId', 'EmployeeName', 'Department', 'DateOfJoining', 'PhotoFileName')
14

Meta Class: Contains metadata for the serializer.

  • model: Specifies the model to be serialized.
  • fields: Specifies the fields to be included in the serialization process.

Define the views for handling API requests in EmployeeApp/views.py

Views in Django REST Framework are used to handle the HTTP requests and return HTTP responses. They contain the logic for the various actions (CRUD operations) that can be performed on the data.

1# EmployeeApp/views.py
2
3from rest_framework import status
4from rest_framework.decorators import api_view
5from rest_framework.response import Response
6from .models import Departments, Employees
7from .serializers import DepartmentSerializer, EmployeeSerializer
8from django.core.files.storage import default_storage
9from django.http import Http404
10import logging
11
12logger = logging.getLogger(__name__)
13
14
15@api_view(['GET', 'POST', 'PUT', 'DELETE'])
16def departmentApi(request, id=None):
17    if request.method == 'GET':
18        if id:
19            try:
20                department = Departments.objects.get(DepartmentId=id)
21                logger.debug(f"GET request for department with id={id}")
22            except Departments.DoesNotExist:
23                logger.error(f"Department with id={id} not found")
24                raise Http404("Department not found")
25            serializer = DepartmentSerializer(department)
26            return Response(serializer.data)
27        else:
28            departments = Departments.objects.all()
29            logger.debug("GET request for all departments")
30            serializer = DepartmentSerializer(departments, many=True)
31            return Response(serializer.data)
32
33    elif request.method == 'POST':
34        logger.debug(f"POST request with data={request.data}")
35        serializer = DepartmentSerializer(data=request.data)
36        if serializer.is_valid():
37            serializer.save()
38            logger.debug(f"Department created: {serializer.data}")
39            return Response(serializer.data, status=status.HTTP_201_CREATED)
40        logger.error(f"Validation errors: {serializer.errors}")
41        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
42
43    elif request.method == 'PUT':
44        if id is None:
45            logger.error("PUT request with id=None")
46            return Response({"error": "Department id is required for update"}, status=status.HTTP_400_BAD_REQUEST)
47        try:
48            department = Departments.objects.get(DepartmentId=id)
49            logger.debug(f"PUT request for department with id={id}")
50        except Departments.DoesNotExist:
51            logger.error(f"Department with id={id} not found")
52            raise Http404("Department not found")
53
54        serializer = DepartmentSerializer(department, data=request.data)
55        if serializer.is_valid():
56            serializer.save()
57            logger.debug(f"Department updated: {serializer.data}")
58            return Response(serializer.data)
59        logger.error(f"Validation errors: {serializer.errors}")
60        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
61
62    elif request.method == 'DELETE':
63        if id is None:
64            logger.error("DELETE request with id=None")
65            return Response({"error": "Department id is required for delete"}, status=status.HTTP_400_BAD_REQUEST)
66        try:
67            department = Departments.objects.get(DepartmentId=id)
68            logger.debug(f"DELETE request for department with id={id}")
69        except Departments.DoesNotExist:
70            logger.error(f"Department with id={id} not found")
71            raise Http404("Department not found")
72        department.delete()
73        logger.debug(f"Department with id={id} deleted")
74        return Response(status=status.HTTP_204_NO_CONTENT)
75
76
77@api_view(['GET', 'POST', 'PUT', 'DELETE'])
78def employeeApi(request, id=None):
79    if request.method == 'GET':
80        if id:
81            try:
82                employee = Employees.objects.get(EmployeeId=id)
83                logger.debug(f"GET request for employee with id={id}")
84            except Employees.DoesNotExist:
85                logger.error(f"Employee with id={id} not found")
86                raise Http404("Employee not found")
87            serializer = EmployeeSerializer(employee)
88            return Response(serializer.data)
89        else:
90            employees = Employees.objects.all()
91            logger.debug("GET request for all employees")
92            serializer = EmployeeSerializer(employees, many=True)
93            return Response(serializer.data)
94
95    elif request.method == 'POST':
96        logger.debug(f"POST request with data={request.data}")
97        serializer = EmployeeSerializer(data=request.data)
98        if serializer.is_valid():
99            serializer.save()
100            logger.debug(f"Employee created: {serializer.data}")
101            return Response(serializer.data, status=status.HTTP_201_CREATED)
102        logger.error(f"Validation errors: {serializer.errors}")
103        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
104
105    elif request.method == 'PUT':
106        if id is None:
107            logger.error("PUT request with id=None")
108            return Response({"error": "Employee id is required for update"}, status=status.HTTP_400_BAD_REQUEST)
109        try:
110            employee = Employees.objects.get(EmployeeId=id)
111            logger.debug(f"PUT request for employee with id={id}")
112        except Employees.DoesNotExist:
113            logger.error(f"Employee with id={id} not found")
114            raise Http404("Employee not found")
115
116        serializer = EmployeeSerializer(employee, data=request.data)
117        if serializer.is_valid():
118            serializer.save()
119            logger.debug(f"Employee updated: {serializer.data}")
120            return Response(serializer.data)
121        logger.error(f"Validation errors: {serializer.errors}")
122        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
123
124    elif request.method == 'DELETE':
125        if id is None:
126            logger.error("DELETE request with id=None")
127            return Response({"error": "Employee id is required for delete"}, status=status.HTTP_400_BAD_REQUEST)
128        try:
129            employee = Employees.objects.get(EmployeeId=id)
130            logger.debug(f"DELETE request for employee with id={id}")
131        except Employees.DoesNotExist:
132            logger.error(f"Employee with id={id} not found")
133            raise Http404("Employee not found")
134        employee.delete()
135        logger.debug(f"Employee with id={id} deleted")
136        return Response(status=status.HTTP_204_NO_CONTENT)
137
138# Handles file upload requests. The uploaded file is saved using Django's default storage system, and the file name is returned in the response.
139@api_view(['POST'])
140def SaveFile(request):
141    file = request.FILES['file']
142    logger.debug(f"File upload request: {file.name}")
143    file_name = default_storage.save(file.name, file)
144    logger.debug(f"File saved as: {file_name}")
145    return Response(file_name, status=status.HTTP_200_OK)
146
  • GET: Retrieves a single department/employee if an id is provided, otherwise retrieves all departments.
  • POST: Creates a new department/employee with the provided data.
  • PUT: Updates an existing department/employee with the provided id and data.
  • DELETE: Deletes a department/employee with the provided id.

These views utilize the Django REST Framework to provide a RESTful API for the Employee Management System, allowing clients to perform CRUD operations on the Departments and Employees resources, as well as upload files. The logging statements help in tracking the flow of requests and debugging any issues that arise during API interactions.

The urls.py file in Django is used to map URL patterns to views. It determines what code is executed when a particular URL is accessed.

1from django.urls import re_path as url
2from EmployeeApp import views
3from django.conf.urls.static import static
4from django.conf import settings
5
6urlpatterns = [
7    url(r'^department$', views.departmentApi, name='departmentApi'),
8    url(r'^department/([0-9]+)$', views.departmentApi, name='departmentApi'),
9
10    url(r'^employee$', views.employeeApi, name='employeeApi'),
11    url(r'^employee/([0-9]+)$', views.employeeApi, name='employeeApi'),
12
13    url(r'^employee/savefile$', views.SaveFile, name='saveFile')
14] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
15
  • url(r'^department$', views.departmentApi, name='departmentApi')
    • Maps the URL /department to the departmentApi view. This handles operations that do not require an ID (e.g., list all departments, create a new department).
  • url(r'^department/([0-9]+)$', views.departmentApi, name='departmentApi')
    • Maps the URL /department/<id> to the departmentApi view. This handles operations that require an ID (e.g., retrieve, update, delete a specific department).
  • url(r'^employee$', views.employeeApi, name='employeeApi')
    • Maps the URL /employee to the employeeApi view. This handles operations that do not require an ID (e.g., list all employees, create a new employee).
  • url(r'^employee/([0-9]+)$', views.employeeApi, name='employeeApi')
    • Maps the URL /employee/<id> to the employeeApi view. This handles operations that require an ID (e.g., retrieve, update, delete a specific employee).
  • url(r'^employee/savefile$', views.SaveFile, name='saveFile')
    • Maps the URL /employee/savefile to the SaveFile view. This handles file upload operations.
  • + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    • Serves media files during development by appending the necessary URL patterns to handle media files (e.g., photos).

Tests are used to ensure that the application works as expected. They help verify that the code performs the intended operations and handles various cases appropriately.

1from django.test import TestCase, Client
2from django.urls import reverse
3from rest_framework import status
4from .models import Departments, Employees
5import json
6import tempfile
7
8
9class DepartmentApiTests(TestCase):
10
11    def setUp(self):
12        self.client = Client()
13        self.department = Departments.objects.create(DepartmentName="Finance")
14
15    def test_get_all_departments(self):
16        response = self.client.get(reverse('departmentApi'))
17        self.assertEqual(response.status_code, status.HTTP_200_OK)
18
19    def test_get_single_department(self):
20        response = self.client.get(
21            reverse('departmentApi', args=[self.department.DepartmentId]))
22        self.assertEqual(response.status_code, status.HTTP_200_OK)
23
24    def test_create_department(self):
25        data = {"DepartmentName": "Marketing"}
26        response = self.client.post(reverse('departmentApi'), data=json.dumps(
27            data), content_type='application/json')
28        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
29
30    def test_update_department(self):
31        data = {"DepartmentName": "Human Resources"}
32        response = self.client.put(reverse('departmentApi', args=[
33                                   self.department.DepartmentId]), data=json.dumps(data), content_type='application/json')
34        self.assertEqual(response.status_code, status.HTTP_200_OK)
35
36    def test_delete_department(self):
37        response = self.client.delete(
38            reverse('departmentApi', args=[self.department.DepartmentId]))
39        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
40
41
42class EmployeeApiTests(TestCase):
43
44    def setUp(self):
45        self.client = Client()
46        self.department = Departments.objects.create(DepartmentName="IT")
47        self.employee = Employees.objects.create(
48            EmployeeName="John Doe", Department=self.department.DepartmentName, DateOfJoining="2022-01-01", PhotoFileName="john_doe.jpg")
49
50    def test_get_all_employees(self):
51        response = self.client.get(reverse('employeeApi'))
52        self.assertEqual(response.status_code, status.HTTP_200_OK)
53
54    def test_get_single_employee(self):
55        response = self.client.get(
56            reverse('employeeApi', args=[self.employee.EmployeeId]))
57        self.assertEqual(response.status_code, status.HTTP_200_OK)
58
59    def test_create_employee(self):
60        data = {"EmployeeName": "Jane Doe", "Department": "IT",
61                "DateOfJoining": "2022-01-01", "PhotoFileName": "jane_doe.jpg"}
62        response = self.client.post(reverse('employeeApi'), data=json.dumps(
63            data), content_type='application/json')
64        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
65
66    def test_update_employee(self):
67        data = {"EmployeeName": "John Smith", "Department": "IT",
68                "DateOfJoining": "2022-01-01", "PhotoFileName": "john_smith.jpg"}
69        response = self.client.put(reverse('employeeApi', args=[
70                                   self.employee.EmployeeId]), data=json.dumps(data), content_type='application/json')
71        self.assertEqual(response.status_code, status.HTTP_200_OK)
72
73    def test_delete_employee(self):
74        response = self.client.delete(
75            reverse('employeeApi', args=[self.employee.EmployeeId]))
76        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
77
78
79class SaveFileTests(TestCase):
80
81    def setUp(self):
82        self.client = Client()
83        self.test_file = tempfile.NamedTemporaryFile(suffix=".jpg")
84
85    def tearDown(self):
86        self.test_file.close()
87
88    def test_save_file(self):
89        with open(self.test_file.name, 'rb') as testfile:
90            response = self.client.post(
91                reverse('saveFile'), {'file': testfile})
92        self.assertEqual(response.status_code, status.HTTP_200_OK)
93
  • setUp: Initializes the test client, creates a sample department, and an employee.
  • test_get_all_departments: Tests retrieving all departments.
  • test_get_single_department: Tests retrieving a specific department by ID.
  • test_create_department: Tests creating a new department.
  • test_update_department: Tests updating an existing department.
  • test_delete_department: Tests deleting a department.
  • test_get_all_employees: Tests retrieving all employees.
  • test_get_single_employee: Tests retrieving a specific employee by ID.
  • test_create_employee: Tests creating a new employee.
  • test_update_employee: Tests updating an existing employee.
  • test_delete_employee: Tests deleting an employee.
  • tearDown: Closes the temporary test file after tests are run.
  • test_save_file: Tests uploading and saving a file.

These tests ensure the integrity and functionality of the API by verifying that the various endpoints perform the expected operations and handle different scenarios correctly.

Ensure you have Node.js and npm installed on your machine. You can download and install them from nodejs.org.

Open your terminal or command prompt and run the following command to create a new React application using Create React App:

npx create-react-app my-app
cd ui/my-app
npm install
ui/my-app/
|-- public/
|   |-- index.html
|-- src/
|   |-- components/
|   |-- services/
|   |-- App.js
|   |-- index.js
|-- package.json

By following the steps above, you have successfully set up a React application for the Employee Management System.

App.css

1/* Add media queries for responsive navigation */
2@media (max-width: 768px) {
3  .navbar-nav {
4    display: none; /* Hide the nav items on small screens */
5  }
6
7  .navbar-nav.show {
8    display: block; /* Show the nav items when toggled */
9  }
10
11  .navbar-toggler {
12    display: block; /* Show the toggle button on small screens */
13  }
14}
15
16.navbar-toggler {
17  display: none; /* Hide the toggle button by default */
18  background-color: #007bff;
19  border: none;
20  color: white;
21  padding: 0.5rem 1rem;
22  font-size: 1.25rem;
23  cursor: pointer;
24}
25
26.navbar-toggler:focus {
27  outline: none;
28}
29
30.dropdown-menu {
31  display: none; /* Hide dropdown menu by default */
32}
33
34.dropdown.show .dropdown-menu {
35  display: block; /* Show dropdown menu when toggled */
36  position: absolute; /* Ensure the dropdown is positioned correctly */
37  top: 100%; /* Align the dropdown menu with the bottom of the toggle button */
38  left: 0; /* Align the dropdown menu to the left */
39  width: 100%; /* Make sure the dropdown menu spans the width of the container */
40  background-color: white; /* Set background color to white */
41  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Add a subtle shadow for visibility */
42}
43

index.css

1/* Ensure the background color covers the entire page */
2body,
3html {
4  height: 100%;
5  margin: 0;
6  background-color: #f9f9f9;
7  overflow: hidden;
8}
9
10@media (max-width: 767px) {
11  .table th {
12    font-size: 12px;
13    padding: 5px;
14  }
15  .table td {
16    font-size: 12px;
17    padding: 5px;
18  }
19}
20
21/* Responsive table */
22.table-responsive {
23  display: block;
24  width: 100%;
25  overflow-x: auto;
26  -webkit-overflow-scrolling: touch;
27}
28
29.table {
30  width: 100%;
31  max-width: 100%;
32  margin-bottom: 1rem;
33  background-color: transparent;
34}
35
36@media (max-width: 768px) {
37  .table thead {
38    display: none;
39  }
40
41  .table,
42  .table tbody,
43  .table tr,
44  .table td {
45    display: block;
46    width: 100%;
47  }
48
49  .table tr {
50    margin-bottom: 15px;
51  }
52
53  .table td {
54    text-align: right;
55    padding-left: 50%;
56    position: relative;
57  }
58
59  .table td::before {
60    content: attr(data-label);
61    position: absolute;
62    left: 0;
63    width: 50%;
64    padding-left: 15px;
65    font-weight: bold;
66    text-align: left;
67  }
68}
69
70/* Home container to center content */
71.home-container {
72  display: flex;
73  flex-direction: column;
74  align-items: center;
75  justify-content: center;
76  min-height: 75vh;
77  padding: 20px;
78  background-color: #f9f9f9;
79}
80
81.home-content {
82  max-width: 600px;
83  margin: 0 20px; /* Ensure some margin for smaller screens */
84}
85
86/* Centered text and margins */
87.text-center {
88  text-align: center;
89}
90
91.my-4 {
92  margin: 2rem 0;
93}
94
95/* Responsive home content styling */
96.home-content {
97  font-size: 16px;
98  line-height: 1.6;
99  max-width: 600px;
100  width: 100%;
101  padding: 20px;
102  background-color: white;
103  border-radius: 8px;
104  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
105  text-align: center; /* Center align text */
106}
107
108.home-content p {
109  margin-bottom: 1rem;
110}
111
112/* Quick links styling */
113.quick-links {
114  list-style-type: none;
115  padding: 0;
116  display: flex;
117  justify-content: center;
118}
119
120.quick-links li {
121  margin: 0 10px;
122}
123
124.quick-links li a {
125  color: #007bff;
126  text-decoration: none;
127}
128
129.quick-links li a:hover {
130  text-decoration: underline;
131}
132
133/* Responsive design for smaller screens */
134@media (max-width: 600px) {
135  .quick-links {
136    flex-direction: column;
137  }
138
139  .quick-links li {
140    margin: 10px 0;
141  }
142}
143

The App.js file is the main entry point of the React application. It sets up the router, navigation, and routes for the different components of the Employee Management System.

1import "./App.css";
2import Home from "./Home";
3import Department from "./Department";
4import { Employee } from "./Employee";
5import { useState } from "react";
6import {
7  BrowserRouter as Router,
8  Route, Routes,
9  NavLink,
10} from "react-router-dom";
11
12function App() {
13  const [isNavOpen, setIsNavOpen] = useState(false);
14
15  const toggleNav = () => {
16    setIsNavOpen(!isNavOpen);
17  };
18
19  return (
20    <Router>
21      <div className="App container">
22        <h3 className="text-center my-4">
23          Welcome to Employee Management System
24        </h3>
25
26        <nav className="navbar navbar-expand-sm bg-light navbar-light">
27          <button className="navbar-toggler" onClick={toggleNav}>
2829          </button>
30          <div className={`navbar-nav ${isNavOpen ? "show" : ""}`}>
31            <div className="dropdown">
32              <button
33                className="btn btn-light btn-outline-primary dropdown-toggle"
34                onClick={toggleNav}
35              >
36                Menu
37              </button>
38              <div className={`dropdown-menu ${isNavOpen ? "show" : ""}`}>
39                <NavLink
40                  className="dropdown-item"
41                  to="/"
42                  onClick={() => setIsNavOpen(false)}
43                >
44                  Home
45                </NavLink>
46                <NavLink
47                  className="dropdown-item"
48                  to="/department"
49                  onClick={() => setIsNavOpen(false)}
50                >
51                  Department
52                </NavLink>
53                <NavLink
54                  className="dropdown-item"
55                  to="/employee"
56                  onClick={() => setIsNavOpen(false)}
57                >
58                  Employee
59                </NavLink>
60              </div>
61            </div>
62          </div>
63        </nav>
64
65        <Routes>
66          <Route path="/" element={<Home />} />
67          <Route path="/department" element={<Department />} />
68          <Route path="/employee" element={<Employee />} />
69        </Routes>
70      </div>
71    </Router>
72  );
73}
74
75export default App;
76
  • const [isNavOpen, setIsNavOpen] = useState(false); manages the state for the navigation menu toggle.
  • toggleNav function toggles the navigation menu's open/close state.
  • BrowserRouter as Router is used to wrap the application and enable routing.
  • Routes contains all the route definitions for the application.
  • Route elements define the component to be rendered for each path ("/", "/department", "/employee").
  • A collapsible navigation menu is created with NavLink components for Home, Department, and Employee pages.
  • The dropdown class and show class are conditionally applied based on isNavOpen state to handle the menu visibility.

The Home.js file represents the Home page of the application. It provides a brief overview and quick links to navigate to other sections.

1import React from "react";
2import "./index.css";
3
4const Home = () => {
5  return (
6    <div className="home-container">
7      <div className="home-content">
8        <p>
9          This is the home page of our React application. Here, you can find
10          various resources and links to other sections of the app. Explore the
11          navigation menu to visit the Departments and Employees sections.
12        </p>
13        <p>
14          Our application is built using React, a popular JavaScript library for
15          building user interfaces. We have implemented various features to
16          provide a seamless experience for managing departments and employees.
17        </p>
18        <p>Below are some quick links to get you started:</p>
19        <ul className="quick-links">
20          <li>
21            <a href="/">Home</a>
22          </li>
23          <li>
24            <a href="/department">Departments</a>
25          </li>
26          <li>
27            <a href="/employee">Employees</a>
28          </li>
29        </ul>
30      </div>
31    </div>
32  );
33};
34
35export default Home;
36
  • The Home component is a functional component that returns a simple layout with some text and links.
  • It uses a div with class home-container for the main container and home-content for content styling.
  • The component provides a brief description of the application and its features.
  • It includes a list of quick links to navigate to the Home, Departments, and Employees sections.
  • The component imports a CSS file ("./index.css") for styling purposes.
  • It uses classes (home-container, home-content, and quick-links) to apply styles defined in the CSS file.

We have two main components:

  • Department - Manages the department data.
  • Employee - Manages the employee data.

Both components have similar functionalities:

  • Fetching data from an API.
  • Displaying the data in a table.
  • Providing CRUD operations (Create, Read, Update, Delete).
  • Implementing drag-and-drop functionality for reordering items.

Defining a JavaScript object named variables using ES6 syntax.

export const variables = {
  API_URL: "http://127.0.0.1:8000/",
  PHOTO_URL: "http://127.0.0.1:8000/Photos/",
};

The variables object has two properties:

  • API_URL: This property is a string "http://127.0.0.1:8000/". It represents the base URL for an API endpoint. In this case, it points to a local development server running on 127.0.0.1 (localhost) at port 8000. This URL is typically used to communicate with a backend server to perform operations like fetching data, updating data, etc.
  • PHOTO_URL: This property is also a string "http://127.0.0.1:8000/Photos/". It represents the base URL for accessing photos or images served by the same local development server. This URL is used to construct the complete path to fetch or display images stored on the server.

Both Department and Employee components use the DraggableRow component to enable drag-and-drop functionality for table rows.

1import React from "react";
2import { useDrag, useDrop } from "react-dnd";
3
4const ItemType = "ROW";
5
6const DraggableRow = ({ id, index, moveRow, children }) => {
7  const ref = React.useRef(null);
8
9  const [, drop] = useDrop({
10    accept: ItemType,
11    hover(item, monitor) {
12      if (!ref.current) {
13        return;
14      }
15      const dragIndex = item.index;
16      const hoverIndex = index;
17
18      if (dragIndex === hoverIndex) {
19        return;
20      }
21
22      const hoverBoundingRect = ref.current.getBoundingClientRect();
23      const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
24      const clientOffset = monitor.getClientOffset();
25      const hoverClientY = clientOffset.y - hoverBoundingRect.top;
26
27      if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
28        return;
29      }
30
31      if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
32        return;
33      }
34
35      moveRow(dragIndex, hoverIndex);
36      item.index = hoverIndex;
37    },
38  });
39
40  const [{ isDragging }, drag] = useDrag({
41    type: ItemType,
42    item: { type: ItemType, id, index },
43    collect: (monitor) => ({
44      isDragging: monitor.isDragging(),
45    }),
46  });
47
48  const opacity = isDragging ? 0.5 : 1;
49  drag(drop(ref));
50
51  return (
52    <tr ref={ref} style={{ opacity }}>
53      {children}
54    </tr>
55  );
56};
57
58export default DraggableRow;
59
  • useDrag: Allows an element to be draggable.
  • useDrop: Allows an element to be a drop target.
  • Drag and Drop Logic: Handles the reordering of rows when dragged and dropped.
1import React, { useState, useEffect, useCallback } from "react";
2import { variables } from "./Variables.js";
3import { DndProvider, useDrag, useDrop } from "react-dnd";
4import { HTML5Backend } from "react-dnd-html5-backend";
5import "./index.css";
6import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
7import { faEdit, faTrash } from '@fortawesome/free-solid-svg-icons';
8import DraggableRow from "./DraggableRow"; // Import the DraggableRow component
9
10const ItemType = "DEPARTMENT";
11
12const Department = () => {
13  const [departments, setDepartments] = useState([]);
14  const [employees, setEmployees] = useState([]);
15  const [modalTitle, setModalTitle] = useState("");
16  const [departmentName, setDepartmentName] = useState("");
17  const [departmentId, setDepartmentId] = useState(0);
18  const [departmentIdFilter, setDepartmentIdFilter] = useState("");
19  const [departmentNameFilter, setDepartmentNameFilter] = useState("");
20  const [departmentsWithoutFilter, setDepartmentsWithoutFilter] = useState([]);
21
22  useEffect(() => {
23    refreshList();
24  }, []);
25
26  const refreshList = async () => {
27    try {
28      const depResponse = await fetch(variables.API_URL + "department");
29      const depData = await depResponse.json();
30      setDepartments(depData);
31      setDepartmentsWithoutFilter(depData);
32
33      const empResponse = await fetch(variables.API_URL + "employee");
34      const empData = await empResponse.json();
35      setEmployees(empData);
36    } catch (error) {
37      console.error("Failed to fetch data:", error);
38    }
39  };
40
41  const filterFn = () => {
42    const filteredData = departmentsWithoutFilter.filter(
43      (el) =>
44        el.DepartmentId.toString().toLowerCase().includes(departmentIdFilter.toLowerCase().trim()) &&
45        el.DepartmentName.toString().toLowerCase().includes(departmentNameFilter.toLowerCase().trim())
46    );
47    setDepartments(filteredData);
48  };
49
50  const sortResult = (prop, asc) => {
51    const sortedData = [...departmentsWithoutFilter].sort((a, b) => {
52      if (asc) return a[prop] > b[prop] ? 1 : a[prop] < b[prop] ? -1 : 0;
53      return b[prop] > a[prop] ? 1 : b[prop] < a[prop] ? -1 : 0;
54    });
55    setDepartments(sortedData);
56  };
57
58  const handleAddClick = () => {
59    setModalTitle("Add Department");
60    setDepartmentId(0);
61    setDepartmentName("");
62  };
63
64  const handleEditClick = (dep) => {
65    setModalTitle("Edit Department");
66    setDepartmentId(dep.DepartmentId);
67    setDepartmentName(dep.DepartmentName);
68  };
69
70  const handleCreateClick = async () => {
71    try {
72      const response = await fetch(variables.API_URL + "department", {
73        method: "POST",
74        headers: {
75          Accept: "application/json",
76          "Content-Type": "application/json",
77        },
78        body: JSON.stringify({ DepartmentName: departmentName }),
79      });
80      const result = await response.json();
81      alert(result);
82      refreshList();
83    } catch (error) {
84      alert("Failed");
85    }
86  };
87
88  const handleUpdateClick = async () => {
89    try {
90      const response = await fetch(variables.API_URL + "department/" + departmentId, {
91        method: "PUT",
92        headers: {
93          Accept: "application/json",
94          "Content-Type": "application/json",
95        },
96        body: JSON.stringify({
97          DepartmentId: departmentId,
98          DepartmentName: departmentName,
99        }),
100      });
101      const result = await response.json();
102      document.getElementById('modalCloseButton').click();
103      refreshList();
104    } catch (error) {
105      alert("Failed");
106    }
107  };
108
109  const handleDeleteClick = async (id) => {
110    if (window.confirm("Are you sure?")) {
111      try {
112        const response = await fetch(variables.API_URL + "department/" + id, {
113          method: "DELETE",
114          headers: {
115            Accept: "application/json",
116            "Content-Type": "application/json",
117          },
118        });
119        if (response.status === 204) {
120          alert("Department deleted successfully");
121        } else {
122          const result = await response.json();
123          alert(result);
124        }
125        refreshList();
126      } catch (error) {
127        alert("Failed");
128      }
129    }
130  };
131
132  const handleFilterChange = (e) => {
133    const { name, value } = e.target;
134    if (name === "departmentIdFilter") {
135      setDepartmentIdFilter(value);
136    } else if (name === "departmentNameFilter") {
137      setDepartmentNameFilter(value);
138    }
139    filterFn();
140  };
141
142  const moveRow = useCallback(
143    (dragIndex, hoverIndex) => {
144      const dragRow = departments[dragIndex];
145      const updatedDepartments = [...departments];
146      updatedDepartments.splice(dragIndex, 1);
147      updatedDepartments.splice(hoverIndex, 0, dragRow);
148      setDepartments(updatedDepartments);
149    },
150    [departments]
151  );
152
153  return (
154    <div>
155      <DndProvider backend={HTML5Backend}>
156        <button
157          type="button"
158          className="btn btn-primary m-2 float-end"
159          data-bs-toggle="modal"
160          data-bs-target="#exampleModal"
161          onClick={handleAddClick}
162        >
163          Add Department
164        </button>
165        <div className="table-responsive">
166          <table className="table table-striped">
167            <thead>
168              <tr>
169                <th>
170                  <div className="d-flex flex-row">
171                    <input
172                      className="form-control m-2"
173                      onChange={handleFilterChange}
174                      name="departmentIdFilter"
175                      placeholder="Filter"
176                    />
177                    <button
178                      type="button"
179                      className="btn btn-light"
180                      onClick={() => sortResult("DepartmentId", true)}
181                    >
182183                    </button>
184                    <button
185                      type="button"
186                      className="btn btn-light"
187                      onClick={() => sortResult("DepartmentId", false)}
188                    >
189190                    </button>
191                  </div>
192                  DepartmentId
193                </th>
194                <th>
195                  <div className="d-flex flex-row">
196                    <input
197                      className="form-control m-2"
198                      onChange={handleFilterChange}
199                      name="departmentNameFilter"
200                      placeholder="Filter"
201                    />
202                    <button
203                      type="button"
204                      className="btn btn-light"
205                      onClick={() => sortResult("DepartmentName", true)}
206                    >
207208                    </button>
209                    <button
210                      type="button"
211                      className="btn btn-light"
212                      onClick={() => sortResult("DepartmentName", false)}
213                    >
214215                    </button>
216                  </div>
217                  DepartmentName
218                </th>
219                <th>Options</th>
220              </tr>
221            </thead>
222            <tbody>
223              {departments.map((dep, index) => (
224                <DraggableRow
225                  key={dep.DepartmentId}
226                  id={dep.DepartmentId}
227                  index={index}
228                  moveRow={moveRow}
229                >
230                  <td>{dep.DepartmentId}</td>
231                  <td>{dep.DepartmentName}</td>
232                  <td>
233                    <button
234                      type="button"
235                      className="btn btn-light mr-1"
236                      data-bs-toggle="modal"
237                      data-bs-target="#exampleModal"
238                      onClick={() => handleEditClick(dep)}
239                    >
240                      <FontAwesomeIcon icon={faEdit} />
241                    </button>
242                    <button
243                      type="button"
244                      className="btn btn-light mr-1"
245                      onClick={() => handleDeleteClick(dep.DepartmentId)}
246                    >
247                      <FontAwesomeIcon icon={faTrash} />
248                    </button>
249                  </td>
250                </DraggableRow>
251              ))}
252            </tbody>
253          </table>
254        </div>
255      </DndProvider>
256      <div
257        className="modal fade"
258        id="exampleModal"
259        tabIndex="-1"
260        aria-labelledby="exampleModalLabel"
261        aria-hidden="true"
262      >
263        <div className="modal-dialog modal-lg modal-dialog-centered">
264          <div className="modal-content">
265            <div className="modal-header">
266              <h5 className="modal-title" id="exampleModalLabel">
267                {modalTitle}
268              </h5>
269              <button
270                type="button"
271                className="btn-close"
272                data-bs-dismiss="modal"
273                aria-label="Close"
274                id="modalCloseButton"
275              ></button>
276            </div>
277            <div className="modal-body">
278              <div className="input-group mb-3">
279                <span className="input-group-text">Department Name</span>
280                <input
281                  type="text"
282                  className="form-control"
283                  value={departmentName}
284                  onChange={(e) => setDepartmentName(e.target.value)}
285                />
286              </div>
287              {departmentId === 0 ? (
288                <button
289                  type="button"
290                  className="btn btn-primary float-start"
291                  onClick={handleCreateClick}
292                >
293                  Create
294                </button>
295              ) : (
296                <button
297                  type="button"
298                  className="btn btn-primary float-start"
299                  onClick={handleUpdateClick}
300                >
301                  Update
302                </button>
303              )}
304            </div>
305          </div>
306        </div>
307      </div>
308    </div>
309  );
310};
311
312export default Department;
313
  • State Management: Uses React's useState to manage department data, modal states, and filters.
  • CRUD Operations: Uses fetch API for Create, Read, Update, and Delete operations.
  • Filtering and Sorting: Implements filtering and sorting for department data.
  • Drag and Drop: Uses react-dnd to enable drag-and-drop functionality for department rows.

The Employee component has similar functionality to the Department component but is focused on managing employee data.

1import React, { useState, useEffect, useCallback } from "react";
2import { variables } from "./Variables.js";
3import { DndProvider, useDrag, useDrop } from "react-dnd";
4import { HTML5Backend } from "react-dnd-html5-backend";
5import "./index.css";
6import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
7import { faEdit, faTrash } from '@fortawesome/free-solid-svg-icons';
8import DraggableRow from "./DraggableRow"; // Import the DraggableRow component
9
10const ItemType = "EMPLOYEE";
11
12const Employee = () => {
13  const [employees, setEmployees] = useState([]);
14  const [departments, setDepartments] = useState([]);
15  const [modalTitle, setModalTitle] = useState("");
16  const [employeeId, setEmployeeId] = useState(0);
17  const [employeeName, setEmployeeName] = useState("");
18  const [department, setDepartment] = useState("");
19  const [dateOfJoining, setDateOfJoining] = useState("");
20  const [photoFileName, setPhotoFileName] = useState("anonymous.png");
21  const [photoPath, setPhotoPath] = useState(variables.PHOTO_URL);
22
23  useEffect(() => {
24    refreshList();
25  }, []);
26
27  const refreshList = async () => {
28    try {
29      const empResponse = await fetch(variables.API_URL + "employee");
30      const empData = await empResponse.json();
31      setEmployees(empData);
32
33      const depResponse = await fetch(variables.API_URL + "department");
34      const depData = await depResponse.json();
35      setDepartments(depData);
36    } catch (error) {
37      console.error("Failed to fetch data:", error);
38    }
39  };
40
41  const handleAddClick = () => {
42    setModalTitle("Add Employee");
43    setEmployeeId(0);
44    setEmployeeName("");
45    setDepartment("");
46    setDateOfJoining("");
47    setPhotoFileName("anonymous.png");
48  };
49
50  const handleEditClick = (emp) => {
51    setModalTitle("Edit Employee");
52    setEmployeeId(emp.EmployeeId);
53    setEmployeeName(emp.EmployeeName);
54    setDepartment(emp.Department);
55    setDateOfJoining(emp.DateOfJoining);
56    setPhotoFileName(emp.PhotoFileName);
57  };
58
59  const handleCreateClick = async () => {
60    try {
61      const response = await fetch(variables.API_URL + "employee", {
62        method: "POST",
63        headers: {
64          Accept: "application/json",
65          "Content-Type": "application/json",
66        },
67        body: JSON.stringify({
68          EmployeeName: employeeName,
69          Department: department,
70          DateOfJoining: dateOfJoining,
71          PhotoFileName: photoFileName,
72        }),
73      });
74      const result = await response.json();
75      alert(result);
76      refreshList();
77    } catch (error) {
78      alert("Failed");
79    }
80  };
81
82  const handleUpdateClick = async () => {
83    try {
84      const response = await fetch(variables.API_URL + "employee", {
85        method: "PUT",
86        headers: {
87          Accept: "application/json",
88          "Content-Type": "application/json",
89        },
90        body: JSON.stringify({
91          EmployeeId: employeeId,
92          EmployeeName: employeeName,
93          Department: department,
94          DateOfJoining: dateOfJoining,
95          PhotoFileName: photoFileName,
96        }),
97      });
98      const result = await response.json();
99      document.getElementById('modalCloseButton').click();
100      refreshList();
101    } catch (error) {
102      alert("Failed");
103    }
104  };
105
106  const handleDeleteClick = async (id) => {
107    if (window.confirm("Are you sure?")) {
108      try {
109        const response = await fetch(variables.API_URL + "employee/" + id, {
110          method: "DELETE",
111          headers: {
112            Accept: "application/json",
113            "Content-Type": "application/json",
114          },
115        });
116        if (response.status === 204) {
117          alert("Employee deleted successfully");
118        } else {
119          const result = await response.json();
120          alert(result);
121        }
122        refreshList();
123      } catch (error) {
124        alert("Failed");
125      }
126    }
127  };
128
129  const handleImageUpload = async (e) => {
130    e.preventDefault();
131    const formData = new FormData();
132    formData.append("file", e.target.files[0]);
133
134    try {
135      const response = await fetch(variables.API_URL + "employee/savefile", {
136        method: "POST",
137        body: formData,
138      });
139      const data = await response.json();
140      setPhotoFileName(data);
141    } catch (error) {
142      alert("Failed to upload image");
143    }
144  };
145
146  const moveRow = useCallback(
147    (dragIndex, hoverIndex) => {
148      const dragRow = employees[dragIndex];
149      const updatedEmployees = [...employees];
150      updatedEmployees.splice(dragIndex, 1);
151      updatedEmployees.splice(hoverIndex, 0, dragRow);
152      setEmployees(updatedEmployees);
153    },
154    [employees]
155  );
156
157  return (
158    <div>
159      <DndProvider backend={HTML5Backend}>
160        <button
161          type="button"
162          className="btn btn-primary m-2 float-end"
163          data-bs-toggle="modal"
164          data-bs-target="#exampleModal"
165          onClick={handleAddClick}
166        >
167          Add Employee
168        </button>
169        <div className="table-responsive">
170          <table className="table table-striped">
171            <thead>
172              <tr>
173                <th>EmployeeId</th>
174                <th>EmployeeName</th>
175                <th>Department</th>
176                <th>DateOfJoining</th>
177                <th>PhotoFileName</th>
178                <th>Options</th>
179              </tr>
180            </thead>
181            <tbody>
182              {employees.map((emp, index) => (
183                <DraggableRow
184                  key={emp.EmployeeId}
185                  id={emp.EmployeeId}
186                  index={index}
187                  moveRow={moveRow}
188                >
189                  <td>{emp.EmployeeId}</td>
190                  <td>{emp.EmployeeName}</td>
191                  <td>{emp.Department}</td>
192                  <td>{emp.DateOfJoining}</td>
193                  <td>
194                    <img
195                      width="50px"
196                      height="50px"
197                      src={photoPath + emp.PhotoFileName}
198                      alt={emp.EmployeeName}
199                    />
200                  </td>
201                  <td>
202                    <button
203                      type="button"
204                      className="btn btn-light mr-1"
205                      data-bs-toggle="modal"
206                      data-bs-target="#exampleModal"
207                      onClick={() => handleEditClick(emp)}
208                    >
209                      <FontAwesomeIcon icon={faEdit} />
210                    </button>
211                    <button
212                      type="button"
213                      className="btn btn-light mr-1"
214                      onClick={() => handleDeleteClick(emp.EmployeeId)}
215                    >
216                      <FontAwesomeIcon icon={faTrash} />
217                    </button>
218                  </td>
219                </DraggableRow>
220              ))}
221            </tbody>
222          </table>
223        </div>
224      </DndProvider>
225      <div
226        className="modal fade"
227        id="exampleModal"
228        tabIndex="-1"
229        aria-labelledby="exampleModalLabel"
230        aria-hidden="true"
231      >
232        <div className="modal-dialog modal-lg modal-dialog-centered">
233          <div className="modal-content">
234            <div className="modal-header">
235              <h5 className="modal-title" id="exampleModalLabel">
236                {modalTitle}
237              </h5>
238              <button
239                type="button"
240                className="btn-close"
241                data-bs-dismiss="modal"
242                aria-label="Close"
243                id="modalCloseButton"
244              ></button>
245            </div>
246            <div className="modal-body">
247              <div className="input-group mb-3">
248                <span className="input-group-text">Employee Name</span>
249                <input
250                  type="text"
251                  className="form-control"
252                  value={employeeName}
253                  onChange={(e) => setEmployeeName(e.target.value)}
254                />
255              </div>
256              <div className="input-group mb-3">
257                <span className="input-group-text">Department</span>
258                <select
259                  className="form-control"
260                  value={department}
261                  onChange={(e) => setDepartment(e.target.value)}
262                >
263                  {departments.map((dep) => (
264                    <option key={dep.DepartmentId} value={dep.DepartmentName}>
265                      {dep.DepartmentName}
266                    </option>
267                  ))}
268                </select>
269              </div>
270              <div className="input-group mb-3">
271                <span className="input-group-text">Date Of Joining</span>
272                <input
273                  type="date"
274                  className="form-control"
275                  value={dateOfJoining}
276                  onChange={(e) => setDateOfJoining(e.target.value)}
277                />
278              </div>
279              <div className="input-group mb-3">
280                <span className="input-group-text">Photo</span>
281                <input
282                  type="file"
283                  className="form-control"
284                  onChange={handleImageUpload}
285                />
286              </div>
287              <button
288                type="button"
289                className="btn btn-primary float-start"
290                onClick={employeeId === 0 ? handleCreateClick : handleUpdateClick}
291              >
292                {employeeId === 0 ? "Create" : "Update"}
293              </button>
294            </div>
295          </div>
296        </div>
297      </div>
298    </div>
299  );
300};
301
302export default Employee;
303
  • State Management: Uses React's useState to manage employee data, modal states, and image uploads.
  • CRUD Operations: Uses fetch API for Create, Read, Update, and Delete operations.
  • Drag and Drop: Uses react-dnd to enable drag-and-drop functionality for employee rows.
  • Image Upload: Handles image uploads for employee photos.

These components are designed to be modular and reusable, focusing on managing data with CRUD operations and enhancing user experience with sorting, filtering, and drag-and-drop features.

Remember, adaptability and clarity in your codebase not only benefit your current development efforts but also pave the way for smoother collaboration and growth in your software projects.

Explore the GitHub repository

Happy coding!

Share on LinkedIn
Share on X
Share on Facebook
Share on WhatsApp
Share on Telegram
Share via Email
Copy Link

Ready to take your business to the next level? Let’s make it happen.

Recommended For You