Data base
USE employeems;
CREATE TABLE face_descriptors (
 id INT AUTO_INCREMENT PRIMARY KEY,
 employee_id INT NOT NULL,
 descriptor JSON NOT NULL,
 FOREIGN KEY (employee_id) REFERENCES employee(id)
);
CREATE TABLE attendance (
 id INT AUTO_INCREMENT PRIMARY KEY,
 employee_id INT NOT NULL,
 date DATE NOT NULL,
 status ENUM('Present', 'Absent') NOT NULL,
 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
 FOREIGN KEY (employee_id) REFERENCES employee(id),
 UNIQUE (employee_id, date)
);
AdminRoute
import express from "express";
import con from "../utils/db.js";
import jwt from "jsonwebtoken";
import bcrypt from 'bcrypt';
import multer from "multer";
import path from 'path';
const router = express.Router();
// Admin Login
router.post("/adminlogin", (req, res) => {
 const sql = "SELECT * from admins where email=? and password=?";
 con.query(sql, [req.body.email, req.body.password], (err, result) => {
  if (err) return res.json({ loginStatus: false, Error: "Query error" });
  if (result.length > 0) {
   const email = result[0].email;
   const token = jwt.sign(
    { role: "admin", email: email, id: result[0].id },
    "jwt_secret_key",
    { expiresIn: "1d" }
          );
          res.cookie('token', token);
          return res.json({ loginStatus: true });
      } else {
          return res.json({
           loginStatus: false,
           Error: "wrong email or password",
          });
 });
});
// Get Categories
router.get('/category', (req, res) => {
 const sql = "SELECT * FROM categorys";
 con.query(sql, (err, result) => {
      if (err) return res.json({ Status: false, Error: "Query Error" });
      return res.json({ Status: true, Result: result });
 });
});
// Add Category
router.post('/add_category', (req, res) => {
 const sql = "INSERT INTO categorys (`name`) VALUES (?)";
 con.query(sql, [req.body.category], (err, result) => {
      if (err) {
          console.log("SQL Error:", err);
          return res.json({ Status: false, Error: "Query Error: " + err.message });
      return res.json({ Status: true });
 });
});
// Image Upload Configuration
const storage = multer.diskStorage({
 destination: (req, file, cb) => {
      cb(null, 'publics/Images');
 },
 filename: (req, file, cb) => {
  cb(null, file.fieldname + "_" + Date.now() +
path.extname(file.originalname));
});
const upload = multer({ storage: storage });
// Add Employee with Face Descriptor
router.post('/add_employee', upload.single('image'), (req, res) => {
 const sql = `INSERT INTO employee (name, email, password, address,
salary, image, category_id) VALUES (?)`;
 bcrypt.hash(req.body.password, 10, (err, hash) => {
      if (err) return res.json({ Status: false, Error: "Query Error" });
      const values = [
       req.body.name,
       req.body.email,
       hash,
       req.body.address,
       req.body.salary,
       req.file ? req.file.filename : null,
       req.body.category_id,
  ];
  con.query(sql, [values], (err, result) => {
    if (err) return res.json({ Status: false, Error: "Query Error: " +
err.message });
       // Save face descriptor if provided
       if (req.body.descriptor) {
           const employeeId = result.insertId;
    const descriptorSql = `INSERT INTO face_descriptors (employee_id,
descriptor) VALUES (?, ?)`;
           con.query(descriptorSql, [employeeId, req.body.descriptor], (err)
=> {
     if (err) return res.json({ Status: false, Error: "Error saving face
descriptor: " + err.message });
            return res.json({ Status: true, employeeId });
           });
       } else {
           return res.json({ Status: true, employeeId: result.insertId });
  });
 });
});
// Get All Employees
router.get('/employee', (req, res) => {
 const sql = "SELECT * FROM employee";
 con.query(sql, (err, result) => {
      if (err) return res.json({ Status: false, Error: "Query Error" });
      return res.json({ Status: true, Result: result });
 });
});
// Get Employee by ID
router.get('/employee/:id', (req, res) => {
 const id = req.params.id;
 const sql = "SELECT * FROM employee WHERE id=?";
 con.query(sql, [id], (err, result) => {
      if (err) return res.json({ Status: false, Error: "Query Error" });
      return res.json({ Status: true, Result: result });
 });
});
// Edit Employee
router.put('/edit_employee/:id', (req, res) => {
 const id = req.params.id;
 const sql = `UPDATE employee set name=?, email=?, salary=?,
address=?, category_id=? Where id=?`;
 const values = [
      req.body.name,
      req.body.email,
      req.body.salary,
      req.body.address,
      req.body.category_id
 ];
 con.query(sql, [...values, id], (err, result) => {
      if (err) return res.json({ Status: false, Error: "Query Error" + err });
      return res.json({ Status: true, Result: result });
 });
});
// Delete Employee
router.delete('/delete_employee/:id', (req, res) => {
 const id = req.params.id;
 const sql = "DELETE FROM employee WHERE id=?";
 con.query(sql, [id], (err, result) => {
      if (err) return res.json({ Status: false, Error: "Query Error" + err });
      return res.json({ Status: true, Result: result });
 });
});
// Admin Count
router.get('/admin_count', (req, res) => {
 const sql = "SELECT COUNT(id) as admin FROM admins";
 con.query(sql, (err, result) => {
      if (err) return res.json({ Status: false, Error: "Query Error" + err });
      return res.json({ Status: true, Result: result });
 });
});
// Employee Count
router.get('/employee_count', (req, res) => {
 const sql = "SELECT COUNT(id) as employee FROM employee";
 con.query(sql, (err, result) => {
      if (err) return res.json({ Status: false, Error: "Query Error" + err });
      return res.json({ Status: true, Result: result });
 });
});
// Salary Count
router.get('/salary_count', (req, res) => {
 const sql = "SELECT SUM(salary) as salaryOfEmp FROM employee";
 con.query(sql, (err, result) => {
      if (err) return res.json({ Status: false, Error: "Query Error" + err });
      return res.json({ Status: true, Result: result });
 });
});
// Admin Records
router.get('/admin_records', (req, res) => {
 const sql = "SELECT * FROM admins";
 con.query(sql, (err, result) => {
      if (err) return res.json({ Status: false, Error: "Query Error" + err });
      return res.json({ Status: true, Result: result });
 });
});
// Get Face Descriptors for an Employee
router.get('/face_descriptors/:employeeId', (req, res) => {
 const sql = "SELECT descriptor FROM face_descriptors WHERE
employee_id = ?";
 con.query(sql, [req.params.employeeId], (err, result) => {
  if (err) return res.json({ Status: false, Error: "Query Error: " +
err.message });
      return res.json({
       Status: true,
   Result: result.map(row => ({ descriptor:
JSON.parse(row.descriptor) }))
      });
 });
});
// Save Attendance
router.post('/attendance', (req, res) => {
 const { employeeId, date, status } = req.body;
 const sql = "INSERT INTO attendance (employee_id, date, status)
VALUES (?, ?, ?)";
 con.query(sql, [employeeId, date, status], (err, result) => {
  if (err) return res.json({ Status: false, Error: "Query Error: " +
err.message });
      return res.json({ Status: true });
 });
});
// Get Attendance Records
router.get('/attendance', (req, res) => {
 const sql = `
      SELECT a.id, a.employee_id, e.name, a.date, a.status
      FROM attendance a
      JOIN employee e ON a.employee_id = e.id
 `;
 con.query(sql, (err, result) => {
  if (err) return res.json({ Status: false, Error: "Query Error: " +
err.message });
      return res.json({ Status: true, Result: result });
 });
});
// Logout
router.get('/logout', (req, res) => {
 res.clearCookie('token');
 return res.json({ Status: true });
});
export { router as adminRouter };
frontend/
├── public/
│ └── models/ (face-api.js models)
├── src/
│ ├── components/
│ │ ├── AttendanceSystem.jsx
│ │ └── AddEmployee.jsx
│ ├── App.jsx
│ └── index.js
├── package.json
└── tailwind.config.js
AddEmployee
import React, { useState, useEffect, useRef } from 'react';
import * as faceapi from 'face-api.js';
import axios from 'axios';
import Cookies from 'js-cookie';
const AddEmployee = () => {
 const [name, setName] = useState('');
 const [email, setEmail] = useState('');
 const [password, setPassword] = useState('');
 const [address, setAddress] = useState('');
 const [salary, setSalary] = useState('');
 const [categoryId, setCategoryId] = useState('');
 const [image, setImage] = useState(null);
 const [categories, setCategories] = useState([]);
 const [isCameraOn, setIsCameraOn] = useState(false);
 const [isModelLoaded, setIsModelLoaded] = useState(false);
 const [descriptor, setDescriptor] = useState(null);
const videoRef = useRef(null);
// Load face-api.js models
useEffect(() => {
 const loadModels = async () => {
   try {
       await Promise.all([
        faceapi.nets.tinyFaceDetector.loadFromUri('/models'),
        faceapi.nets.faceLandmark68Net.loadFromUri('/models'),
        faceapi.nets.faceRecognitionNet.loadFromUri('/models'),
       ]);
       setIsModelLoaded(true);
   } catch (error) {
       console.error('Error loading models:', error);
 };
 loadModels();
}, []);
// Fetch categories
 useEffect(() => {
  const fetchCategories = async () => {
    try {
    const response = await
axios.get('http://localhost:3000/auth/category', {
            headers: { Authorization: `Bearer ${Cookies.get('token')}` }
        });
        if (response.data.Status) {
            setCategories(response.data.Result);
    } catch (error) {
        console.error('Error fetching categories:', error);
  };
  fetchCategories();
 }, []);
 // Start webcam
 const startCamera = async () => {
  try {
   const stream = await navigator.mediaDevices.getUserMedia({ video:
true });
      videoRef.current.srcObject = stream;
      setIsCameraOn(true);
  } catch (error) {
      console.error('Error accessing webcam:', error);
 };
 // Stop webcam
 const stopCamera = () => {
  if (videoRef.current && videoRef.current.srcObject) {
   videoRef.current.srcObject.getTracks().forEach(track =>
track.stop());
  setIsCameraOn(false);
 };
 // Capture face descriptor
 const captureFace = async () => {
  if (!isModelLoaded || !videoRef.current) return;
  const detections = await faceapi
   .detectSingleFace(videoRef.current, new
faceapi.TinyFaceDetectorOptions())
      .withFaceLandmarks()
      .withFaceDescriptor();
  if (detections) {
      setDescriptor(Array.from(detections.descriptor));
      alert('Face captured successfully!');
      stopCamera();
  } else {
      alert('No face detected!');
 };
 // Submit employee data
 const handleSubmit = async (e) => {
  e.preventDefault();
  const formData = new FormData();
  formData.append('name', name);
  formData.append('email', email);
  formData.append('password', password);
  formData.append('address', address);
  formData.append('salary', salary);
  formData.append('category_id', categoryId);
  if (image) formData.append('image', image);
  if (descriptor) formData.append('descriptor',
JSON.stringify(descriptor));
  try {
   const response = await
axios.post('http://localhost:3000/auth/add_employee', formData, {
    headers: {
         'Content-Type': 'multipart/form-data',
         Authorization: `Bearer ${Cookies.get('token')}`
   });
   if (response.data.Status) {
         alert('Employee added successfully!');
         setName('');
         setEmail('');
         setPassword('');
         setAddress('');
         setSalary('');
         setCategoryId('');
         setImage(null);
         setDescriptor(null);
     } else {
         alert('Error: ' + response.data.Error);
 } catch (error) {
     console.error('Error adding employee:', error);
     alert('Failed to add employee');
};
return (
 <div className="container mx-auto p-4">
<h1 className="text-3xl font-bold mb-4">Add Employee</h1>
<form onSubmit={handleSubmit} className="space-y-4">
 <div>
  <label className="block text-lg mb-1">Name:</label>
  <input
   type="text"
   value={name}
   onChange={(e) => setName(e.target.value)}
   className="border p-2 rounded w-full"
   required
  />
 </div>
 <div>
  <label className="block text-lg mb-1">Email:</label>
  <input
   type="email"
   value={email}
   onChange={(e) => setEmail(e.target.value)}
   className="border p-2 rounded w-full"
   required
 />
</div>
<div>
 <label className="block text-lg mb-1">Password:</label>
 <input
  type="password"
  value={password}
  onChange={(e) => setPassword(e.target.value)}
  className="border p-2 rounded w-full"
  required
 />
</div>
<div>
 <label className="block text-lg mb-1">Address:</label>
 <input
  type="text"
  value={address}
  onChange={(e) => setAddress(e.target.value)}
  className="border p-2 rounded w-full"
  required
 />
</div>
<div>
 <label className="block text-lg mb-1">Salary:</label>
 <input
  type="number"
  value={salary}
  onChange={(e) => setSalary(e.target.value)}
  className="border p-2 rounded w-full"
  required
 />
</div>
<div>
 <label className="block text-lg mb-1">Category:</label>
 <select
  value={categoryId}
  onChange={(e) => setCategoryId(e.target.value)}
  className="border p-2 rounded w-full"
  required
 >
      <option value="">Select a category</option>
      {categories.map(category => (
       <option key={category.id}
value={category.id}>{category.name}</option>
      ))}
     </select>
    </div>
    <div>
     <label className="block text-lg mb-1">Profile Image:</label>
     <input
      type="file"
      onChange={(e) => setImage(e.target.files[0])}
      className="border p-2 rounded w-full"
     />
    </div>
    <div>
     <label className="block text-lg mb-1">Capture Face:</label>
     {!isCameraOn ? (
      <button
          type="button"
  className="bg-blue-500 text-white px-4 py-2 rounded"
  onClick={startCamera}
  disabled={!isModelLoaded}
 >
  Start Camera
 </button>
):(
 <div>
  <button
      type="button"
      className="bg-green-500 text-white px-4 py-2 rounded mr-2"
      onClick={captureFace}
  >
      Capture Face
  </button>
  <button
      type="button"
      className="bg-red-500 text-white px-4 py-2 rounded"
      onClick={stopCamera}
  >
          Stop Camera
      </button>
     </div>
 )}
</div>
{isCameraOn && (
 <div className="relative mb-4">
     <video
      ref={videoRef}
      autoPlay
      className="border rounded"
      width="640"
      height="480"
     />
 </div>
)}
<button
 type="submit"
 className="bg-green-500 text-white px-4 py-2 rounded"
>
        Add Employee
       </button>
      </form>
     </div>
 );
};
export default AddEmployee;
AttendanceSystem.jsx
import React, { useState, useEffect, useRef } from 'react';
import * as faceapi from 'face-api.js';
import axios from 'axios';
import Cookies from 'js-cookie';
const AttendanceSystem = () => {
 const [employees, setEmployees] = useState([]);
 const [attendanceRecords, setAttendanceRecords] = useState([]);
 const [selectedEmployee, setSelectedEmployee] = useState(null);
 const [isCameraOn, setIsCameraOn] = useState(false);
 const [isModelLoaded, setIsModelLoaded] = useState(false);
const videoRef = useRef(null);
const canvasRef = useRef(null);
// Load face-api.js models
useEffect(() => {
 const loadModels = async () => {
   try {
       await Promise.all([
        faceapi.nets.tinyFaceDetector.loadFromUri('/models'),
        faceapi.nets.faceLandmark68Net.loadFromUri('/models'),
        faceapi.nets.faceRecognitionNet.loadFromUri('/models'),
       ]);
       setIsModelLoaded(true);
   } catch (error) {
       console.error('Error loading models:', error);
 };
 loadModels();
}, []);
 // Fetch employees
 useEffect(() => {
  const fetchEmployees = async () => {
    try {
    const response = await
axios.get('http://localhost:3000/auth/employee', {
            headers: { Authorization: `Bearer ${Cookies.get('token')}` }
        });
        if (response.data.Status) {
            setEmployees(response.data.Result);
    } catch (error) {
        console.error('Error fetching employees:', error);
  };
  fetchEmployees();
 }, []);
 // Fetch attendance records
 useEffect(() => {
  const fetchAttendance = async () => {
    try {
    const response = await
axios.get('http://localhost:3000/auth/attendance', {
            headers: { Authorization: `Bearer ${Cookies.get('token')}` }
        });
        if (response.data.Status) {
            setAttendanceRecords(response.data.Result);
    } catch (error) {
        console.error('Error fetching attendance:', error);
  };
  fetchAttendance();
 }, []);
 // Start webcam
 const startCamera = async () => {
  try {
   const stream = await navigator.mediaDevices.getUserMedia({ video:
true });
      videoRef.current.srcObject = stream;
      setIsCameraOn(true);
  } catch (error) {
      console.error('Error accessing webcam:', error);
 };
 // Stop webcam
 const stopCamera = () => {
  if (videoRef.current && videoRef.current.srcObject) {
   videoRef.current.srcObject.getTracks().forEach(track =>
track.stop());
  setIsCameraOn(false);
 };
 // Capture and recognize face for attendance
 const captureAttendance = async () => {
  if (!isModelLoaded || !selectedEmployee || !videoRef.current)
return;
  const detections = await faceapi
   .detectSingleFace(videoRef.current, new
faceapi.TinyFaceDetectorOptions())
   .withFaceLandmarks()
   .withFaceDescriptor();
  if (detections) {
   try {
    // Fetch stored descriptors for the employee
    const response = await axios.get(
      `http://localhost:3000/auth/face_descriptors/$
{selectedEmployee.id}`,
         headers: { Authorization: `Bearer ${Cookies.get('token')}` }
    );
    if (!response.data.Status || response.data.Result.length === 0) {
        alert('No face descriptor found for this employee!');
        return;
    const descriptors = response.data.Result.map(d => new
Float32Array(d.descriptor));
    const labeledDescriptors = descriptors.map(
     d => new
faceapi.LabeledFaceDescriptors(selectedEmployee.id.toString(), [d])
    );
    const faceMatcher = new
faceapi.FaceMatcher(labeledDescriptors);
    // Find best match
    const match = faceMatcher.findBestMatch(detections.descriptor);
   const isMatch = match.label === selectedEmployee.id.toString() &&
match.distance < 0.6;
    if (isMatch) {
        const today = new Date().toISOString().split('T')[0];
        const attendanceResponse = await axios.post(
 'http://localhost:3000/auth/attendance',
     employeeId: selectedEmployee.id,
     date: today,
     status: 'Present',
 },
     headers: { Authorization: `Bearer ${Cookies.get('token')}` }
);
if (attendanceResponse.data.Status) {
 setAttendanceRecords([
     ...attendanceRecords,
         id: Date.now(),
         employee_id: selectedEmployee.id,
         name: selectedEmployee.name,
         date: today,
         status: 'Present',
                   },
                  ]);
                  alert(`Attendance marked for ${selectedEmployee.name}`);
                  stopCamera();
              } else {
      alert('Failed to mark attendance: ' +
attendanceResponse.data.Error);
          } else {
              alert('Face not recognized!');
      } catch (error) {
          console.error('Error capturing attendance:', error);
          alert('Failed to mark attendance');
  } else {
      alert('No face detected!');
 };
 return (
  <div className="container mx-auto p-4">
   <h1 className="text-3xl font-bold mb-4">Employee Attendance
System</h1>
   {/* Employee Selection */}
   <div className="mb-4">
    <label className="block text-lg mb-2">Select Employee:</label>
    <select
     className="border p-2 rounded"
     onChange={(e) => {
      const employee = employees.find(emp => emp.id ===
parseInt(e.target.value));
        setSelectedEmployee(employee);
     }}
    >
     <option value="">Select an employee</option>
     {employees.map(employee => (
      <option key={employee.id}
value={employee.id}>{employee.name}</option>
     ))}
 </select>
</div>
{/* Webcam Controls */}
<div className="mb-4">
 {!isCameraOn ? (
  <button
   className="bg-blue-500 text-white px-4 py-2 rounded"
   onClick={startCamera}
   disabled={!selectedEmployee || !isModelLoaded}
  >
   Start Camera
  </button>
 ):(
  <div>
   <button
       className="bg-green-500 text-white px-4 py-2 rounded mr-2"
       onClick={captureAttendance}
   >
       Capture Attendance
      </button>
      <button
       className="bg-red-500 text-white px-4 py-2 rounded"
       onClick={stopCamera}
      >
       Stop Camera
      </button>
  </div>
 )}
</div>
{/* Webcam Feed */}
{isCameraOn && (
 <div className="relative mb-4">
  <video
      ref={videoRef}
      autoPlay
      className="border rounded"
      width="640"
      height="480"
        />
        <canvas
         ref={canvasRef}
         className="absolute top-0 left-0"
         width="640"
         height="480"
        />
    </div>
   )}
   {/* Attendance Records */}
   <h2 className="text-2xl font-semibold mb-2">Attendance
Records</h2>
   <table className="w-full border-collapse border">
    <thead>
        <tr className="bg-gray-200">
         <th className="border p-2">Employee</th>
         <th className="border p-2">Date</th>
         <th className="border p-2">Status</th>
        </tr>
       </thead>
       <tbody>
        {attendanceRecords.map(record => (
         <tr key={record.id}>
          <td className="border p-2">{record.name}</td>
          <td className="border p-2">{record.date}</td>
          <td className="border p-2">{record.status}</td>
         </tr>
        ))}
       </tbody>
      </table>
     </div>
 );
};
export default AttendanceSystem;
App.jsx
import   React from 'react';
import   { BrowserRouter, Route, Routes } from 'react-router-dom';
import   AttendanceSystem from './components/AttendanceSystem';
import   AddEmployee from './components/AddEmployee';
function App() {
    return (
       <BrowserRouter>
         <div className="min-h-screen bg-gray-100">
           <Routes>
             <Route path="/attendance" element={<AttendanceSystem />} />
             <Route path="/add-employee" element={<AddEmployee />} />
           </Routes>
         </div>
       </BrowserRouter>
    );
}
export default App;