Laravel jQuery POS Tutorial – Part 8/8 (END): Graph Reports with ApexCharts

This Laravel jQuery POS chart reports tutorial wraps up the series with beautiful interactive graphs using ApexCharts to present your data visually.

In this tutorial, you’ll learn how to visualize key business data using ApexCharts—a modern JavaScript charting library that integrates seamlessly with jQuery. We’ll create interactive charts that show total sales, daily trends, top products, and more.

By the end, your POS dashboard will not only be functional but visually insightful—giving store owners and admins a quick overview of performance without needing to open Excel files or read tables.

Step 1: Import ApexCharts for Laravel jQuery POS Chart Reports

In this step, you will import and configure ApexCharts to power your laravel jquery pos chart reports. This chart library helps you display sales insights, product performance, and daily transactions in a clean and interactive way using jQuery and Ajax inside your Laravel POS system.

Check your JavaScript file resources/js/app.js and make sure you’ve imported ApexCharts into your project. This library will power the interactive charts in your POS dashboard, allowing you to visualize sales and performance data with ease.

// ...
import ApexCharts from 'apexcharts';
window.ApexCharts = ApexCharts;
// ...

Step 2: Build the Controller

Next, you will build a controller that prepares the data needed for your laravel jquery pos chart reports. The controller will collect sales records, format the response for jQuery Ajax, and return clean JSON data so ApexCharts can generate dynamic POS chart reports without page reloads.

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 Chart Reports @ https://laravelcenter.com
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Order;
use Illuminate\Support\Facades\DB;

class DashboardController extends Controller
{
    public function __invoke()
    {
        // Top Products
        $top_products = Order::join('order_details', 'order_details.order_id', '=', 'orders.id')
            ->selectRaw('order_details.description,sum(order_details.qty) AS qty')
            ->where(DB::raw('DATE_FORMAT(orders.created_at,"%Y-%m-%d")'), DB::raw('DATE_FORMAT(CURDATE(),"%Y-%m-%d")'))
            ->groupBy('order_details.description')
            ->orderBy('qty', 'desc')
            ->take(10)->get();

        // Sale by Categories
        $sale_categories = Order::join('order_details', 'orders.id', '=', 'order_details.order_id')
            ->join('product_categories', 'product_categories.id', '=', 'order_details.product_category_id')
            ->select(
                DB::raw("product_categories.name,sum((order_details.qty * order_details.unit_price*order_details.discount/100) + (order_details.qty * order_details.unit_price * (1-order_details.discount/100) * orders.discount/100)) as discount, sum(order_details.qty * order_details.unit_price) as total")
            )
            ->where(DB::raw('DATE_FORMAT(orders.created_at,"%Y-%m-%d")'), DB::raw('DATE_FORMAT(CURDATE(),"%Y-%m-%d")'))
            ->groupBy(DB::raw('product_categories.name'))
            ->orderBy('product_categories.name')
            ->get();

        // Last 15 days total sale amount
        $days = 15;
        $data = Order::select(DB::raw("DATE_FORMAT(created_at,'%Y-%m-%d') AS dd, sum(net_amount) AS total"))
            ->where(DB::raw('DATE_FORMAT(created_at,"%Y-%m-%d")'), '>=', DB::raw('DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL ' . $days . ' DAY),"%Y-%m-%d")'))
            ->groupBy('dd')
            ->orderBy('dd')
            ->get()->toArray();

        $result = [];
        for ($i = $days - 1; $i >= 0; $i--) {
            $date = date('Y-m-d', strtotime('-' . $i . ' days'));
            $total = 0;
            foreach ($data as $row) {
                if ($row['dd'] == $date) {
                    $total = $row['total'];
                    break;
                }
            }
            array_push($result, [
                'date' => date('d-M', strtotime($date)),
                'total' => $total
            ]);
        }

        return view('dashboard', compact('result', 'top_products', 'sale_categories'));
    }
}

Step 3: Create the View

Here, you will design the view that displays your laravel jquery pos chart reports. The view will include chart placeholders, jQuery Ajax scripts, and ApexCharts configuration so your POS dashboard can render real-time graph reports for sales, orders, and revenue trends.

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 Chart Reports @ https://laravelcenter.com -->
<div class="pagetitle">
    <h1>Dashboard</h1>
