laravel-jquery-pos-ajax-crud

Laravel jQuery POS Tutorial – Part 4/8: Ajax Menu & CRUD

Introduction

In this Laravel jQuery POS Ajax CRUD tutorial, you’ll add powerful interactivity with jQuery and Ajax to manage system data dynamically.

In this part, we’ll bring your POS system to life with dynamic Ajax-powered menu navigation and CRUD functionality for managing system data like products, categories, and tables. You’ll learn how to switch between views without refreshing the page and build reusable components for a faster and cleaner user experience.

By the end of this tutorial, your project will support seamless screen switching and fully functional Create, Read, Update, and Delete operations—laying the foundation for day-to-day POS tasks.

In this part of the tutorial, we’ll focus on building CRUD functionality for the key data used in our POS system. You’ll learn how to manage the following:

  • Tables (for dine-in orders)
  • Product Categories
  • Products
  • Balance Adjustments
  • System Users

Each of these will include Create, Read, Update, and Delete operations using Laravel and Ajax—making your POS system dynamic and fully manageable from the admin interface.

Create Ajax Navigation & CRUD

Set up a global jQuery function that loads different screens into a main content area using Ajax. This allows you to navigate between pages like Dashboard, Products, or Reports without full-page reloads, giving the app a smooth single-page feel.

Replace the contents of resources/js/app.js with the code below. If the file doesn’t exist yet, please create it.

// Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com
import './bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap-icons/font/bootstrap-icons.min.css';
import '../css/style.css';
import '../css/app.css';
import * as bootstrap from 'bootstrap';
import jQuery from 'jquery';
import XlsxPopulate from "xlsx-populate/browser/xlsx-populate";
import flatpickr from "flatpickr";
import "flatpickr/dist/flatpickr.min.css";
import ApexCharts from 'apexcharts';
window.bootstrap = bootstrap;
window.XlsxPopulate = XlsxPopulate;
window.$ = jQuery;
window.ApexCharts = ApexCharts;

document.addEventListener('DOMContentLoaded', function () {
    $("body").show();
    // Easy selector helper function
    const select = (el, all = false) => {
        el = el.trim()
        if (all) {
            return [...document.querySelectorAll(el)]
        } else {
            return document.querySelector(el)
        }
    }

    //   Easy event listener function
    const on = (type, el, listener, all = false) => {
        if (all) {
            select(el, all).forEach(e => e.addEventListener(type, listener))
        } else {
            select(el, all).addEventListener(type, listener)
        }
    }

    //  Easy on scroll event listener 
    const onscroll = (el, listener) => {
        el.addEventListener('scroll', listener)
    }

    // Sidebar toggle
    if (select('.toggle-sidebar-btn')) {
        on('click', '.toggle-sidebar-btn', function (e) {
            select('body').classList.toggle('toggle-sidebar')
        })
    }

    //    Navbar links active state on scroll
    let navbarlinks = select('#navbar .scrollto', true)
    const navbarlinksActive = () => {
        let position = window.scrollY + 200
        navbarlinks.forEach(navbarlink => {
            if (!navbarlink.hash) return
            let section = select(navbarlink.hash)
            if (!section) return
            if (position >= section.offsetTop && position <= (section.offsetTop + section.offsetHeight)) {
                navbarlink.classList.add('active')
            } else {
                navbarlink.classList.remove('active')
            }
        })
    }
    window.addEventListener('load', navbarlinksActive)
    onscroll(document, navbarlinksActive)

    //   Toggle .header-scrolled class to #header when page is scrolled
    let selectHeader = select('#header')
    if (selectHeader) {
        const headerScrolled = () => {
            if (window.scrollY > 100) {
                selectHeader.classList.add('header-scrolled')
            } else {
                selectHeader.classList.remove('header-scrolled')
            }
        }
        window.addEventListener('load', headerScrolled)
        onscroll(document, headerScrolled)
    }

    $(function () {
        $(window).on("hashchange", function () {
            hashChange();
        });
        hashChange();
    });

    window.hashChange = function () {
        const url = window.location.hash;
        let hash = url.split('?')[0];

        if (!hash) hash = "#dashboard";
        $("ul#sidebar-nav a.nav-link").each(function () {
            var nav = hash;
            var pos = hash.indexOf("/");
            if (pos > 0) nav = hash.substring(0, pos);
            if (nav == "#report") nav = hash;
            $(this)[$(this).attr("href") === nav ? "removeClass" : "addClass"](
                "collapsed"
            );
        });

        ajaxLoad(hash.replace("#", ""));
    };

    const formModalId = document.getElementById("formModal");
    const formModal = new bootstrap.Modal(formModalId);
    if (formModalId) {
        formModalId.addEventListener("shown.bs.modal", (event) => {
            $("#autofocus").trigger("focus").trigger("select");
        });
        formModalId.addEventListener("hide.bs.modal", (event) => {
            document.activeElement?.blur();
        });
    }

    const deleteModal = document.getElementById("confirmDelete");
    if (deleteModal) {
        deleteModal.addEventListener("show.bs.modal", (event) => {
            var data = $(event.relatedTarget).data();
            $("input#delete_id").val(data.recordId);
            document.querySelector('form#deleteForm').action = data.recordUrl;
        });
        deleteModal.addEventListener("hide.bs.modal", (event) => {
            document.activeElement?.blur();
        });
    }

    const errorModalId = document.getElementById("errorModal");
    const errorModal = new bootstrap.Modal(errorModalId);
    if (errorModalId) {
        errorModalId.addEventListener("hide.bs.modal", (event) => {
            document.activeElement?.blur();
        });
    }

    const successModalId = document.getElementById("successModal");
    const successModal = new bootstrap.Modal(successModalId);
    if (successModalId) {
        successModalId.addEventListener("hide.bs.modal", (event) => {
            document.activeElement?.blur();
        });
    }

    $(document).on("click", "a.page-link", function (event) {
        event.preventDefault();
        ajaxLoad($(this).attr("href"));
    });

    $(document).on("submit", "form#submitForm", function (event) {
        event.preventDefault();
        $(".loading").show();
        var form = $(this);
        var data = new FormData(form[0]);
        var url = form.attr("action");
        $.ajaxSetup({
            headers: {
                "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content"),
            },
        });
        $.ajax({
            type: "POST",
            url: url,
            data: data,
            cache: false,
            contentType: false,
            processData: false,
            success: function (data) {
                $(".is-invalid").removeClass("is-invalid");
                $("span.invalid-feedback").remove();
                if (!data.success) {
                    for (var control in data.errors) {
                        $("[name='" + control + "']").addClass("is-invalid");
                        $("<span class='invalid-feedback'>" + data.errors[control] + "</span>").insertAfter($("[name='" + control + "']"));
                        $("#autofocus").trigger("focus");
                    }
                } else {
                    formModal.hide();
                    $('.modal-body p', successModalId).text("Data has been saved successfully");
                    successModal.show();
                    if (data.redirect_url) {
                        ajaxLoad(data.redirect_url);
                    }
                }
                $(".loading").hide();
            },
            error: function (xhr, textStatus, errorThrown) {
                showError(xhr.responseJSON.message);
            },
        });
        return false;
    });

    $(document).on("submit", "form#deleteForm", function (event) {
        event.preventDefault();
        $(".loading").show();
        var form = $(this);
        var data = new FormData(form[0]);
        var url = form.attr("action");
        $.ajaxSetup({
            headers: {
                "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content"),
            },
        });
        $.ajax({
            type: "POST",
            url: url,
            data: data,
            cache: false,
            contentType: false,
            processData: false,
            success: function (data) {
                $("#content").html(data);
                $(".loading").hide();
            },
            error: function (xhr, textStatus, errorThrown) {
                showError(xhr.responseJSON.message);
            },
        });
        return false;
    });

    window.ajaxLoad = function (filename, content) {
        content = typeof content !== "undefined" ? content : "content";
        $(".loading").show();
        $.ajax({
            type: "GET",
            url: filename,
            contentType: false,
            success: function (data) {
                $("#" + content).html(data);
            },
            error: function (xhr, status, error) {
                showError(xhr.responseJSON.message);
            },
            complete: function () {
                $(".loading").hide();
            }
        });
    };

    window.ajaxPopup = function (url, bigModal = false) {
        $(".loading").show();
        $.ajax({
            type: "GET",
            url: url,
            contentType: false,
            success: function (data) {
                if (bigModal)
                    $("#formModal .modal-dialog").removeClass('modal-lg').addClass('modal-lg');
                else
                    $("#formModal .modal-dialog").removeClass('modal-lg');
                $("#formModal .modal-content").html(data);
                $(".loading").hide();
                formModal.show();
            },
            error: function (xhr, status, error) {
                showError(xhr.responseJSON.message);
            },
        });
    };

    window.validateFile = (event, maxFileSize = 1, validFileExtension = [".jpg", ".jpeg", ".bmp", ".gif",
        ".png",
        ".webp"
    ]) => {
        var file = null;
        var files = event.files;
        if (files && files.length > 0) {
            $("input[name=image]").next('span').remove();
            var filesize = ((files[0].size / 1024) / 1024).toFixed(4); // MB
            if (filesize <= maxFileSize) {
                var blnValid = false;
                for (var j = 0; j < validFileExtension.length; j++) {
                    var sCurExtension = validFileExtension[j];
                    if (files[0].name.substr(files[0].name.length - sCurExtension.length, sCurExtension
                        .length)
                        .toLowerCase() == sCurExtension.toLowerCase()) {
                        blnValid = true;
                        break;
                    }
                }

                files[0].name.substr(files[0].name.length - sCurExtension.length, sCurExtension.length)
                var fileName = files[0].name.substr(0, files[0].name.length - sCurExtension.length)
                    .trim();
                fileName = fileName.replace(/[^a-zA-Z0-9-_\s]/g, '');

                if (fileName != files[0].name.substr(0, files[0].name.length - sCurExtension.length)) {
                    $("input[name=image]").addClass("is-invalid");
                    $("<span class='invalid-feedback'>Invalid filename. Filename only allow alphanumeric chatacters.</span>").insertAfter($("input[name=image]"));
                    event.value = '';
                } else if (blnValid) {
                    file = files[0];
                } else {
                    $("input[name=image]").addClass("is-invalid");
                    $("<span class='invalid-feedback'>" + files[0].name +
                        " is invalid, allowed extensions are:" +
                        validFileExtension.join(", ") + "</span>").insertAfter($("input[name=image]"));
                    event.value = '';
                }
            } else {
                if (maxFileSize < 1) {
                    $("input[name=image]").addClass("is-invalid");
                    $("<span class='invalid-feedback'>Maximum file size is " + (maxFileSize * 1000).toString() + "KB.</span>").insertAfter($("input[name=image]"));
                    event.value = '';
                } else {
                    $("input[name=image]").addClass("is-invalid");
                    $("<span class='invalid-feedback'>Maximum file size is " + maxFileSize.toString() + "MB.</span>").insertAfter($("input[name=image]"));
                    event.value = '';
                }
            }
        }
        return file;
    };

    window.removeProfile = () => {
        $('#img_preview').attr('src', 'images/default.png');
        $("#is_deleted_image").val(1);
    };

    $(document).on("change", "#image", function (event) {
        if ($(this).val() != '') {
            var selectedFile = validateFile(this, 1, [".jpg", ".jpeg", ".bmp", ".gif", ".png",
                ".webp"
            ]);
            if (selectedFile) {
                var reader = new FileReader();
                reader.onload = function (e) {
                    $('#img_preview').attr('src', e.target.result);
                }
                reader.readAsDataURL(selectedFile);
            }
        }
    });

    $(document).on("submit", "form#search_form", function (event) {
        event.preventDefault();
        const form = event.target;
        const formData = new FormData(form);
        const queryString = new URLSearchParams(formData).toString();
        const url = form.getAttribute("action") + "?" + queryString;
        ajaxLoad(url);
    });

    window.showError = (msg) => {
        $('.modal-body p', errorModalId).text(msg);
        errorModal.show();
    }
});

