User Check-In Check-Out System with AJAX, PHP, JavaScript, and MySQL

0
Building a User Check-In Check-Out System

Introduction

In the digital age, managing physical spaces efficiently has become a necessity. Whether it’s for coworking spaces, offices, or shared amenities in residential buildings, having a system to track who is present at any given time is valuable. This blog post explores a script that allows us to create a user check-in/check-out system. This system could be used in a variety of environments that require managing and tracking user presence.

The technologies we use include AJAX, PHP, JavaScript, and MySQL. AJAX allows us to update parts of the webpage without reloading the whole page, PHP is used for server-side scripting, JavaScript powers the client-side interactivity, and MySQL is used for database management.

You can access the system here

Test building code: Demo

How It Works

The script works in the following way:

  1. User Authentication: When users first visit the webpage, they are asked to enter a building code. This building code is then stored in the browser sessionStorage for persistence across page reloads and sessions.
  2. User Lists: The webpage displays two lists of users – those currently in the building (checked in) and those not (checked out).
  3. Check-In/Check-Out: Each user in the list is accompanied by two buttons – one for checking in and one for checking out. Users are moved to the “checked-in” list when they check in. They are moved to the “checked-out” list when they check out. Thanks to AJAX, these changes are updated in real-time on the webpage without requiring a page reload.
  4. Adding Users: The webpage also includes a form for adding new users to the system. This new user is added to the “checked-out” list until they check in.
  5. Deleting Users: Each user has a delete button next to their name. Clicking this button removes the user from the system entirely.

How to Use It

To use the system, follow the steps below:

  1. Visit the webpage and enter your building code. You can use the code Demo to trial the system.
  2. If you are a new user, fill in your name in the “Add User” form and click the “Add User” button.
  3. To check-in, find your name in the “Checked-Out” list and click the “Check In” button next to your name.
  4. To check out, find your name in the “Checked-In” list and click the “Check Out” button next to your name.
  5. To delete your user from the system, click the “Delete” button next to your name.

The files/code

You can find the full code below a download a copy from here

MySQL

-- Create the database
CREATE DATABASE IF NOT EXISTS CheckInOutDB;
USE CheckInOutDB;

-- Create the buildings table
CREATE TABLE IF NOT EXISTS buildings (
    id INT AUTO_INCREMENT PRIMARY KEY,
    code VARCHAR(255) NOT NULL,
    name VARCHAR(255) NOT NULL
);

-- Create the users table
CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    building_id INT NOT NULL,
    is_present BOOLEAN NOT NULL DEFAULT FALSE,
    FOREIGN KEY (building_id) REFERENCES buildings(id)
);

Here, we are creating two tables, buildings and users. The buildings table has an id, a code, and a name. The users table has an id, name, building_id (which references the id in the buildings table), and is_present (which is a boolean indicating whether the user is checked in or not).

This database structure allows for multiple buildings each having their own set of users. Users are associated with a building through the building_id foreign key.

Remember to replace CheckInOutDB with the name of the database you want to use, and adjust the column types and sizes as needed for your specific use case.

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
    <meta http-equiv="Pragma" content="no-cache" />
    <meta http-equiv="Expires" content="0" />
    <title>Check-in / Check-out Board</title>
    <link rel="stylesheet" href="styles.css">
</head>

<body>
    <div id="wrapper">
        <h1>Check-in / Check-out Board</h1>
        <div id="users-container">
            <div id="users-present-container">
                <h2>Users Present</h2>
                <ul id="users-present"></ul>
            </div>
            <div id="users-absent-container">
                <h2>Users Absent</h2>
                <ul id="users-absent"></ul>
            </div>
        </div>
        <div id="add-user-form">
            <input type="text" id="new-user-name" placeholder="Enter new user's name">
            <button class="checkin-btn" onclick="addUser()">Add User</button>
        </div>
        
    </div>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="main.js"></script>
</body>

</html>

api.php

<?php
// Replace these values with your database credentials
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "CheckInOutDB";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection
if ($conn->connect_error) {
    die(json_encode(['error' => 'Failed to connect to the database']));
}


header('Content-Type: application/json');

$action = $_REQUEST['action'] ?? '';

switch ($action) {
    case 'get_building_id':
        get_building_id($conn);
        break;
    case 'get_users':
        get_users($conn);
        break;
    case 'add_user':
        add_user($conn);
        break;
    case 'check_in_out':
        check_in_out($conn);
        break;
    case 'delete_user':
        delete_user($conn);
        break;
    default:
        echo json_encode(['error' => 'Invalid action']);
        break;
}

function get_building_id($conn) {
    $code = $_GET['code'] ?? '';

    if (empty($code)) {
        echo json_encode(['error' => 'Invalid building code']);
        return;
    }

    $sql = "SELECT id FROM buildings WHERE code = ?";
    $stmt = $conn->prepare($sql);
    $stmt->bind_param("s", $code);
    $stmt->execute();
    $result = $stmt->get_result();

    if ($result->num_rows > 0) {
        $row = $result->fetch_assoc();
        echo json_encode(['id' => $row['id']]);
    } else {
        echo json_encode(['error' => 'Invalid building code']);
    }
}