</div>
@php
$total_amount = 0;
$total_discount = 0;
$net_amount = 0;
$pie_labels = [];
$pie_series = [];
if (isset($sale_categories) && $sale_categories->count() > 0) {
foreach ($sale_categories as $value) {
$total_amount += $value->total;
$total_discount += $value->discount;
array_push($pie_labels, $value->name);
array_push($pie_series, $value->total - $value->discount);
}
$net_amount = $total_amount - $total_discount;
}
@endphp
<div class="row">
    <div class="col-md-4 mb-4">
        <div class="card shadow bg-primary text-white">
            <div class="card-body p-4">
                <div class="d-flex justify-content-between align-items-center mb-2">
                    <div class="me-2">
                        <div class="display-6 text-white">
                            $ {{ number_format($total_amount, 2) }}
                        </div>
                        <div class="card-text fs-6 mt-2">Daily Total Sale</div>
                    </div>
                    <div style="color: lightblue"><i class="bi bi-cash-stack display-4"></i></div>
                </div>
            </div>
        </div>
    </div>
    <div class="col-md-4 mb-4">
        <div class="card shadow bg-danger text-white">
            <div class="card-body p-4">
                <div class="d-flex justify-content-between align-items-center mb-2">
                    <div class="me-2">
                        <div class="display-6 text-white">$ {{ number_format($total_discount, 2) }}</div>
                        <div class="card-text fs-6 mt-2">Daily Total Disount</div>
                    </div>
                    <div style="color: lightgray;"><i class="bi bi-percent display-4"></i></div>
                </div>
            </div>
        </div>
    </div>
    <div class="col-md-4 mb-4">
        <div class="card shadow bg-success text-white">
            <div class="card-body p-4">
                <div class="d-flex justify-content-between align-items-center mb-2">
                    <div class="me-2">
                        <div class="display-6 text-white">$ {{ number_format($net_amount, 2) }}</div>
                        <div class="card-text fs-6 mt-2">Daily Net Amount</div>
                    </div>
                    <div style="color: lightblue"><i class="bi bi-coin display-4"></i></div>
                </div>
            </div>
        </div>
    </div>
</div>
<div class="row">
    <div class="col-md-6 mb-4">
        <div class="card shadow mb-3">
            <div class="card-header bg-dark text-white py-2">
                <i class="fas fa-chart-area me-1"></i>
                Daily Sale Report By Categories
            </div>
            <div class="card-body py-1">
                <div id="pie_chart"></div>
            </div>
        </div>
    </div>
    <div class="col-md-6 mb-4">
        <table class="table table-hover shadow align-middle bg-white">
            <thead>
                <tr class="table-dark">
                    <th style="width: 50px" class="text-center">#</th>
                    <th>Product Name</th>
                    <th class="text-center">QTY</th>
                </tr>
            </thead>
            <tbody>
                @foreach ($top_products as $index => $value)
                <tr>
                    <td class="text-center">{{ $index + 1 }}</td>
                    <td>{{ $value->description }}</td>
                    <td class="text-center">
                        {{ $value->qty }}
                    </td>
                </tr>
                @endforeach
                @for ($i = 1; $i <= 10 - $top_products->count(); $i++)
                    <tr>
                        <td class="text-center">{{ $top_products->count() + $i }}</td>
                        <td></td>
                        <td class="text-center"></td>
                    </tr>
                    @endfor
            </tbody>
        </table>
    </div>
</div>
<div class="col mb-5">
    <div class="card shadow mb-3">
        <div class="card-header bg-dark text-white py-2">
            <i class="fas fa-chart-bar me-1"></i>
            15 Days Total Sale Amount
        </div>
        <div class="card-body">
            <div id="bar_chart"></div>
        </div>
    </div>