Setup Model for Laravel jQuery POS Ajax CRUD Operations

Define Eloquent models for your system data—such as Product, Category, Table, and System User. These models handle database interactions and define the structure of each data entity.

Replace the contents of app/Models/Table.php with the code below. If the file doesn’t exist yet, please create it.

<?php
// Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Table extends Model
{
    use SoftDeletes;
}

Replace the contents of app/Models/ProductCategory.php with the code below. If the file doesn’t exist yet, please create it.

<?php
// Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class ProductCategory extends Model
{
    use SoftDeletes;
}

Replace the contents of app/Models/Product.php with the code below. If the file doesn’t exist yet, please create it.

<?php
// Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Product extends Model
{
    use SoftDeletes;

    public function product_category()
    {
        return $this->belongsTo(ProductCategory::class);
    }
}

Replace the contents of app/Models/BalanceAdjustment.php with the code below. If the file doesn’t exist yet, please create it.

<?php
// Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class BalanceAdjustment extends Model
{
    use SoftDeletes;
}

Update this file app/Models/User.php and add SoftDeletes in.

<?php
// Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com
namespace App\Models;

use Illuminate\Database\Eloquent\SoftDeletes;

class User extends Authenticatable
{
    use HasFactory, Notifiable, SoftDeletes;
}

Setup Controller to Handle Laravel jQuery POS Ajax CRUD Requests

Create controllers to handle the logic for listing, adding, editing, and deleting data. Each controller method returns a view that will be loaded via Ajax into the interface.

Replace the contents of app/Http/Controllers/TableController.php with the code below. If the file doesn’t exist yet, please create it.

<?php
// Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com
namespace App\Http\Controllers;

use App\Models\Table;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;

class TableController extends Controller
{
    public function index(Request $request)
    {
        session()->put('table_name', $request->get('table_name', session('table_name')));
        session()->put('table_status', $request->get('table_status', session('table_status')));
        session()->put('table_field', $request->get('table_field', session('table_field', 'created_at')));
        session()->put('table_order', $request->get('table_order', session('table_order', 'desc')));

        $list = Table::when(session('table_name'), function ($query) {
            $query->where('name', 'like', '%' . session('table_name') . '%');
        })->when(session('table_status'), function ($query) {
            $query->where('status', '=', session('table_status'));
        })->orderBy(session('table_field'), session('table_order'))
            ->paginate(50);

        return view('table.index', compact('list'));
    }

    public function form($id = 0)
    {
        if ($id == 0)
            $data = null;
        else
            $data = Table::find($id);
        return view('table.form', compact('data'));
    }

    public function submit(Request $request)
    {
        // validation
        $rules = [
            'name' => 'required|unique:tables,name,' . $request->id,
            'status' => 'required',
        ];
        $validator = Validator::make($request->all(), $rules);
        if ($validator->fails())
            return response()->json([
                'success' => false,
                'errors' => $validator->errors()
            ]);

        // save to database
        if ($request->id > 0) {
            $data = Table::find($request->id);
        } else {
            $data = new Table();
            $data->created_by_id = Auth::id();
        }

        $data->updated_by_id = Auth::id();
        $data->name = $request->name;
        $data->status = $request->status;

        $data->save();
        return response()->json([
            'success' => true,
            'redirect_url' => url('table')
        ]);
    }

    public function delete(Request $request)
    {
        $data = Table::find($request->delete_id);
        $data->deleted_by_id = Auth::id();
        $data->delete();
        return redirect('table');
    }
}

Replace the contents of app/Http/Controllers/ProductCategoryController.php with the code below. If the file doesn’t exist yet, please create it.

<?php
// Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com
namespace App\Http\Controllers;

use App\Models\ProductCategory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;

class ProductCategoryController extends Controller
{
    public function index(Request $request)
    {
        session()->put('product_category_name', $request->get('product_category_name', session('product_category_name')));
        session()->put('product_category_field', $request->get('product_category_field', session('product_category_field', 'created_at')));
        session()->put('product_category_order', $request->get('product_category_order', session('product_category_order', 'desc')));

        $list = ProductCategory::when(session('product_category_name'), function ($query) {
            $query->where('name', 'like', '%' . session('product_category_name') . '%');
        })->orderBy(session('product_category_field'), session('product_category_order'))
            ->paginate(50);

        return view('product_category.index', compact('list'));
    }

    public function form($id = 0)
    {
        if ($id == 0)
            $data = null;
        else
            $data = ProductCategory::find($id);
        return view('product_category.form', compact('data'));
    }

    public function submit(Request $request)
    {
        // validation
        $rules = [
            'name' => 'required|unique:product_categories,name,' . $request->id
        ];
        $validator = Validator::make($request->all(), $rules);
        if ($validator->fails())
            return response()->json([
                'success' => false,
                'errors' => $validator->errors()
            ]);

        // save to database
        if ($request->id > 0) {
            $data = ProductCategory::find($request->id);
        } else {
            $data = new ProductCategory();
            $data->created_by_id = Auth::id();
        }
        $data->updated_by_id = Auth::id();
        $data->name = $request->name;
        $data->save();
        return response()->json([
            'success' => true,
            'redirect_url' => url('product-category')
        ]);
    }

    public function delete(Request $request)
    {
        $data = ProductCategory::find($request->delete_id);
        $data->deleted_by_id = Auth::id();
        $data->delete();
        return redirect('product-category');
    }
}

Replace the contents of app/Http/Controllers/ProductController.php with the code below. If the file doesn’t exist yet, please create it.

<?php
// Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com
namespace App\Http\Controllers;

use App\Models\Product;
use App\Models\ProductCategory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;

class ProductController extends Controller
{
    public function index(Request $request)
    {
        session()->put('product_name', $request->get('product_name', session('product_name')));
        session()->put('product_category', $request->get('product_category', session('product_category')));
        session()->put('product_field', $request->get('product_field', session('product_field', 'created_at')));
        session()->put('product_order', $request->get('product_order', session('product_order', 'desc')));

        // product list
        $list = Product::join('product_categories', 'product_categories.id', '=', 'products.product_category_id')
            ->when(session('product_name'), function ($query) {
                $query->where('products.name', 'like', '%' . session('product_name') . '%');
            })
            ->when(session('product_category'), function ($query) {
                $query->where('products.product_category_id', '=', session('product_category'));
            })
            ->select('products.id', 'products.name', 'products.image', 'products.unit_price', 'products.created_at', 'product_categories.name AS category_name')
            ->orderBy(session('product_field'), session('product_order'))
            ->paginate(50);

        // product category list
        $product_categories = ProductCategory::all(['id', 'name']);

        return view('product.index', compact('list', 'product_categories'));
    }

    public function form($id = 0)
    {
        if ($id == 0)
            $data = null;
        else
            $data = Product::find($id);
        // product category list
        $product_categories = ProductCategory::all(['id', 'name']);
        return view('product.form', compact('data', 'product_categories'));
    }