function get_users($conn) {
    $building_id = $_GET['building_id'] ?? '';

    if (empty($building_id)) {
        echo json_encode(['error' => 'Invalid building ID']);
        return;
    }

    $sql_present = "SELECT id, name, is_present FROM users WHERE building_id = ? AND is_present = 1";
    $sql_absent = "SELECT id, name, is_present FROM users WHERE building_id = ? AND is_present = 0";

    $stmt_present = $conn->prepare($sql_present);
    $stmt_present->bind_param("i", $building_id);
    $stmt_present->execute();
    $result_present = $stmt_present->get_result()->fetch_all(MYSQLI_ASSOC);

    $stmt_absent = $conn->prepare($sql_absent);
    $stmt_absent->bind_param("i", $building_id);
    $stmt_absent->execute();
    $result_absent = $stmt_absent->get_result()->fetch_all(MYSQLI_ASSOC);

    echo json_encode(['present' => $result_present, 'absent' => $result_absent]);
}

function add_user($conn) {
    $name = $_GET['name'] ?? '';
    $building_id = $_GET['building_id'] ?? '';

    if (empty($name) || empty($building_id)) {
        echo json_encode(['error' => 'Invalid user data']);
        return;
    }

    $sql = "INSERT INTO users (name, building_id) VALUES (?, ?)";
    $stmt = $conn->prepare($sql);
    $stmt->bind_param("si", $name, $building_id);

    if ($stmt->execute()) {
       
echo json_encode(['success' => true]);
    } else {
        echo json_encode(['error' => 'Failed to add user']);
    }
}

function check_in_out($conn) {
    $user_id = $_POST['user_id'] ?? '';
    $is_present = $_POST['is_present'] ?? '';

    if (empty($user_id)) {
        echo json_encode(['error' => 'Invalid user ID']);
        return;
    }

    $sql = "UPDATE users SET is_present = ? WHERE id = ?";
    $stmt = $conn->prepare($sql);
    $stmt->bind_param("ii", $is_present, $user_id);

    if ($stmt->execute()) {
        echo json_encode(['success' => true]);
    } else {
        echo json_encode(['error' => 'Failed to update user status']);
    }
}

function delete_user($conn) {
    $user_id = $_POST['user_id'] ?? '';

    if (empty($user_id)) {
        echo json_encode(['error' => 'Invalid user ID']);
        return;
    }

    $sql = "DELETE FROM users WHERE id = ?";
    $stmt = $conn->prepare($sql);
    $stmt->bind_param("i", $user_id);

    if ($stmt->execute()) {
        echo json_encode(['success' => true]);
    } else {
        echo json_encode(['error' => 'Failed to delete user']);
    }
}

$conn->close();

main.js

let currentBuildingId = sessionStorage.getItem('buildingId');

function showLoading() {
    $('#loading').show();
}

function hideLoading() {
    $('#loading').hide();
}

function showError(message) {
    $('#error-message').text(message);
    $('#error-message').show();
}

function hideError() {
    $('#error-message').text('');
    $('#error-message').hide();
}

function getUsers() {
    if (!currentBuildingId) {
        showError('Invalid building code. Please enter a valid building code.');
        return;
    }

    $.ajax({
        url: 'api.php',
        method: 'GET',
        cache: false,
        data: {
            action: 'get_users',
            building_id: currentBuildingId,
        },
        dataType: 'json',
        beforeSend: function() {
            showLoading();
        },
        success: function(response) {
            hideLoading();
            if (response.error) {
                showError(response.error);
            } else {
                populateUserLists(response.present, $('#users-present'));
                populateUserLists(response.absent, $('#users-absent'));
            }
        },
        error: function() {
            hideLoading();
            showError('Failed to fetch user data. Please try again.');
        },
    });
}

function populateUserLists(users, listElement) {
    listElement.empty();
    users.forEach(function(user) {
        const listItem = $('<li></li>');
        listItem.text(user.name);

        const checkInOutBtn = $('<button></button>');
        checkInOutBtn.text(user.is_present ? 'Check Out' : 'Check In');
        checkInOutBtn.addClass(user.is_present ? 'checkout-btn' : 'checkin-btn');
        checkInOutBtn.click(function() {
            checkInOutUser(user.id, !user.is_present);
        });

        const deleteBtn = $('<button>Delete</button>');
        deleteBtn.addClass('delete-btn');
        deleteBtn.click(function() {
            deleteUser(user.id);
        });

        listItem.append(' ', checkInOutBtn, ' ', deleteBtn);
        listElement.append(listItem);
    });
}