</div>
<script>
    // Pie Chart
    var options = {
        fill: {
            colors: ['#3366cc', '#660066', '#006600', '#cc0066', '#996633', '#006666', '#993399', '#999966',
                '#ffcc99', '#33cc33', '#cccc00'
            ]
        },
        series: <?php echo json_encode($pie_series); ?>,
        chart: {
            height: 400,
            type: 'pie',
        },
        labels: <?php echo json_encode($pie_labels); ?>,
        legend: {
            position: 'bottom'
        },
        responsive: [{
            breakpoint: 480,
            options: {
                chart: {
                    width: 200
                },
                legend: {
                    position: 'bottom'
                }
            }
        }],
        dataLabels: {
            enabled: true,
            formatter: function(val) {
                return val.toFixed(2) + "%"
            },
            dropShadow: {}
        },
        tooltip: {
            shared: true,
            intersect: false,
            y: {
                formatter: function(value) {
                    try {
                        if (typeof value !== "number") {
                            if (value && !isNaN(value)) {
                                value = parseFloat(value);
                            } else {
                                return value;
                            }
                        }
                        var formatter = new Intl.NumberFormat("en-US", {
                            style: "decimal",
                            minimumFractionDigits: 2,
                            maximumFractionDigits: 2,
                        });
                        return "$" + formatter.format(value);
                    } catch (ex) {
                        return "$" + value;
                    }
                }
            }
        },
    };

    var chart = new ApexCharts(document.querySelector("#pie_chart"), options);
    chart.render();

    // Bar Chart

    var options = {
        series: [{
            name: 'Net Amount',
            data: <?php echo json_encode(array_column($result, 'total')); ?>
        }],
        chart: {
            height: 350,
            type: 'bar',
        },
        plotOptions: {
            bar: {
                borderRadius: 10,
                dataLabels: {
                    position: 'top', // top, center, bottom
                },
            }
        },
        dataLabels: {
            enabled: true,
            formatter: function(val) {
                return "$" + val;
            },
            offsetY: -20,
            style: {
                fontSize: '12px',
                colors: ["#304758"]
            }
        },

        xaxis: {
            categories: <?php echo json_encode(array_column($result, 'date')); ?>,
            position: 'top',
            axisBorder: {
                show: false
            },
            axisTicks: {
                show: false
            },
            crosshairs: {
                fill: {
                    type: 'gradient',
                    gradient: {
                        colorFrom: '#D8E3F0',
                        colorTo: '#BED1E6',
                        stops: [0, 100],
                        opacityFrom: 0.4,
                        opacityTo: 0.5,
                    }
                }
            },
            tooltip: {
                enabled: true,
            }
        },
        yaxis: {
            axisBorder: {
                show: false
            },
            axisTicks: {
                show: false,
            },
            labels: {
                show: false,
                formatter: function(val) {
                    return "$" + val;
                }
            }
        }
    };

    var chart = new ApexCharts(document.querySelector("#bar_chart"), options);
    chart.render();
</script>

Running and Testing Your Project

After setting everything up, you will run and test your project to ensure the laravel jquery pos chart reports load correctly. This includes checking Ajax responses, verifying chart rendering, and confirming the POS data updates smoothly inside your reports page.

Open your Terminal/CMD in separate windows, go to the project’s root folder, and then run the command below:

npm run dev
php artisan serve

With both commands running in their separate windows, open your web browser to the Laravel address (http://127.0.0.1:8000).

Graph Reports Setup Complete

You have now completed the setup for laravel jquery pos chart reports. Your Laravel POS system can successfully generate interactive charts and visual reports using jQuery, Ajax, and ApexCharts, giving users a clear overview of sales analytics.

With this final feature, your POS app is not only functional but also insightful and professional, ready to help business owners make data-driven decisions with ease.

Thank you for following along this complete Laravel POS with jQuery tutorial series! 🚀

Laravel jQuery POS Tutorial for Beginners Series

This step-by-step series will guide you through building a complete Laravel jQuery POS system from scratch:

Senghok
Senghok

Senghok is a web developer who enjoys working with Laravel and Vue.js. He creates easy-to-follow tutorials and guides to help beginners learn step by step. His goal is to make learning web development simple and fun for everyone.

Articles: 44

Newsletter Updates

Enter your email address below and subscribe to our newsletter

Leave a Reply

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