    public function submit(Request $request)
    {
        // validation
        $rules = [
            'image' => 'nullable|image|mimes:png,jpg,jpeg|max:1024',
            'name' => 'required|unique:products,name,' . $request->id,
            'product_category_id' => 'required',
            'unit_price' => 'required|numeric'
        ];
        $validator = Validator::make($request->all(), $rules, [], ['product_category_id' => 'product category']);
        if ($validator->fails())
            return response()->json([
                'success' => false,
                'errors' => $validator->errors()
            ]);

        // save to database
        if ($request->id > 0) {
            $data = Product::find($request->id);
        } else {
            $data = new Product();
            $data->created_by_id = Auth::id();
        }
        $data->updated_by_id = Auth::id();
        $data->name = $request->name;
        $data->product_category_id = $request->product_category_id;
        $data->unit_price = $request->unit_price;

        // delete uploaded file
        if ($request->is_deleted_image == 1 && $request->id > 0) {
            if (Storage::disk('public')->exists($data->image)) {
                Storage::disk('public')->delete($data->image);
            }
            $data->image = '';
        }
        // upload file
        else if ($request->hasFile('image')) {
            if ($data->image && Storage::disk('public')->exists($data->image)) {
                Storage::disk('public')->delete($data->image);
            }
            $data->image = Storage::disk('public')->put('product', $request->image);
        }

        $data->save();
        return response()->json([
            'success' => true,
            'redirect_url' => url('product')
        ]);
    }

    public function delete(Request $request)
    {
        $data = Product::find($request->delete_id);
        $data->deleted_by_id = Auth::id();
        // delete uploaded file
        if ($data->image && Storage::disk('public')->exists($data->image)) {
            Storage::disk('public')->delete($data->image);
        }
        $data->delete();
        return redirect('product');
    }
}

Replace the contents of app/Http/Controllers/BalanceAdjustmentController.php with the code below. If the file doesn’t exist yet, please create it.

<?php
// Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com
namespace App\Http\Controllers;

use App\Models\BalanceAdjustment;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;

class BalanceAdjustmentController extends Controller
{
    public function index(Request $request)
    {
        session()->put('balance_adjustment_remark', $request->get('balance_adjustment_remark', session('balance_adjustment_remark')));
        session()->put('balance_adjustment_type_id', $request->get('balance_adjustment_type_id', session('balance_adjustment_type_id', 0)));
        session()->put('balance_adjustment_fd', $request->get('balance_adjustment_fd', session('balance_adjustment_fd', date('Y-m-d'))));
        session()->put('balance_adjustment_td', $request->get('balance_adjustment_td', session('balance_adjustment_td', date('Y-m-d'))));
        session()->put('balance_adjustment_field', $request->get('balance_adjustment_field', session('balance_adjustment_field', 'created_at')));
        session()->put('balance_adjustment_order', $request->get('balance_adjustment_order', session('balance_adjustment_order', 'desc')));
        // product list
        $list = BalanceAdjustment::when(session('balance_adjustment_remark'), function ($query) {
            $query->where('remark', 'like', '%' . session('balance_adjustment_remark') . '%');
        })
            ->when(session('balance_adjustment_type_id') > 0, function ($query) {
                $query->where('type_id', '=', session('balance_adjustment_type_id'));
            })
            ->when(session('balance_adjustment_fd'), function ($query) {
                $query->where('updated_at', '>=', date('Y-m-d 00:00:00', strtotime(session('balance_adjustment_fd'))));
            })
            ->when(session('balance_adjustment_td'), function ($query) {
                $query->where('updated_at', '<=', date('Y-m-d 23:59:59', strtotime(session('balance_adjustment_td'))));
            })
            ->orderBy(session('balance_adjustment_field'), session('balance_adjustment_order'))
            ->paginate(50);

        return view('balance_adjustment.index', compact('list'));
    }

    public function form($id = 0)
    {
        if ($id == 0)
            $data = null;
        else
            $data = BalanceAdjustment::find($id);

        return view('balance_adjustment.form', compact('data'));
    }

    public function submit(Request $request)
    {
        // validation
        $rules = [
            'amount' => 'required|numeric',
            'type_id' => 'required',
            'adjusted_date' => 'required|date',
            'remark' => 'required',
        ];
        $validator = Validator::make($request->all(), $rules, [], ['type_id' => 'type']);
        if ($validator->fails())
            return response()->json([
                'success' => false,
                'errors' => $validator->errors()
            ]);

        // save to database
        if ($request->id > 0) {
            $data = BalanceAdjustment::find($request->id);
        } else {
            $data = new BalanceAdjustment();
            $data->created_by_id = Auth::id();
        }

        $data->updated_by_id = Auth::id();
        $data->amount = $request->amount;
        $data->type_id = $request->type_id;
        $data->adjusted_date = $request->adjusted_date;
        $data->remark = $request->remark;

        $data->save();
        return response()->json([
            'success' => true,
            'redirect_url' => url('balance-adjustment')
        ]);
    }

    public function delete(Request $request)
    {
        $data = BalanceAdjustment::find($request->delete_id);
        $data->deleted_by_id = Auth::id();
        $data->delete();
        return redirect('balance-adjustment');
    }
}

Replace the contents of app/Http/Controllers/UserController.php with the code below. If the file doesn’t exist yet, please create it.

<?php
// Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com
namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;

class UserController extends Controller
{
    /**
     * Handle an authentication attempt.
     */
    public function login(Request $request)
    {
        if ($request->isMethod('GET'))
            return view('user.login');

        // validation
        $rules = [
            'username' => 'required',
            'password' => 'required'
        ];
        $validator = Validator::make($request->all(), $rules);
        if ($validator->fails())
            return response()->json([
                'success' => false,
                'errors' => $validator->errors()
            ]);

        $credentials = [
            'username' => $request->username,
            'password' => $request->password,
            'active' => 1,
        ];

        if (Auth::attempt($credentials)) {
            $request->session()->regenerate();
            return response()->json([
                'success' => true,
                'redirect_url' => url('/')
            ]);
        }
        return response()->json([
            'success' => false,
            'errors' => [
                'username' => ['Incorrect username or password']
            ]
        ]);
    }

    /**
     * Log the user out of the application.
     */
    public function logout(Request $request)
    {
        Auth::logout();

        $request->session()->invalidate();
        $request->session()->regenerateToken();

        return redirect('/');
    }

    // Change password
    public function changePassword(Request $request)
    {
        if ($request->isMethod('GET'))
            return view('user.change_password');

        $rules = [
            'old_password' => [
                'required',
                function ($attribute, $value, $fail) use ($request) {
                    if (!Hash::check($value, $request->user()->password)) {
                        $fail('The old password is incorrect');
                    }
                }
            ],
            'new_password' => ['required', 'confirmed'],
        ];
        //validate data
        $validator = Validator::make($request->all(), $rules);
        if ($validator->fails())
            return response()->json([
                'success' => false,
                'errors' => $validator->errors()
            ]);

        // change the password
        $user = $request->user();
        $user->updated_at = now();
        $user->updated_by_id = $user->id;
        $user->password = bcrypt($request->new_password);
        $user->save();

        // redirect
        return response()->json([
            'success' => true,
            'redirect_url' => null
        ]);
    }

    public function index(Request $request)
    {
        session()->put('user_name', $request->get('user_name', session('user_name')));
        session()->put('user_role', $request->get('user_role', session('user_role')));
        session()->put('user_field', $request->get('user_field', session('user_field', 'created_at')));
        session()->put('user_order', $request->get('user_order', session('user_order', 'desc')));

        $list = User::when(session('user_name'), function ($query) {
            $query->where('username', 'like', '%' . session('user_name') . '%');
        })->when(session('user_role'), function ($query) {
            $query->where('role', '=', session('user_role'));
        })->orderBy(session('user_field'), session('user_order'))
            ->paginate(50);

        return view('user.index', compact('list'));
    }

    public function form($id = 0)
    {
        if ($id == 0)
            $data = null;
        else
            $data = User::find($id);
        return view('user.form', compact('data'));
    }

    public function submit(Request $request)
    {
        // validation
        $rules = [
            'username' => 'required|alpha_num|unique:users,username,' . $request->id,
            'role' => 'required',
            'password' => [$request->id > 0 ? 'nullable' : 'required', 'confirmed'],
        ];

        $validator = Validator::make($request->all(), $rules);
        if ($validator->fails())
            return response()->json([
                'success' => false,
                'errors' => $validator->errors()
            ]);

        // save to database
        if ($request->id > 0) {
            $data = User::find($request->id);
        } else {
            $data = new User();
            $data->created_by_id = Auth::id();
        }

        $data->updated_by_id = Auth::id();
        $data->username = $request->username;
        $data->role = $request->role;
        $data->active = $request->active == 'on';
        if ($request->password)
            $data->password = bcrypt($request->password);

        $data->save();
        return response()->json([
            'success' => true,
            'redirect_url' => url('user')
        ]);
    }

    public function delete(Request $request)
    {
        $data = User::find($request->delete_id);
        $data->deleted_by_id = Auth::id();
        $data->delete();
        return redirect('user');
    }
}

Replace the contents of app/Http/Controllers/DashboardController.php with the code below. If the file doesn’t exist yet, please create it.

<?php
// Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;

class DashboardController extends Controller
{
    public function __invoke()
    {
        return view('dashboard');
    }
}