function checkInOutUser(userId, isPresent) {
    $.ajax({
        url: 'api.php',
        method: 'POST',
        cache: false,
        data: {
            action: 'check_in_out',
            user_id: userId,
            is_present: isPresent ? 1 : 0,
        },
        dataType: 'json',
        beforeSend: function() {
            showLoading();
        },
        success: function(response) {
            hideLoading();
            if (response.error) {
                showError(response.error);
            } else {
                getUsers();
            }
        },
        error: function() {
            hideLoading();
            showError('Failed to update user status. Please try again.');
        },
    });
}

function deleteUser(userId) {
    $.ajax({
        url: 'api.php',
        method: 'POST',
        cache: false,
        data: {
            action: 'delete_user',
            user_id: userId,
        },
        dataType: 'json',
        beforeSend: function() {
            showLoading();
        },
        success: function(response) {
            hideLoading();
            if (response.error) {
                showError(response.error);
            } else {
                getUsers();
            }
        },
        error: function() {
            hideLoading();
            showError('Failed to delete user. Please try again.');
        },
    });
}

function addUser() {
    const inputField = document.getElementById("new-user-name");
    const name = inputField.value.trim();
    
    if (name === "") {
        alert("Please enter a user's name.");
        return;
    }
    
    inputField.value = "";

    const buildingId = sessionStorage.getItem("buildingId");
    
    fetch(`api.php?action=add_user&name=${encodeURIComponent(name)}&building_id=${buildingId}`, {
        method: "POST",
    })
    .then((response) => {
        if (response.ok) {
            return response.json();
        } else {
            throw new Error("Error adding user.");
        }
    })
    .then((data) => {
        if (data.success) {
            populateUserLists();
        } else {
            alert("Error adding user.");
        }
    })
    .catch((error) => {
        console.error("Error:", error);
    });
}



function getBuildingId(code) {
    $.ajax({
        url: 'api.php',
        method: 'GET',
        cache: false,
        data: {
            action: 'get_building_id',
            code: code,
        },
        dataType: 'json',
        beforeSend: function() {
            showLoading();
        },
        success: function(response) {
            hideLoading();
            if (response.error) {
                showError(response.error);
            } else {
                currentBuildingId = response.id;
                sessionStorage.setItem('buildingId', currentBuildingId);
                getUsers();
            }
        },
        error: function() {
            hideLoading();
            showError('Failed to fetch building data. Please try again.');
        },
    });
}

$(document).ready(function() {
    if (currentBuildingId) {
        getUsers();
    } else {
        const code = prompt("Enter Building Code:");
        if (code) {
            getBuildingId(code);
        } else {
            showError("You must enter a building code to proceed.");
        }
    }

    $('#new-user-form').submit(function(event) {
        event.preventDefault();
        const name = $('#new-user-input').val();
        addUser(name);
        $('#new-user-input').val('');
    });
});

styles.css

body {
    font-family: 'Roboto', Arial, sans-serif;
    background-color: #F5F5F5;
    margin: 0;
    padding: 0;
}

#wrapper {
    max-width: 800px;
    margin: 0 auto;
    padding: 20px;
    background-color: #fff;
    border-radius: 5px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

h1 {
    text-align: center;
    margin-bottom: 30px;
    color: #fff;
    background-color: #4CAF50;
    padding: 10px 0;
    border-radius: 5px;
}

#users-container {
    display: flex;
    justify-content: space-between;
}

#users-present-container,
#users-absent-container {
    flex-basis: 48%;
}

ul {
    list-style-type: none;
    padding: 0;
}

li {
    background-color: #f9f9f9;
    padding: 10px;
    margin-bottom: 5px;
    border-radius: 5px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

button {
    cursor: pointer;
    border: none;
    padding: 5px 10px;
    border-radius: 5px;
    font-weight: bold;
}

button.checkin-btn {
    background-color: #4CAF50; /* Green */
    color: white;
    margin-right: 5px;
}

button.checkout-btn {
    background-color: #007BFF; /* Blue */
    color: white;
    margin-right: 5px;
}

button.delete-btn {
    background-color: #FF0000; /* Red */
    color: white;
}

#add-user-form {
    margin-top: 20px;
    text-align: center;
}

#new-user-name {
    padding: 5px;
    width: 60%;
    margin-right: 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
}

button[type="submit"] {
    background-color: #007BFF; /* Blue */
    color: white;
    cursor: pointer;
    border: none;
    padding: 5px 10px;
    border-radius: 5px;
    font-weight: bold;
}

Conclusion

This check-in/check-out system is a practical tool for managing user presence in physical spaces. It can be used in a variety of settings and is flexible to adapt to specific needs. The use of AJAX, PHP, JavaScript, and MySQL makes it a powerful, efficient, and real-time system. Happy coding!

Please note that this is a simple system and doesn’t incorporate advanced features like user authentication and encryption, which are important for real-world applications. Always ensure you follow best practices for security when developing web applications.

Found priceless insights in this blog? Support the author’s creativity – buy them a coffee!

Leave a Reply

Your email address will not be published. Required fields are marked *