Setup View in Laravel jQuery POS Ajax CRUD Interface

Design modular Blade views for each menu screen. These views will be returned by the controller and injected into the main content area dynamically using jQuery Ajax.

Replace the contents of resources/views/layout/admin.blade.php with the code below. If the file doesn’t exist yet, please create it.

<!-- Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com -->
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <link rel="icon" type="image/png" href="images/favicon.png">
    <title>{{ env('APP_NAME') }}</title>
    <!-- Google Fonts -->
    <link href="https://fonts.gstatic.com" rel="preconnect">
    <link
        href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i|Nunito:300,300i,400,400i,600,600i,700,700i|Poppins:300,300i,400,400i,500,500i,600,600i,700,700i"
        rel="stylesheet">
    @vite('resources/js/app.js')
</head>

<body style="display: none">
    <!-- Error Modal -->
    <div class="fade modal" tabindex="-1" id="errorModal">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header py-2 bg-danger text-light">
                    <h5 class="modal-title">ERROR</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <p class="fs-5"></p>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Ok</button>
                </div>
            </div>
        </div>
    </div>
    <!-- Success Modal -->
    <div class="fade modal" tabindex="-1" id="successModal">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header py-2 bg-success text-light">
                    <h5 class="modal-title">SUCCESS</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <p class="fs-5"></p>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Ok</button>
                </div>
            </div>
        </div>
    </div>
    <!-- Delete Modal -->
    <div class="fade modal" tabindex="-1" id="confirmDelete">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header py-2 bg-danger text-light">
                    <h5 class="modal-title">Confirm Delete</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <p class="fs-5">Are you sure want to delete?</p>
                </div>
                <div class="modal-footer">
                    <form id="deleteForm" method="post" style="padding-bottom: 0px;margin-bottom: 0px;">
                        @method('DELETE')
                        @csrf
                        <input type="hidden" name="delete_id" id="delete_id" />
                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
                        <button type="submit" class="btn btn-danger" data-bs-dismiss="modal">Delete</button>
                    </form>
                </div>
            </div>
        </div>
    </div>
    <!-- Form Modal -->
    <div class="modal fade" id="formModal" tabindex="-1" aria-hidden="true" data-bs-keyboard="false"
        data-bs-backdrop="static" data-bs-focus="false">
        <div class="modal-dialog">
            <div class="modal-content">
            </div>
        </div>
    </div>

    <header id="header" class="header fixed-top d-flex align-items-center">

        <div class="d-flex align-items-center justify-content-between">
            <a href="{{ url('/') }}" class="logo d-flex align-items-center">
                <img src="images/logo.png" alt="">
            </a>
            <i class="bi bi-list toggle-sidebar-btn"></i>
        </div>

        <nav class="header-nav ms-auto">
            <ul class="d-flex align-items-center">
                <li class="d-none d-md-inline-block form-inline ms-auto nav-item dropdown me-5">
                    <i class="bi bi-alarm-fill text-secondary pe-2"></i>
                    <span class="text-secondary">{{ date('d-M-Y H:i:s') }}</span>
                </li>
                <li class="nav-item dropdown pe-3">
                    <a class="nav-link nav-profile d-flex align-items-center pe-0" href="#"
                        data-bs-toggle="dropdown">
                        <i class="bi bi-person-fill" style="font-size: 35px;"></i>
                        <span
                            class="d-none d-md-block dropdown-toggle ps-2">{{ ucwords(request()->user()?->username) }}</span>
                    </a>
                    <ul class="dropdown-menu dropdown-menu-end dropdown-menu-arrow profile">
                        <li>
                            <button class="dropdown-item d-flex align-items-center"
                                onclick="ajaxPopup(`{{ url('user/change-password') }}`)">
                                <i class="bi bi-shield-lock"></i>
                                <span>Change Password</span>
                            </button>
                        </li>
                        <li>
                            <hr class="dropdown-divider">
                        </li>
                        <li>
                            <form method="post" action="{{ url('./user/logout') }}">
                                @csrf
                                <button type="submit" class="dropdown-item d-flex align-items-center">
                                    <i class="bi bi-box-arrow-right"></i>
                                    <span>Sign Out</span>
                                </button>
                            </form>
                        </li>
                    </ul>
                </li>
            </ul>
        </nav>

    </header>

    <!-- ======= Sidebar ======= -->
    <aside id="sidebar" class="sidebar">
        <ul class="sidebar-nav" id="sidebar-nav">
            <li class="nav-item">
                <a href="#dashboard" class="nav-link collapsed">
                    <i class="bi bi-speedometer2"></i>
                    <span>Dashboard</span>
                </a>
            </li>
            <li class="nav-heading">Main Data</li>
            <li class="nav-item">
                <a href="#table" class="nav-link collapsed">
                    <i class="bi bi-grid-3x3-gap"></i>
                    <span>Table</span>
                </a>
            </li>
            <li class="nav-item">
                <a href="#product" class="nav-link collapsed">
                    <i class="bi bi-list-ul"></i>
                    <span>Product</span>
                </a>
            </li>
            <li class="nav-item">
                <a href="#product-category" class="nav-link collapsed">
                    <i class="bi bi-grid"></i>
                    <span>Product Category</span>
                </a>
            </li>
            <li class="nav-heading">Operation</li>
            <li class="nav-item">
                <a href="#balance-adjustment" class="nav-link collapsed">
                    <i class="bi bi-coin"></i>
                    <span>Balance Adjustment</span>
                </a>
            </li>
            <li class="nav-heading">Report</li>
            <li class="nav-item">
                <a href="#report/sale-summary" class="nav-link collapsed">
                    <i class="bi bi-graph-up-arrow"></i>
                    <span>Sale Summary</span>
                </a>
            </li>
            <li class="nav-item">
                <a href="#report/product-summary" class="nav-link collapsed">
                    <i class="bi bi-clipboard-data"></i>
                    <span>Product Summary</span>
                </a>
            </li>
            <li class="nav-item">
                <a href="#report/sale-history" class="nav-link collapsed">
                    <i class="bi bi-clock-history"></i>
                    <span>Sale History</span>
                </a>
            </li>
            @if (request()->user()->role == 'superadmin')
            <li class="nav-heading">System Setting</li>
            <li class="nav-item">
                <a href="#user" class="nav-link collapsed">
                    <i class="bi bi-people"></i>
                    <span>System User</span>
                </a>
            </li>
            @endif
        </ul>
    </aside>

    <main id="main" class="main">
        <div id="content"></div>
    </main>

    <div class="loading"></div>
</body>

</html>

Replace the contents of resources/views/table/index.blade.php with the code below. If the file doesn’t exist yet, please create it.

<!-- Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com -->
<button type="button" class="btn btn-primary" style="float: right" onclick="ajaxPopup(`{{ url('table/form') }}`)">
    <i class="bi bi-plus-circle"></i> Add New
</button>

<div class="pagetitle">
    <h1>Table</h1>
</div>
<section class="section">
    <div class="col">
        <div class="card">
            <div class="card-body">
                <form method="get" id="search_form" action="{{ url('/table') }}">
                    <div class="row pt-4">
                        <div class="col-md-10">
                            <div class="row justify-content-start">
                                <div class="col-lg-3 col-sm-6">
                                    <label class="form-label" for="table_name">Name</label>
                                    <input type="text" id="table_name" name="table_name" class="form-control"
                                        value="{{ session('table_name') }}" placeholder="Search..." />
                                </div>
                                <div class="col-lg-3 col-sm-6">
                                    <label for="table_status" class="form-label">Status</label>
                                    <select id="table_status" name="table_status" class="form-select">
                                        <option value="0" {{ session('table_status') == 0 ? 'selected' : '' }}>
                                            ALL
                                        </option>
                                        <option value="2" {{ session('table_status') == 2 ? 'selected' : '' }}>
                                            Free</option>
                                        <option value="1" {{ session('table_status') == 1 ? 'selected' : '' }}>
                                            Busy</option>
                                        <option value="3" {{ session('table_status') == 3 ? 'selected' : '' }}>
                                            Payment</option>
                                    </select>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-2 align-self-end">
                            <button type="submit" class="btn btn-secondary pt-1" style="float: right">
                                <i class="bi bi-search"></i> Search
                            </button>
                        </div>
                    </div>
                </form>
                <hr class="text-secondary" />
                <table class="table table-striped">
                    <thead>
                        <tr class="table-dark">
                            <th width="50px">#</th>
                            <th style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('table?table_field=name&table_order=' . (session('table_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Name
                                <i
                                    class="text-secondary {{ session('table_field') == 'name' ? (session('table_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('table?table_field=status&table_order=' . (session('table_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Status
                                <i
                                    class="text-secondary {{ session('table_field') == 'status' ? (session('table_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('table?table_field=created_at&table_order=' . (session('table_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Created at
                                <i
                                    class="text-secondary {{ session('table_field') == 'created_at' ? (session('table_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th class="text-center" width="100px">Action</th>
                        </tr>
                    </thead>
                    <tbody>
                        @if (isset($list) && count($list) > 0)
                        @foreach ($list as $index => $value)
                        <tr>
                            <th style="vertical-align: middle;text-align: center">
                                {{ $list->perPage() * ($list->currentPage() - 1) + ($index + 1) }}
                            </th>
                            <td style="vertical-align: middle">{{ $value->name }}</td>
                            <td style="vertical-align: middle">{!! $value->status == 1
                                ? '<span class="text-danger">Busy</span>'
                                : ($value->status == 2
                                ? 'Free'
                                : '<span class="text-danger">Printed</span>') !!}</td>
                            <td style="vertical-align: middle">
                                {{ date('d-M-Y H:i:s', strtotime($value->created_at)) }}
                            </td>
                            <td style="vertical-align: middle;text-align: center;">
                                <i class="bi bi-trash3-fill text-danger" role="button"
                                    data-record-url="{{ url('table/delete') }}"
                                    data-record-id="{{ $value->id }}" title="Delete"
                                    data-bs-toggle="modal" data-bs-target="#confirmDelete"></i>
                                <a title="Edit"
                                    href="javascript:ajaxPopup('{{ url('table/form/' . $value->id) }}')">
                                    <i class="bi bi-pencil-square text-success ps-3" role="button"></i>
                                </a>
                            </td>
                        </tr>
                        @endforeach
                        @else
                        <tr v-else>
                            <td colspan="10" class="shadow-none">
                                No record found
                            </td>
                        </tr>
                        @endif
                    </tbody>
                </table>
                <div class="d-flex justify-content-end">
                    <!-- Pagination -->
                    <nav>
                        <ul class="pagination justify-content-end">
                            {{ $list->links() }}
                        </ul>
                    </nav>
                </div>
            </div>
        </div>
    </div>
</section>

Replace the contents of resources/views/table/form.blade.php with the code below. If the file doesn’t exist yet, please create it.

<!-- Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com --> 
<div class="modal-header py-2 bg-secondary text-light">
     <h5 class="modal-title" style="font-weight: bold">
         {{ isset($data) ? 'Edit' : 'New' }} Table
     </h5>
 </div>
 <div class="modal-body">
     <form method="POST" id="submitForm" action="{{ url('table/submit') }}">
         @csrf
         @method(isset($data) ? 'PUT' : 'POST')
         <input type="hidden" value="{{ isset($data) ? $data->id : 0 }}" name="id" />
         <div class="row">
             <div class="required mb-3">
                 <label for="autofocus" class="form-label">Name</label>
                 <input id="autofocus" name="name" type="text" class="form-control"
                     value="{{ isset($data) ? $data->name : '' }}" />
             </div>
             <div class="required mb-3">
                 <label for="status" class="form-label">Status</label>
                 <select id="status" name="status" class="form-select">
                     <option value="2" @selected(isset($data) && $data->status == 2)>Free</option>
                     <option value="1" @selected(isset($data) && $data->status == 1)>Busy</option>
                 </select>
             </div>
         </div>
     </form>
 </div>
 <div class="modal-footer">
     <button type="button" class="btn btn-danger" data-bs-dismiss="modal">
         <i class="bi bi-x-lg"></i> Cancel
     </button>
     <button type="submit" class="btn btn-primary" form="submitForm">
         <i class="bi bi-floppy" style="padding-right: 3px;"></i>Save
     </button>
 </div>

Replace the contents of resources/views/product_category/index.blade.php with the code below. If the file doesn’t exist yet, please create it.

<!-- Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com -->
<button type="button" class="btn btn-primary" style="float: right"
    onclick="ajaxPopup(`{{ url('product-category/form') }}`)">
    <i class="bi bi-plus-circle"></i> Add New
</button>

<div class="pagetitle">
    <h1>Product Category</h1>
</div>
<section class="section">
    <div class="col">
        <div class="card">
            <div class="card-body">
                <form method="get" id="search_form" action="{{ url('/product-category') }}">
                    <div class="row pt-4">
                        <div class="col-md-10">
                            <div class="row justify-content-start">
                                <div class="col-lg-3 col-sm-6">
                                    <label class="form-label" for="product_category_name">Name</label>
                                    <input type="text" id="product_category_name" name="product_category_name"
                                        class="form-control" value="{{ session('product_category_name') }}"
                                        placeholder="Search..." />
                                </div>
                            </div>
                        </div>
                        <div class="col-md-2 align-self-end">
                            <button type="submit" class="btn btn-secondary pt-1" style="float: right">
                                <i class="bi bi-search"></i> Search
                            </button>
                        </div>
                    </div>
                </form>
                <hr class="text-secondary" />
                <table class="table table-striped">
                    <thead>
                        <tr class="table-dark">
                            <th width="50px">#</th>
                            <th style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('product-category?product_category_field=name&product_category_order=' . (session('product_category_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Name
                                <i
                                    class="text-secondary {{ session('product_category_field') == 'name' ? (session('product_category_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th style="cursor: pointer; width: 200px;"
                                onclick="ajaxLoad(`{{ url('product-category?product_category_field=created_at&product_category_order=' . (session('product_category_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Created at
                                <i
                                    class="text-secondary {{ session('product_category_field') == 'created_at' ? (session('product_category_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th class="text-center" width="100px">Action</th>
                        </tr>
                    </thead>
                    <tbody>
                        @if (isset($list) && count($list) > 0)
                        @foreach ($list as $index => $value)
                        <tr>
                            <th style="vertical-align: middle;text-align: center">
                                {{ $list->perPage() * ($list->currentPage() - 1) + ($index + 1) }}
                            </th>
                            <td style="vertical-align: middle">{{ $value->name }}</td>
                            <td style="vertical-align: middle">
                                {{ date('d-M-Y H:i:s', strtotime($value->created_at)) }}
                            </td>
                            <td style="vertical-align: middle;text-align: center;">
                                <i class="bi bi-trash3-fill text-danger" role="button"
                                    data-record-url="{{ url('product-category/delete') }}"
                                    data-record-id="{{ $value->id }}" title="Delete"
                                    data-bs-toggle="modal" data-bs-target="#confirmDelete"></i>
                                <a title="Edit"
                                    href="javascript:ajaxPopup('{{ url('product-category/form/' . $value->id) }}')">
                                    <i class="bi bi-pencil-square text-success ps-3" role="button"></i>
                                </a>
                            </td>
                        </tr>
                        @endforeach
                        @else
                        <tr v-else>
                            <td colspan="10" class="shadow-none">
                                No record found
                            </td>
                        </tr>
                        @endif
                    </tbody>
                </table>
                <div class="d-flex justify-content-end">
                    <!-- Pagination -->
                    <nav>
                        <ul class="pagination justify-content-end">
                            {{ $list->links() }}
                        </ul>
                    </nav>
                </div>
            </div>
        </div>
    </div>
</section>

Replace the contents of resources/views/product_category/form.blade.php with the code below. If the file doesn’t exist yet, please create it.

<!-- Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com --> 
 <div class="modal-header py-2 bg-secondary text-light">
     <h5 class="modal-title" style="font-weight: bold">
         {{ isset($data) ? 'Edit' : 'New' }} Product Category
     </h5>
 </div>
 <div class="modal-body">
     <form method="POST" id="submitForm" action="{{ url('product-category/submit') }}">
         @csrf
         @method(isset($data) ? 'PUT' : 'POST')
         <input type="hidden" value="{{ isset($data) ? $data->id : 0 }}" name="id" />
         <div class="row">
             <div class="required mb-3">
                 <label for="autofocus" class="form-label">Name</label>
                 <input id="autofocus" name="name" type="text" class="form-control"
                     value="{{ isset($data) ? $data->name : '' }}" />
             </div>
         </div>
     </form>
 </div>
 <div class="modal-footer">
     <button type="button" class="btn btn-danger" data-bs-dismiss="modal">
         <i class="bi bi-x-lg"></i> Cancel
     </button>
     <button type="submit" class="btn btn-primary" form="submitForm">
         <i class="bi bi-floppy" style="padding-right: 3px;"></i>Save
     </button>
 </div>

Replace the contents of resources/views/product/index.blade.php with the code below. If the file doesn’t exist yet, please create it.

<!-- Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com -->
<button type="button" class="btn btn-primary" style="float: right" onclick="ajaxPopup(`{{ url('product/form') }}`)">
    <i class="bi bi-plus-circle"></i> Add New
</button>

<div class="pagetitle">
    <h1>Product</h1>
</div>
<section class="section">
    <div class="col">
        <div class="card">
            <div class="card-body">
                <form method="get" id="search_form" action="{{ url('/product') }}">
                    <div class="row pt-4">
                        <div class="col-md-10">
                            <div class="row justify-content-start">
                                <div class="col-lg-3 col-sm-6">
                                    <label class="form-label" for="product_name">Name</label>
                                    <input type="text" id="product_name" name="product_name" class="form-control"
                                        value="{{ session('product_name') }}" placeholder="Search..." />
                                </div>
                                <div class="col-lg-3 col-sm-6">
                                    <label for="product_category" class="form-label">Category</label>
                                    <select id="product_category" name="product_category" class="form-select">
                                        <option value="0"
                                            {{ session('product_category') == 0 ? 'selected' : '' }}>
                                            ALL
                                        </option>
                                        @foreach ($product_categories as $category)
                                        <option value="{{ $category->id }}"
                                            {{ session('product_category') == $category->id ? 'selected' : '' }}>
                                            {{ $category->name }}
                                        </option>
                                        @endforeach
                                    </select>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-2 align-self-end">
                            <button type="submit" class="btn btn-secondary pt-1" style="float: right">
                                <i class="bi bi-search"></i> Search
                            </button>
                        </div>
                    </div>
                </form>
                <hr class="text-secondary" />
                <table class="table table-striped">
                    <thead>
                        <tr class="table-dark">
                            <th width="50px">#</th>
                            <th width="100px">Image</th>
                            <th style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('product?product_field=name&product_order=' . (session('product_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Name
                                <i
                                    class="text-secondary {{ session('product_field') == 'name' ? (session('product_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('product?product_field=category_name&product_order=' . (session('product_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Category
                                <i
                                    class="text-secondary {{ session('product_field') == 'category_name' ? (session('product_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th class="text-end" style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('product?product_field=unit_price&product_order=' . (session('product_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Unit Price
                                <i
                                    class="text-secondary {{ session('product_field') == 'unit_price' ? (session('product_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('product?product_field=created_at&product_order=' . (session('product_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Created at
                                <i
                                    class="text-secondary {{ session('product_field') == 'created_at' ? (session('product_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th class="text-center" width="100px">Action</th>
                        </tr>
                    </thead>
                    <tbody>
                        @if (isset($list) && count($list) > 0)
                        @foreach ($list as $index => $value)
                        <tr>
                            <th style="vertical-align: middle;text-align: center">
                                {{ $list->perPage() * ($list->currentPage() - 1) + ($index + 1) }}
                            </th>
                            <td>
                                <img src="{{ url($value->image ? 'storage/' . $value->image : 'images/default.png') }}"
                                    style="height: 40px;" />
                            </td>
                            <td style="vertical-align: middle">{{ $value->name }}</td>
                            <td style="vertical-align: middle">{{ $value->category_name }}</td>
                            <td class="text-end" style="vertical-align: middle">
                                ${{ number_format($value->unit_price, 2) }}
                            </td>
                            <td style="vertical-align: middle">
                                {{ date('d-M-Y H:i:s', strtotime($value->created_at)) }}
                            </td>
                            <td style="vertical-align: middle;text-align: center;">
                                <i class="bi bi-trash3-fill text-danger" role="button"
                                    data-record-url="{{ url('product/delete') }}"
                                    data-record-id="{{ $value->id }}" title="Delete"
                                    data-bs-toggle="modal" data-bs-target="#confirmDelete"></i>
                                <a title="Edit"
                                    href="javascript:ajaxPopup('{{ url('product/form/' . $value->id) }}')">
                                    <i class="bi bi-pencil-square text-success ps-3" role="button"></i>
                                </a>
                            </td>
                        </tr>
                        @endforeach
                        @else
                        <tr v-else>
                            <td colspan="10" class="shadow-none">
                                No record found
                            </td>
                        </tr>
                        @endif
                    </tbody>
                </table>
                <div class="d-flex justify-content-end">
                    <!-- Pagination -->
                    <nav>
                        <ul class="pagination justify-content-end">
                            {{ $list->links() }}
                        </ul>
                    </nav>
                </div>
            </div>
        </div>
    </div>
</section>

Replace the contents of resources/views/product/form.blade.php with the code below. If the file doesn’t exist yet, please create it.

<!-- Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com --> 
<div class="modal-header py-2 bg-secondary text-light">
     <h5 class="modal-title" style="font-weight: bold">
         {{ isset($data) ? 'Edit' : 'New' }} Table
     </h5>
 </div>
 <div class="modal-body">
     <form method="POST" id="submitForm" enctype="multipart/form-data" action="{{ url('product/submit') }}">
         @csrf
         @method(isset($data) ? 'PUT' : 'POST')
         <input type="hidden" value="{{ isset($data) ? $data->id : 0 }}" name="id" />
         <div class="row">
             <div class="mb-3">
                 <label class="form-label">Image</label>
                 <div style="position: relative; width: 40%;">
                     <i class="bi bi-x-circle fs-3 m-0 p-0 text-danger"
                         style="position: absolute; right: 5px;top: -2px; cursor: pointer;" onclick="removeImage"></i>
                     <img id="img_preview"
                         src="{{ url(isset($data) && $data->image ? 'storage/' . $data->image : 'images/default.png') }}"
                         style="width: 100%;cursor: pointer;" class="img-thumbnail" onclick="$('#image').click()" />
                     <input type="hidden" style="display: none" value="0" name="is_deleted_image"
                         id="is_deleted_image" />
                 </div>
                 <input type="file" id="image" name="image" style="display: none;"
                     accept=".jpg,.jpeg,.bmp,.gif,.png,.webp" />
             </div>
             <div class="required mb-3">
                 <label for="autofocus" class="form-label">Name</label>
                 <input id="autofocus" name="name" type="text" class="form-control"
                     value="{{ isset($data) ? $data->name : '' }}" />
             </div>
             <div class="required mb-3">
                 <label for="product_category_id" class="form-label">Category</label>
                 <select id="product_category_id" name="product_category_id" class="form-select">
                     @foreach ($product_categories as $category)
                     <option value="{{ $category->id }}"
                         {{ isset($data) && $data->product_category_id == $category->id ? 'selected' : '' }}>
                         {{ $category->name }}
                     </option>
                     @endforeach
                 </select>
             </div>
             <div class="required mb-3">
                 <label class="form-label">Unit Price</label>
                 <div class="input-group" for="unit_price">
                     <span class="input-group-text">$</span>
                     <input id="unit_price" name="unit_price" type="text" class="form-control"
                         value="{{ isset($data) ? $data->unit_price : '' }}" />
                 </div>
             </div>
         </div>
     </form>
 </div>
 <div class="modal-footer">
     <button type="button" class="btn btn-danger" data-bs-dismiss="modal">
         <i class="bi bi-x-lg"></i> Cancel
     </button>
     <button type="submit" class="btn btn-primary" form="submitForm">
         <i class="bi bi-floppy" style="padding-right: 3px;"></i>Save
     </button>
 </div>

Replace the contents of resources/views/balance_adjustment/index.blade.php with the code below. If the file doesn’t exist yet, please create it.

<!-- Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com -->
<button type="button" class="btn btn-primary" style="float: right" onclick="ajaxPopup(`{{ url('balance-adjustment/form') }}`)">
    <i class="bi bi-plus-circle"></i> Add New
</button>

<div class="pagetitle">
    <h1>Balance Adjustment</h1>
</div>
<section class="section">
    <div class="col">
        <div class="card">
            <div class="card-body">
                <form method="get" id="search_form" action="{{ url('/balance-adjustment') }}">
                    <div class="row pt-4">
                        <div class="col-md-10">
                            <div class="row justify-content-start">
                                <div class="col-lg-3 col-sm-6">
                                    <label class="form-label" for="balance_adjustment_remark">Remark</label>
                                    <input type="text" id="balance_adjustment_remark" name="balance_adjustment_remark" class="form-control"
                                        value="{{ session('balance_adjustment_remark') }}" placeholder="Search..." />
                                </div>
                                <div class="col-lg-3 col-sm-6">
                                    <label for="balance_adjustment_type_id" class="form-label">Type</label>
                                    <select id="balance_adjustment_type_id" name="balance_adjustment_type_id" class="form-select">
                                        <option value="0"
                                            {{ session('balance_adjustment_type_id') == 0 ? 'selected' : '' }}>
                                            ALL
                                        </option>
                                        <option value="1"
                                            {{ session('balance_adjustment_type_id') == 1 ? 'selected' : '' }}>
                                            Credit (+)
                                        </option>
                                        <option value="2"
                                            {{ session('balance_adjustment_type_id') == 2 ? 'selected' : '' }}>
                                            Debit (-)
                                        </option>
                                    </select>
                                </div>
                                <div class="col-lg-3 col-sm-6">
                                    <label class="form-label" for="balance_adjustment_fd">From Date</label>
                                    <input type="text" id="balance_adjustment_fd" name="balance_adjustment_fd" value="{{session('balance_adjustment_fd')}}" class="form-control" />
                                </div>
                                <div class="col-lg-3 col-sm-6">
                                    <label class="form-label" for="balance_adjustment_td">To Date</label>
                                    <input type="text" id="balance_adjustment_td" name="balance_adjustment_td" value="{{session('balance_adjustment_td')}}" class="form-control" />
                                </div>
                            </div>
                        </div>
                        <div class="col-md-2 align-self-end">
                            <button type="submit" class="btn btn-secondary pt-1" style="float: right">
                                <i class="bi bi-search"></i> Search
                            </button>
                        </div>
                    </div>
                </form>
                <hr class="text-secondary" />
                <table class="table table-striped">
                    <thead>
                        <tr class="table-dark">
                            <th width="50px">#</th>
                            <th class="text-end" style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('balance-adjustment?balance_adjustment_field=amount&balance_adjustment_order=' . (session('balance_adjustment_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Amount
                                <i
                                    class="text-secondary {{ session('balance_adjustment_field') == 'amount' ? (session('balance_adjustment_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('balance-adjustment?balance_adjustment_field=type_id&balance_adjustment_order=' . (session('balance_adjustment_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Type
                                <i
                                    class="text-secondary {{ session('balance_adjustment_field') == 'type_id' ? (session('balance_adjustment_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th> Remark </th>
                            <th style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('balance-adjustment?balance_adjustment_field=adjusted_date&balance_adjustment_order=' . (session('balance_adjustment_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Adjusted Date
                                <i
                                    class="text-secondary {{ session('balance_adjustment_field') == 'adjusted_date' ? (session('balance_adjustment_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('balance-adjustment?balance_adjustment_field=updated_at&balance_adjustment_order=' . (session('balance_adjustment_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Updated at
                                <i
                                    class="text-secondary {{ session('balance_adjustment_field') == 'updated_at' ? (session('balance_adjustment_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th class="text-center" width="100px">Action</th>
                        </tr>
                    </thead>
                    <tbody>
                        @if (isset($list) && count($list) > 0)
                        @foreach ($list as $index => $value)
                        <tr>
                            <th style="vertical-align: middle;text-align: center">
                                {{ $list->perPage() * ($list->currentPage() - 1) + ($index + 1) }}
                            </th>
                            <td style="vertical-align: middle" class="text-end">${{ number_format($value->amount, 2) }}</td>
                            <td style="vertical-align: middle">{{ $value->type_id == 1?'Credit (+)':'Debit (-)' }}</td>
                            <td style="vertical-align: middle">{{ $value->remark }}</td>
                            <td style="vertical-align: middle">
                                {{ date('d-M-Y', strtotime($value->adjusted_date)) }}
                            </td>
                            <td style="vertical-align: middle">
                                {{ date('d-M-Y H:i:s', strtotime($value->updated_at)) }}
                            </td>
                            <td style="vertical-align: middle;text-align: center;">
                                <i class="bi bi-trash3-fill text-danger" role="button"
                                    data-record-url="{{ url('balance-adjustment/delete') }}"
                                    data-record-id="{{ $value->id }}" title="Delete"
                                    data-bs-toggle="modal" data-bs-target="#confirmDelete"></i>
                                <a title="Edit"
                                    href="javascript:ajaxPopup('{{ url('balance-adjustment/form/' . $value->id) }}')">
                                    <i class="bi bi-pencil-square text-success ps-3" role="button"></i>
                                </a>
                            </td>
                        </tr>
                        @endforeach
                        @else
                        <tr v-else>
                            <td colspan="10" class="shadow-none">
                                No record found
                            </td>
                        </tr>
                        @endif
                    </tbody>
                </table>
                <div class="d-flex justify-content-end">
                    <!-- Pagination -->
                    <nav>
                        <ul class="pagination justify-content-end">
                            {{ $list->links()}}
                        </ul>
                    </nav>
                </div>
            </div>
        </div>
    </div>
</section>
<script>
    $(document).ready(function() {
        const $start = $("#balance_adjustment_fd");
        const $end = $("#balance_adjustment_td");

        const startPicker = flatpickr($start, {
            altFormat: "d-M-Y",
            altInput: true,
            onChange: function(selectedDates, dateStr, instance) {
                if (dateStr) {
                    endPicker.set('minDate', dateStr);
                }
            }
        });

        const endPicker = flatpickr($end, {
            altFormat: "d-M-Y",
            altInput: true,
            onChange: function(selectedDates, dateStr, instance) {
                if (dateStr) {
                    startPicker.set('maxDate', dateStr);
                }
            }
        });
    });
</script>

Replace the contents of resources/views/balance_adjustment/form.blade.php with the code below. If the file doesn’t exist yet, please create it.

<!-- Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com -->
 <div class="modal-header py-2 bg-secondary text-light">
     <h5 class="modal-title" style="font-weight: bold">
         {{ isset($data) ? 'Edit' : 'New' }} Balance Adjustment
     </h5>
 </div>
 <div class="modal-body">
     <form method="POST" id="submitForm" action="{{ url('balance-adjustment/submit') }}">
         @csrf
         @method(isset($data) ? 'PUT' : 'POST')
         <input type="hidden" value="{{ isset($data) ? $data->id : 0 }}" name="id" />
         <div class="row">
             <div class="required mb-3">
                 <label class="form-label">Unit Price</label>
                 <div class="input-group" for="autofocus">
                     <span class="input-group-text">$</span>
                     <input id="autofocus" name="amount" type="text" class="form-control"
                         value="{{ isset($data) ? $data->amount : '' }}" />
                 </div>
             </div>
             <div class="required mb-3">
                 <label for="type_id" class="form-label">Type</label>
                 <select id="type_id" name="type_id" class="form-select">
                     <option value="1"
                         {{ isset($data) && $data->type_id == 1 ? 'selected' : '' }}>
                         Credit (+)
                     </option>
                     <option value="2"
                         {{ isset($data) && $data->type_id == 2 ? 'selected' : '' }}>
                         Debit (-)
                     </option>
                 </select>
             </div>
             <div class="required mb-3">
                 <label for="adjusted_date" class="form-label">Adjust Date</label>
                 <input id="adjusted_date" name="adjusted_date" type="text" class="form-control"
                     value="{{ isset($data) ? Date('Y-m-d', strtotime($data->adjusted_date)) : Date('Y-m-d') }}" />
             </div>
             <div class="required mb-3">
                 <label for="remark" class="form-label">Remark</label>
                 <textarea id="remark" name="remark" class="form-control">{{ isset($data) ? $data->remark : '' }}</textarea>
             </div>
         </div>
     </form>
 </div>
 <div class="modal-footer">
     <button type="button" class="btn btn-danger" data-bs-dismiss="modal">
         <i class="bi bi-x-lg"></i> Cancel
     </button>
     <button type="submit" class="btn btn-primary" form="submitForm">
         <i class="bi bi-floppy" style="padding-right: 3px;"></i>Save
     </button>
 </div>
 <script>
     $(document).ready(function() {
         let oldSelectedDate = null;
         flatpickr($('#adjusted_date'), {
             altFormat: "d-M-Y",
             altInput: true,
             onChange: function(selectedDates, dateStr) {
                 if (dateStr)
                     oldSelectedDate = dateStr;
             },
             onClose: function(selectedDates, dateStr, instance) {
                 if (!dateStr)
                     instance.setDate(oldSelectedDate ?? new Date());
             }
         });
     });
 </script>

Replace the contents of resources/views/user/index.blade.php with the code below. If the file doesn’t exist yet, please create it.

<!-- Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com -->
<button type="button" class="btn btn-primary" style="float: right" onclick="ajaxPopup(`{{ url('user/form') }}`)">
    <i class="bi bi-plus-circle"></i> Add New
</button>

<div class="pagetitle">
    <h1>User</h1>
</div>
<section class="section">
    <div class="col">
        <div class="card">
            <div class="card-body">
                <form method="get" id="search_form" action="{{ url('/user') }}">
                    <div class="row pt-4">
                        <div class="col-md-10">
                            <div class="row justify-content-start">
                                <div class="col-lg-3 col-sm-6">
                                    <label class="form-label" for="user_name">Name</label>
                                    <input type="text" id="user_name" name="user_name" class="form-control"
                                        value="{{ session('user_name') }}" placeholder="Search..." />
                                </div>
                                <div class="col-lg-3 col-sm-6">
                                    <label for="user_role" class="form-label">Role</label>
                                    <select id="user_role" name="user_role" class="form-select">
                                        <option value="0" {{ session('user_role') == 0 ? 'selected' : '' }}>
                                            ALL
                                        </option>
                                        <option value="superadmin" {{ session('user_role') == 'superadmin' ? 'selected' : '' }}>
                                            Super Admin
                                        </option>
                                        <option value="admin" {{ session('user_role') == 'admin' ? 'selected' : '' }}>
                                            Admin
                                        </option>
                                        <option value="cashier" {{ session('user_role') == 'cashier' ? 'selected' : '' }}>
                                            Cashier
                                        </option>
                                    </select>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-2 align-self-end">
                            <button type="submit" class="btn btn-secondary pt-1" style="float: right">
                                <i class="bi bi-search"></i> Search
                            </button>
                        </div>
                    </div>
                </form>
                <hr class="text-secondary" />
                <table class="table table-striped">
                    <thead>
                        <tr class="table-dark">
                            <th width="50px">#</th>
                            <th style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('user?user_field=username&user_order=' . (session('user_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Username
                                <i class="text-secondary {{ session('user_field') == 'username' ? (session('user_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('user?user_field=role&user_order=' . (session('user_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Role
                                <i class="text-secondary {{ session('user_field') == 'role' ? (session('user_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('user?user_field=active&user_order=' . (session('user_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Active
                                <i class="text-secondary {{ session('user_field') == 'active' ? (session('user_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th style="cursor: pointer"
                                onclick="ajaxLoad(`{{ url('user?user_field=created_at&user_order=' . (session('user_order') == 'asc' ? 'desc' : 'asc')) }}`)">
                                Created at
                                <i class="text-secondary {{ session('user_field') == 'created_at' ? (session('user_order') == 'desc' ? 'bi bi-sort-alpha-down-alt' : 'bi bi-sort-alpha-down') : 'bi bi-arrow-down-up' }}"></i>
                            </th>
                            <th class="text-center" width="100px">Action</th>
                        </tr>
                    </thead>
                    <tbody>
                        @if (isset($list) && count($list) > 0)
                        @foreach ($list as $index => $value)
                        <tr>
                            <th style="vertical-align: middle;text-align: center">
                                {{ $list->perPage() * ($list->currentPage() - 1) + ($index + 1) }}
                            </th>
                            <td style="vertical-align: middle">{{ $value->username }}</td>
                            <td style="vertical-align: middle">{{ ucwords($value->role) }}
                            </td>
                            <td class="py-0 my-0">
                                <i class="bi {{$value->active?'bi-toggle-on text-success':'bi-toggle-off text-danger'}} fs-3"></i>
                            </td>
                            <td style="vertical-align: middle">
                                {{ date('d-M-Y H:i:s', strtotime($value->created_at)) }}
                            </td>
                            <td style="vertical-align: middle;text-align: center;">
                                <i class="bi bi-trash3-fill text-danger" role="button"
                                    data-record-url="{{ url('user/delete') }}"
                                    data-record-id="{{ $value->id }}" title="Delete"
                                    data-bs-toggle="modal" data-bs-target="#confirmDelete"></i>
                                <a title="Edit"
                                    href="javascript:ajaxPopup('{{ url('user/form/' . $value->id) }}')">
                                    <i class="bi bi-pencil-square text-success ps-3" role="button"></i>
                                </a>
                            </td>
                        </tr>
                        @endforeach
                        @else
                        <tr v-else>
                            <td colspan="10" class="shadow-none">
                                No record found
                            </td>
                        </tr>
                        @endif
                    </tbody>
                </table>
                <div class="d-flex justify-content-end">
                    <!-- Pagination -->
                    <nav>
                        <ul class="pagination justify-content-end">
                            {{ $list->links() }}
                        </ul>
                    </nav>
                </div>
            </div>
        </div>
    </div>
</section>

Replace the contents of resources/views/user/form.blade.php with the code below. If the file doesn’t exist yet, please create it.

<!-- Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com -->
 <div class="modal-header py-2 bg-secondary text-light">
     <h5 class="modal-title" style="font-weight: bold">
         {{ isset($data) ? 'Edit' : 'New' }} User
     </h5>
 </div>
 <div class="modal-body">
     <form method="POST" id="submitForm" action="{{ url('user/submit') }}">
         @csrf
         @method(isset($data) ? 'PUT' : 'POST')
         <input type="hidden" value="{{ isset($data) ? $data->id : 0 }}" name="id" />
         <div class="row">
             <div class="required mb-3">
                 <label for="autofocus" class="form-label">Username</label>
                 <input id="autofocus" name="username" type="text" class="form-control"
                     value="{{ isset($data) ? $data->username : '' }}" />
             </div>
             <div class="mb-3">
                 <div class="row">
                     <div class="col-9">
                         <label for="role" class="form-label">Role</label>
                          <select id="role" name="role" class="form-select">
                             <option value="superadmin" @selected(isset($data) && $data->role == 'superadmin')>Super Admin</option>
                             <option value="admin" @selected(isset($data) && $data->role == 'admin')>Admin</option>
                             <option value="cashier" @selected(isset($data) && $data->role == 'cashier')>Cashier</option>
                         </select>
                     </div>
                     <div class="col-3">
                         <label for="active" class="form-label">Active</label>
                         <div class="form-check form-switch">
                             <input class="form-check-input" type="checkbox" role="switch"
                                 id="active" name="active" @checked(isset($data) && $data->active) />
                         </div>
                     </div>
                 </div>
             </div>
             <div class="required mb-3">
                 <label for="password" class="form-label">Password</label>
                 <input id="password" name="password" type="password" class="form-control" />
             </div>
             <div class="mb-3">
                 <label for="password_confirmation" class="form-label">Confirm Password</label>
                 <input id="password_confirmation" name="password_confirmation" type="password" class="form-control" />
             </div>
         </div>
     </form>
 </div>
 <div class="modal-footer">
     <button type="button" class="btn btn-danger" data-bs-dismiss="modal">
         <i class="bi bi-x-lg"></i> Cancel
     </button>
     <button type="submit" class="btn btn-primary" form="submitForm">
         <i class="bi bi-floppy" style="padding-right: 3px;"></i>Save
     </button>
 </div>

Replace the contents of resources/views/user/change_password.blade.php with the code below. If the file doesn’t exist yet, please create it.

<!-- Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com -->
<div class="modal-header py-2 bg-secondary text-light">
     <h5 class="modal-title" style="font-weight: bold">
         Change Password
     </h5>
 </div>
 <div class="modal-body">
     <form method="POST" id="submitForm" action="{{ url('user/change-password') }}">
         @csrf
         @method('POST')
         <div class="row">
             <div class="required mb-3">
                 <label class="form-label">Username</label>
                 <input type="text" class="form-control" disabled value="{{ request()->user()?->username }}" />
             </div>
             <div class="required mb-3">
                 <label for="autofocus" class="form-label">Old Password</label>
                 <input id="autofocus" name="old_password" type="password" class="form-control" />
             </div>
             <div class="required mb-3">
                 <label for="new_password" class="form-label">New Password</label>
                 <input id="new_password" name="new_password" type="password" class="form-control" />
             </div>
             <div class="required mb-3">
                 <label for="new_password_confirmation" class="form-label">Confirm New Password</label>
                 <input id="new_password_confirmation" name="new_password_confirmation" type="password"
                     class="form-control" />
             </div>
         </div>
     </form>
 </div>
 <div class="modal-footer">
     <button type="button" class="btn btn-danger" data-bs-dismiss="modal">
         <i class="bi bi-x-lg"></i> Cancel
     </button>
     <button type="submit" class="btn btn-primary" form="submitForm">
         <i class="bi bi-floppy" style="padding-right: 3px;"></i>Save
     </button>
 </div>

Replace the contents of resources/views/dashboard.blade.php with the code below. If the file doesn’t exist yet, please create it.

<!-- Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com -->
<div class="pagetitle">
    <h1>Dashboard</h1>
</div>

Setup Route for Laravel jQuery POS Ajax CRUD System

Define web routes for each CRUD operation and menu screen. Make sure each route returns a partial view that’s optimized for Ajax loading.

Replace the contents of routes/web.php with the code below. If the file doesn’t exist yet, please create it.

<?php
// Laravel jQuery POS Ajax CRUD @ https://laravelcenter.com

use App\Http\Controllers\BalanceAdjustmentController;
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\ProductCategoryController;
use App\Http\Controllers\ProductController;
use App\Http\Controllers\TableController;
use App\Http\Controllers\UserController;
use Illuminate\Support\Facades\Route;

Route::middleware('guest')->match(['get', 'post'], '/login', [UserController::class, 'login'])->name('login');

Route::middleware('auth')->group(function () {
    Route::post('/user/logout', [UserController::class, 'logout']);

    Route::view('/', 'layout.admin');
    Route::get('dashboard', DashboardController::class);
    // User
    Route::prefix('user')->controller(UserController::class)->group(function () {
        Route::get('/', 'index');
        Route::get('form/{id?}', 'form');
        Route::match(['post', 'put'], 'submit', 'submit');
        Route::delete('delete', 'delete');
    });
    // Table
    Route::prefix('table')->controller(TableController::class)->group(function () {
        Route::get('/', 'index');
        Route::get('form/{id?}',  'form');
        Route::match(['post', 'put'], 'submit', 'submit');
        Route::delete('delete', 'delete');
    });

    // Product
    Route::prefix('product')->controller(ProductController::class)->group(function () {
        Route::get('/', 'index');
        Route::get('form/{id?}',  'form');
        Route::match(['post', 'put'], 'submit', 'submit');
        Route::delete('delete', 'delete');
    });

    // Product Category
    Route::prefix('product-category')->controller(ProductCategoryController::class)->group(function () {
        Route::get('/', 'index');
        Route::get('form/{id?}',  'form');
        Route::match(['post', 'put'], 'submit', 'submit');
        Route::delete('delete', 'delete');
    });

    // Balance Adjustment
    Route::prefix('balance-adjustment')->controller(BalanceAdjustmentController::class)->group(function () {
        Route::get('/', 'index');
        Route::get('form/{id?}',  'form');
        Route::match(['post', 'put'], 'submit', 'submit');
        Route::delete('delete', 'delete');
    });
});
Route::fallback(function () {
    return view('404');
});

Additional Setup for Laravel jQuery POS Ajax CRUD Functionality

Fixing Pagination Styling with Bootstrap in Laravel

By default, Laravel uses Tailwind CSS for pagination views. If your project is using Bootstrap (especially Bootstrap 4 or 5), the pagination links generated by {{ $items->links() }} may look unstyled or broken.

To fix this, you need to tell Laravel to use Bootstrap-compatible pagination views. You can do this by updating the AppServiceProvider.

Open the file:
app/Providers/AppServiceProvider.php

Inside the boot() method, add the following line:

use Illuminate\Pagination\Paginator;

public function boot()
{
    Paginator::useBootstrap();
}

This tells Laravel to render pagination links using Bootstrap’s markup instead of Tailwind CSS.

When you’re handling image uploads in Laravel, the uploaded files are typically stored in the storage/app/public directory. However, these files need to be publicly accessible from the browser. Laravel provides a convenient command to create a symbolic link between the public/storage directory and storage/app/public:

php artisan storage:link

This command will generate a symbolic link so you can access uploaded images using a public URL like /storage/your-image.jpg.

You can always find the latest documentation and features on the official Laravel website.

Compile Assets for Laravel jQuery POS Ajax CRUD Integration

Run the following command to compile your assets:

npm run dev

Use <strong>npm run build</strong> for production.

Once compiled, visit:

http://laravel-jquery-pos

Laravel jQuery POS Ajax CRUD – Navigation & CRUD Setup Complete

Great work! 🎉 You’ve now added dynamic Ajax-based navigation and built CRUD functionality for managing core POS data—like tables, product categories, products, users, and balance adjustments. Your Laravel jQuery POS Ajax CRUD is now fully interactive and easier to manage.

In the next tutorial, we’ll dive into building the heart of the POS system: the cart functionality. You’ll learn how to add items, update quantities, and calculate totals using jQuery—bringing the sales process to life.

👉 Continue to Part 5: Build the POS Cart System with jQuery

Laravel jQuery POS Tutorial for Beginners Series

Leave a Reply

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