|
|
<!DOCTYPE html><html lang="en" xmlns:th="http://www.thymeleaf.org"><head th:replace="~{fragments/head-admin :: head}"> <meta charset="UTF-8"> <title>Title</title> <script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"> <link rel="stylesheet" href="https://cdn.datatables.net/1.11.5/css/jquery.dataTables.min.css"> <script th:src="@{/js/ajax.js}"></script> <link rel="stylesheet" href="/node_modules/amcharts3/amcharts/plugins/export/export.css" type="text/css" media="all" /> <p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p></head>
<style>.custom-close-button { background-color: red; border: none;
color: #FFFFFF; /* Change the color to red */ transition: color 0.2s ease-in-out, opacity 0.2s ease-in-out;}
.custom-close-button:hover { color:black; opacity: 1; /* Fully opaque on hover */}
.custom-close-button:focus { outline: none; /* Remove the default focus outline */ }
.modal-body { max-height: 500px; /* Adjust the height as needed */ overflow-y: auto; /* Enable vertical scrolling */ }.modal-body { max-height: 500px; /* Adjust the height as needed */ overflow-y: auto; /* Enable vertical scrolling */ }.pagination { display: flex; justify-content: center; align-items: center; margin-top: 20px;}
.pagination .btn { margin: 0 10px;}
.pagination .btn.disabled { background-color: #cccccc; border-color: #cccccc; cursor: not-allowed;}
.pagination .btn:not(.disabled):hover { background-color: #0056b3; /* Darker shade for hover effect */ border-color: #0056b3;}
.page-info { margin: 0 10px; font-weight: bold; color: #333;}
.pagination span { margin: 0 10px; line-height: 2; } .modal-header { background-color: darkcyan; color: white; }
.modal-body { padding: 20px; }
.table-responsive { margin-bottom: 20px; }
.modal-footer { display: flex; justify-content: space-between; }
.btn-secondary { background-color: #3cb371; }
.btn-secondary:hover { background-color: #3cb371; } .btn-warning { background-color: red; }
.btn-warning:hover { background-color: orange; }
.btn-export { margin-left: 5px; }
.hidden { display: none;}#page-container.page-header-fixed #main-container { padding-top: 1rem !important;}.card{box-shadow: rgba(0, 0, 0, 0.5) 0px 3px 8px !important;}.row tail{ display: flex;}.col-lg-4, .col-md-4, .col-sm-12 { display: flex; flex-direction: column; justify-content: space-between;}.boxcard { height: 100px; border-radius: 20px;}.boxcard1 { height: 200px; border-radius: 20px;}@media (min-width: 768px) { .card boxcard { margin-bottom: 20%; }}</style>
<body class="light-theme"><link rel="stylesheet" href="node_modules/amcharts3/amcharts/plugins/export/export.css" type="text/css" media="all" /><div id="page-container" class="sidebar-o sidebar-dark enable-page-overlay side-scroll page-header-fixed page-header-dark"> <aside th:replace="~{fragments/aside-right :: aside}"></aside> <nav th:replace="~{fragments/nav-admin :: nav}"></nav> <header th:replace="~{fragments/header-admin :: header}"></header>
<main id="main-container"> <div class="content"> <div class="content content-full">
<div class="col-md-12">
<div class="card-header"> <h3> <i class="fas fa-chart-pie pr-2"></i><b>Overall Dashboard:</b> </h3> </div>
<div class="card"> <diV class="card-body"> <div class="row" > <div class="col-sm-3 mb-3"> <label for="fromDate" style="font-size:medium; ;margin-bottom: 0px;">From Date:</label> <input type="date" id="fromDate" name="fromDate" value="${fromDate}" class="form-control"> </div> <div class="col-sm-3 mb-3"> <label for="toDate" style="font-size:medium;margin-bottom: 0px;">To Date:</label> <input type="date" id="toDate" name="toDate" value="${toDate}" class="form-control"> </div>
<div class="col-sm-3 mb-3"> <label for="zone1" class="pr-2" style="font-size:medium;margin-bottom: 0px;">Select Zone:</label> <select class="form-select custom-select" name="zone1" id="zone1" onchange="filterDivisions()" > <option value="ALL">--Select Zone--</option>
</select> </div>
<div class="col-sm-3 mb-3 hidden" id="divisionContainer"> <label for="division1" class="pr-2" style="font-size:medium;margin-bottom: 0px;">Select Ward:</label> <select id="division1" name="division1" class="form-select custom-select" onchange="filterHalls()"> <option value="ALL">--Select Div--</option>
</select> </div>
<div class="col-sm-3 mb-3 hidden" id="hallContainer"> <label for="hall1" class="pr-2" style="font-size:medium;margin-bottom: 0px;">Select Hall:</label> <select id="hall1" name="hall1" class="form-select custom-select">
</select> </div>
<div class="col-sm-3 mb-3"> <label for="userType" class="pr-2" style="font-size:medium;margin-bottom: 0px;">User Type:</label> <select id="userType" name="userType" class="form-select custom-select" > <option value="ALL">--Select UserType--</option> <option value="PUBLIC">PUBLIC</option> <option value="PENSIONER">PENSIONER</option> <option value="GCC_EMPLOYEE">GCC EMPLOYEE</option> <option value="COUNCILLOR">COUNCILLOR</option> <!-- Add userType options dynamically --> </select> </div>
</div>
<div class="row"> <div class="col-12 d-flex justify-content-center"> <button type="submit" id="filterButton" class="btn btn-primary mx-2">Filter</button>
<button class="btn btn-danger mx-2" onclick="resetDate()" name="reset" type="reset">Reset</button> </div> </div>
</div> </div>
<br>
<div class="card-block" style="text-align:center;background-color: #F6F7FB;"> <div id="chart" class="row">
<div class="col-12"> <div class="row tail"> <!-- First Part: 2 cards vertically --> <div class="col-lg-4 col-md-4 col-sm-12"> <div class="card boxcard"> <div class="card-body"> <h5 class="card-title" style="font-size: 14px;">Total Amount Received</h5> <p class="card-text" id="totalAmount" style="font-size: large; font-weight: bold;"></p> </div> </div> <div class="card boxcard"> <div class="card-body"> <h5 class="card-title" style="font-size: 14px;">Total Refund Amount</h5> <p class="card-text" id="totalRefundedAmount" style="font-size: large; font-weight: bold;"></p> </div> </div> </div> <!-- Second Part: 1 card, height equal to both cards in the first part --> <div class="col-lg-4 col-md-4 col-sm-12 mt-3"> <div class="card boxcard1"> <div class="card-body"> <h3 class="card-title mt-3 mb-4" style="font-size: 14px;">Total Bookings</h3> <p class="card-text" id="totalBookings" style="font-size:40px; font-weight: bold;"></p> </div> </div> </div> <!-- Third Part: 2 cards vertically --> <div class="col-lg-4 col-md-4 col-sm-12"> <div class="card boxcard"> <div class="card-body"> <h5 class="card-title" style="font-size: 14px;">NetAmount</h5> <p class="card-text" id="netAmount" style="font-size: large; font-weight: bold;"></p> </div> </div> <div class="card boxcard"> <div class="card-body"> <h5 class="card-title" style="font-size: 14px;">GST</h5> <p class="card-text" id="gstAmount" style="font-size: large; font-weight: bold;"></p> </div> </div> </div> </div> </div> </div> </div> <br> <div class="card-block" style="text-align:center;background-color: #F6F7FB;"> <div class="row" > <div class="col-sm-12 col-lg-4" > <div class="card" style="width:100%;" > <div id="booking-status-chartdiv" class="chart-shadow" style="height:420px;"></div> </div> </div>
<div class="col-sm-12 col-lg-4"> <div class="card" style="width:100%;"> <div id="refund-status-chartdiv" class="chart-shadow" style="height:420px;"></div> </div> </div> <div class="col-sm-12 col-lg-4"> <div class="card" style="width:100%;"> <div id="reason-chartdiv" class="chart-shadow" style="height:420px;"></div> </div> </div>
</div> </div> <br>
<div class="row"> <div class="col-sm-12 col-lg-6">
<div class="card" style="width:100%;"> <div id="paymentStatus-chartdiv" class="chart-shadow" style="height:420px;"></div> </div> </div> <div class="col-sm-12 col-lg-6">
<div class="card" style="width:100%;"> <div id="past_future-chartdiv" class="chart-shadow" style="height:420px;"></div> </div> </div> </div> <br>
<div class="row"> <div class="col-sm-12 col-lg-12"> <div class="card"> <div id="zonewise-chartdiv" class="chart-shadow" style="height:600px;"></div> </div> </div> </div>
</div>
</div>
</div> </main>
<!-- Modal --> <div class="modal fade backdrop" id="DetailsModal" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="zoneDetailsModalLabel" aria-hidden="true"> <div class="modal-dialog modal-xl" role="document"> <div class="modal-content"> <div id="zone-details-content"></div> </div> </div> </div> <!-- modal-->
<!-- Modal for Hall Details --> <div class="modal fade" id="HallDetailsModal" tabindex="-1" role="dialog" aria-labelledby="HallDetailsModalTitle" aria-hidden="true"> <div class="modal-dialog modal-xl" role="document"> <div class="modal-content" id="hall-details-content"> <!-- Content will be injected by JavaScript --> </div> </div> </div>
<footer th:replace="~{fragments/footer2 :: footer}"></footer></div>
<div th:replace="~{fragments/resetpassword :: div}"></div><script th:replace="~{fragments/script :: script}"></script><script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- Include AmCharts JavaScript libraries --><script src="node_modules/amcharts3/amcharts/amcharts.js"></script><script src="node_modules/amcharts3/amcharts/serial.js"></script><script src="node_modules/amcharts3/amcharts/plugins/export/export.min.js"></script><script src="node_modules/amcharts3/amcharts/plugins/animate/animate.min.js"></script><script src="node_modules/amcharts3/amcharts/pie.js"></script><script src="node_modules/amcharts3/amcharts/themes/light.js"></script><script src="node_modules/tempusdominus-bootstrap-4/build/js/tempusdominus-bootstrap-4.min.js"></script>
<!-- Include Tempus Dominus JavaScript --><script src="https://cdnjs.cloudflare.com/ajax/libs/tempusdominus-bootstrap-4/5.1.6/js/tempusdominus-bootstrap-4.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script><!-- DataTables JS -->
<!-- Bootstrap JavaScript --><script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.bundle.min.js"></script><!-- SheetJS --><script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script><!-- jsPDF --><script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"></script><!-- jsPDF-AutoTable --><script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.13/jspdf.plugin.autotable.min.js"></script>
<!-- Script to handle fetching data and rendering charts --><script>
// Function to generate random dark color function getRandomDarkColor() { var letters = '0123456789ABCDEF'; var color = '#'; for (var i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } return color; }
// Function to fetch data and update charts
function fetchDataAndDisplayCharts(fromDate, toDate, zone, division, hallid,userType) {
var apiUrl = "/victoriahallbooking/admin/api/bookingstatistics"; var queryParams = []; if (fromDate) { queryParams.push("fromDate=" + encodeURIComponent(fromDate)); } if (toDate) { queryParams.push("toDate=" + encodeURIComponent(toDate)); } if (zone) { queryParams.push("zone=" + encodeURIComponent(zone)); } if (division) { queryParams.push("division=" + encodeURIComponent(division)); } if (hallid){ queryParams.push("hallid=" + encodeURIComponent(hallid)); } if (userType) { queryParams.push("userType=" + encodeURIComponent(userType)); }
if (queryParams.length > 0) { apiUrl += "?" + queryParams.join("&"); }
//console.log("API URL:", apiUrl);
$.ajax({ url: apiUrl, type: "GET", dataType:'json', success: function(response) {
//console.log('overallreports:',response);
const data = response; //console.log('Parsed Data:', data);
// Check and create charts if data is available, otherwise display an image
if (data.main && Object.keys(data.main).length > 0) { document.getElementById('totalBookings').innerText = data.main.total; document.getElementById('totalAmount').innerText = "Rs." + data.main.main_total_amount; document.getElementById('totalRefundedAmount').innerText = "Rs." + data.main.main_refunded_amount; document.getElementById('netAmount').innerText = "Rs." + data.main.main_net_amount; document.getElementById('gstAmount').innerText = "Rs." + data.main.main_gst_amount;
animateAmount('totalBookings', data.main.total, 2000); // Duration in milliseconds animateAmount('totalAmount', data.main.main_total_amount, 2000); // Duration in milliseconds animateAmount('totalRefundedAmount', data.main.main_refunded_amount, 2000); animateAmount('netAmount', data.main.main_net_amount, 2000); animateAmount('gstAmount', data.main.main_gst_amount, 2000);
}
else{ document.getElementById("totalBookings").innerHTML = ` <div class="d-flex justify-content-center align-items-center" style="height: 100%;"> <img src='/images/nodata_pic.png' alt='No data available' width='50' height='50' /> </div> `; document.getElementById("totalAmount").innerHTML = ` <div class="d-flex justify-content-center align-items-center" style="height: 100%;"> <img src='staticimages/nodata-founds.png' alt='No data available' width='50' height='50' /> </div> `; document.getElementById("netAmount").innerHTML = ` <div class="d-flex justify-content-center align-items-center" style="height: 100%;"> <img src='media/images/nodata-founds.png' alt='No data available' width='50' height='50' /> </div> `; document.getElementById("totalRefundedAmount").innerHTML = ` <div class="d-flex justify-content-center align-items-center" style="height: 100%;"> <img src='/images/nodata_pic.png' alt='No data available' width='50' height='50' /> </div> `;document.getElementById("gstAmount").innerHTML = ` <div class="d-flex justify-content-center align-items-center" style="height: 100%;"> <img src='/images/nodata_pic.png' alt='No data available' width='50' height='50' /> </div> `; } if (data.bookingStatus && Object.keys(data.bookingStatus).length > 0) { createDonutChart("booking-status-chartdiv", data.bookingStatus, "Booking Status","bookingStatus"); } else { document.getElementById("booking-status-chartdiv").innerHTML = ` <div class="d-flex justify-content-center align-items-center" style="height: 100%;"> <img src='media/images/nodata-founds.png' alt='No data available' width='100' height='100' /> </div> `; }
if (data.refundStatus && Object.keys(data.refundStatus).length > 0) { createDonutChart("refund-status-chartdiv", data.refundStatus, "Refund Status","refundStatus"); } else { document.getElementById("refund-status-chartdiv").innerHTML = ` <div class="d-flex justify-content-center align-items-center" style="height: 100%;"><!-- <img src='media/images/nodata-founds.png' alt='No data available' width='100' height='100' />
</div> `; }
if (data.reason && Object.keys(data.reason).length > 0) { createReasonChart("reason-chartdiv", data.reason, "Event Types"); } else { document.getElementById("reason-chartdiv").innerHTML = ` <div class="d-flex justify-content-center align-items-center" style="height: 100%;"> <img src='media/images/nodata-founds.png' alt='No data available' width='100' height='100' /> </div> `; }
if (data.zonewise && Object.keys(data.zonewise).length > 0) { createZoneChart("zonewise-chartdiv", data.zonewise, "Zonewise Bookings","zonewise"); } else { document.getElementById("zonewise-chartdiv").innerHTML = ` <div class="d-flex justify-content-center align-items-center" style="height: 100%;"> <img src='media/images/nodata-founds.png' alt='No data available' width='100' height='100' /> </div> `; }
if (data.paymentStatus && Object.keys(data.paymentStatus).length > 0) { createZoneCharts("paymentStatus-chartdiv", data.paymentStatus, "Paymentstatus Bookings","paymentStatus"); } else { document.getElementById("paymentStatus-chartdiv").innerHTML = ` <div class="d-flex justify-content-center align-items-center" style="height: 100%;"> <img src='media/images/nodata-founds.png' alt='No data available' width='100' height='100' /> </div> `; } if (data.past_future && Object.keys(data.past_future).length > 0) { // Extract only the desired fields const filteredData = { "PAST_Events": data.past_future.PAST_Events, "FUTURE_Events": data.past_future.FUTURE_Events }; createZoneCharts("past_future-chartdiv", filteredData, "Booking Summary","past_future"); } else { document.getElementById("past_future-chartdiv").innerHTML = ` <div class="d-flex justify-content-center align-items-center" style="height: 100%;"> <img src='media/images/nodata-founds.png' alt='No data available' width='100' height='100' /> </div> `; }
}, error: function(error) { console.error("Error fetching data:", error); } }); }
// Initial call to fetch and display charts with default parameters or initial load
fetchDataAndDisplayCharts();
// Example of handling date input changes to update charts document.getElementById("filterButton").addEventListener("click", function(event) { event.preventDefault(); var fromDate = document.getElementById("fromDate").value; var toDate = document.getElementById("toDate").value; var zone = document.getElementById("zone1").value; var division = document.getElementById("division1").value; var hallid = document.getElementById("hall1").value; var userType = document.getElementById("userType").value;
fetchDataAndDisplayCharts(fromDate, toDate, zone, division, hallid ,userType); });
function formatValue(value) { value = Number(value); // Ensure the value is a number
if (value >= 1e9) { return (value / 1e9).toFixed(2) + ' Billion'; } else if (value >= 1e6) { return (value / 1e6).toFixed(2) + ' Million'; } else if (value >= 1e5) { return (value / 1e5).toFixed(2) + ' Lakh'; } else if (value >= 1e4) { return (value / 1e4).toFixed(2) + ' Thousand'; } return value.toFixed(2); } // colors for each field function getColorByCategory(category, key) { const colors = { bookingStatus: { "PENDING": "#DBAE58", // Orange "APPROVED": "#B3C100", // Greenish "REJECTED": "#D32D41", "COMPLETED" : "#009900", "CANCELED" : "#ff9933", "PAYMENT_FAILURE": "#b35900", "GCC_BLOCKED" : "#ff6600" }, refundStatus: { "WAITING": "#D32D41", "INITIATED": "#DBAE58", "APPROVED": "#B3C100" }, past_future:{ "PAST_Events":"#D32D41", "FUTURE_Events":"#B3C100" }, paymentStatus:{ "Not Completed":"#D32D41", "Success": "#B3C100" }, zonewise:{ "01":"#46659b", "02":"#46659b", "03":"#46659b", "04":"#46659b", "05":"#46659b", "06":"#46659b", "08":"#46659b", "07":"#46659b", "09":"#46659b", "10":"#46659b", "11":"#46659b", "12":"#46659b", "13":"#46659b", "14":"#46659b", "15":"#46659b", } }; if (!colors[category] || !colors[category][key]) { return "#000000"; // Default color } return colors[category][key]; }
// Function to create a donut chart function createDonutChart(chartId, chartData, chartTitle,category) {
chartData = Object.keys(chartData).map(key => ({ "title": key, "value": chartData[key], "color": getColorByCategory(category,key)
}));
/* chartData.forEach(data => { data.color = getRandomDarkColor(); });*/ var zone = document.getElementById("zone1").value; var division = document.getElementById("division1").value;
AmCharts.makeChart(chartId, { "type": "pie", "theme": "dark", "dataProvider": chartData, "valueField": "value", "titleField": "title", "colorField": "color", "startEffect":"elastic", "innerRadius": "45%", "pullOutRadius": "12%",
"labelText": "[[[[value]]]]", "labelsEnabled": true, "gradientRatio": [-0.4, -0.4, -0.4, -0.4, -0.4, -0.4, 0, 0.1, 0.2, 0.1, 0, -0.2, -0.5], "balloonText": "[[[[title]]]]<br><span style='font-size:14px'><b>[[[[value]]]]</b></span>", "export": { "enabled": true, "fileName": `Zone:${zone}_Div:${division}_${chartTitle}`
}, "responsive": { "enabled": true, }, "legend": { "position": "bottom", "markerType": "diamond", "valueAlign": "left", "align": "center", "labelText": "[[[[title]]]] - ", //"reversedOrder": true, "enabled": true, },
"titles": [{ "text": `Zone:${zone} Div:${division} \n \n ${chartTitle}`, "size": 15 }]
}); }
// Function to create a donut chart function createReasonChart(chartId, chartData, chartTitle) {
chartData = Object.keys(chartData).map(key => ({ "title": key, "value": chartData[key],
}));
var existingColors = new Set(); chartData.forEach(data => { data.color = getRandomDarkColor(existingColors); }); var zone = document.getElementById("zone1").value; var division = document.getElementById("division1").value;
AmCharts.makeChart(chartId, { "type": "pie", "theme": "dark", "dataProvider": chartData, "valueField": "value", "titleField": "title", "colorField": "color", "startEffect":"elastic", "innerRadius": "45%", "pullOutRadius": "12%",
"labelText": "[[[[value]]]]", "labelsEnabled": true, "gradientRatio": [-0.4, -0.4, -0.4, -0.4, -0.4, -0.4, 0, 0.1, 0.2, 0.1, 0, -0.2, -0.5], "balloonText": "[[[[title]]]]<br><span style='font-size:14px'><b>[[[[value]]]]</b></span>", "export": { "enabled": true, "fileName": `Zone:${zone}_Div:${division}_${chartTitle}`
}, "responsive": { "enabled": true, }, "legend": { "position": "bottom", "markerType": "diamond", "valueAlign": "left", "align": "center", "labelText": "[[[[title]]]] - ", //"reversedOrder": true, "enabled": true, },
"titles": [{ "text": `Zone:${zone} Div:${division} \n \n ${chartTitle}`, "size": 15 }]
}); }
// Function to payment Status and booking Summary function createZoneCharts(chartId, chartData, chartTitle,category) {
chartData = Object.keys(chartData).map(key => ({ "category": key, "value": chartData[key], "color": getColorByCategory(category,key) })).sort((a, b) => b.value - a.value);
var zone = document.getElementById("zone1").value; var division = document.getElementById("division1").value;
//console.log("Chart Data for", chartId, chartData);
const chartElement = document.getElementById(chartId); const minHeight = 150; // Minimum height in pixels const heightPerZone = 30; // Height per zone in pixels
// Calculate height dynamically const dynamicHeight = Math.max(minHeight, chartData.length * heightPerZone); chartElement.style.height = dynamicHeight + 'px';
AmCharts.makeChart(chartId, { "type": "serial", "theme": "light", "dataProvider": chartData, "depth3D": 2, "angle": 10, "valueAxes": [{ "gridColor": "#808080", "gridAlpha": 0, "dashLength": 0, "axisAlpha": 0, "labelsEnabled": false, "dashLength": 0 }], "gridAboveGraphs": true, "startDuration": 2, "startEffect":"elastic", "graphs": [{ "balloonText": "[[[[category]]]]<br><span style='font-size:14px'><b>[[[[value]]]]</b></span>", "fillAlphas": 0.8, "lineAlpha": 0.2, "topRadius": 1, "type": "column", "valueField": "value", "fillColorsField": "color", "labelText": "[[[[value]]]]", "labelColorField": "#ffffff", "lineThickness": 1, }], "chartCursor": { "valueLineEnabled": false, "valueLineBalloonEnabled": false, "cursorAlpha": 0, "valueLineAlpha": 0.2, "pan": false }, "categoryField": "category", "categoryAxis": { "gridPosition": "start", "gridAlpha": 0, "axisAlpha": 0, "autoWrap": false, //"position": "left" }, "rotate": true, "export": { "enabled": true, "fileName": `Zone:${zone}_Div:${division}_${chartTitle}` }, "titles": [{ "text": `Zone:${zone} Div:${division} \n \n ${chartTitle}`, "size": 15 }], }); }
// Function to create a Zone column chart
function createZoneChart(chartId, chartData, chartTitle,category) {
chartData = Object.keys(chartData).map(key => ({ "category": key, "value": chartData[key], "color": getColorByCategory(category,key) })).sort((a, b) => b.value - a.value);
/* chartData.forEach(data => { data.color = getRandomDarkColor(); }); */ var zone = document.getElementById("zone1").value; var division = document.getElementById("division1").value;
//console.log("Chart Data for", chartId, chartData);
const chartElement = document.getElementById(chartId); const minHeight = 150; // Minimum height in pixels const heightPerZone = 30; // Height per zone in pixels
// Calculate height dynamically const dynamicHeight = Math.max(minHeight, chartData.length * heightPerZone); chartElement.style.height = dynamicHeight + 'px';
AmCharts.makeChart(chartId, { "type": "serial", "theme": "light", "dataProvider": chartData, "depth3D": 2, "angle": 10, "valueAxes": [{ "gridColor": "#808080", "gridAlpha": 0, "dashLength": 0, "axisAlpha": 0, "labelsEnabled": false, "dashLength": 0 }], "gridAboveGraphs": true, "startDuration": 2, "startEffect":"elastic", "graphs": [{ "balloonText": "[[[[category]]]]<br><span style='font-size:14px'><b>[[[[value]]]]</b></span>", "fillAlphas": 0.8, "lineAlpha": 0.2, "topRadius": 1, "type": "column", "valueField": "value", "fillColorsField": "color", "labelText": "[[[[value]]]]", "labelColorField": "#ffffff", "lineThickness": 1, }], "chartCursor": { "valueLineEnabled": false, "valueLineBalloonEnabled": false, "cursorAlpha": 0, "valueLineAlpha": 0.2, "pan": false }, "categoryField": "category", "categoryAxis": { "gridPosition": "start", "gridAlpha": 0, "axisAlpha": 0, "autoWrap": false, //"position": "left" }, "rotate": true, "export": { "enabled": true, "fileName": `Zone:${zone}_Div:${division}_${chartTitle}` }, "titles": [{ "text": `Zone:${zone} Div:${division} \n \n ${chartTitle}`, "size": 15 }], "listeners": [{ "event": "clickGraphItem", "method": function(event) { let zone = event.item.category; fetchZoneDetails(zone); } }] }); }
function fetchZoneDetails(zone) { $.ajax({ url: '/victoriahallbooking/admin/api/getHallsDetailsByZone', type: 'GET', data: { zone: zone }, dataType: 'json', // Ensure response is parsed as JSON success: function(response) { //console.log("response received:",response); displayZoneDetails(response, zone); }, error: function(error) { console.error("Error fetching zone details:", error); } }); }
function displayZoneDetails(response, zone) { //console.log("Display Zone Details Response:", response);
let totalBooking = response.totalBooking; let amountReceived = response.amountReceived; let approvedCount = response.approvedCount; let rejectedCount = response.rejectedCount; let completedCount = response.completedCount; let canceledCount = response.canceledCount; let paymentFailureCount = response.paymentFailureCount; let gccBlockedCount = response.gccBlockedCount;
let zoneHalls = response.zonehalls;
if (!Array.isArray(zoneHalls)) { console.error("zoneHalls is not an array or is undefined:", zoneHalls); return; }
amountReceived = amountReceived.toLocaleString();
const rowsPerPage = 10; // Number of rows per page let currentPage = 1;
function renderTable(page) { const startIndex = (page - 1) * rowsPerPage; const endIndex = startIndex + rowsPerPage; const paginatedData = zoneHalls.slice(startIndex, endIndex);
let modalContent = ` <div class="modal-header"> <h5 class="modal-title" id="DetailsModalTitle"><b>Zone: ${zone} Details</b></h5> <button type="button" class="close custom-close-button" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <div class="table-responsive" style="max-height: 400px; overflow-y: auto;"> <table id="Zonetable" class="table table-striped table-bordered table-hover"> <thead class="thead-dark"> <tr> <th>Zone</th> <th>Division</th> <th>Hall Name</th> <th>Approved</th> <th>Rejected</th> <th>Completed</th> <th>Cancelled</th> <th>Payment Failure</th> <th>GCC Blocked</th> <th>Total Bookings</th> <th>Total Amount</th> </tr> </thead> <tbody>`;
paginatedData.forEach(hall => { modalContent += ` <tr> <td>${hall.zonename}</td> <td>${hall.division}</td> <td>${hall.hallName}</td> <td>${hall.approvedCount}</td> <td>${hall.rejectedCount}</td> <td>${hall.completedCount}</td> <td>${hall.canceledCount}</td> <td>${hall.paymentFailureCount}</td> <td>${hall.gccBlockedCount}</td> <td><b><button style="cursor: pointer; background-color: darkcyan; color: white; border: none; padding: 4px 10px; font-size: 12px; border-radius: 5px;" href="#" class="total-booking" data-hallid="${hall.hall_id}">${hall.totalBookings}</button></b></td> <td>Rs.${hall.totalAmount.toLocaleString()}</td> </tr>`; });
modalContent += ` <tr> <td>Nil</td> <td>Nil</td> <td><b>Total:</b></td> <td><b>${approvedCount}</b></td> <td><b>${rejectedCount}</b></td> <td><b>${completedCount}</b></td> <td><b>${canceledCount}</b></td> <td><b>${paymentFailureCount}</b></td> <td><b>${gccBlockedCount}</b></td> <td><b>${totalBooking}</b></td> <td><b>Rs.${amountReceived}</b></td> </tr> </tbody> </table> </div> <div class="pagination"> <button class="btn btn-primary ${page === 1 ? 'disabled' : ''}" onclick="changePage(${page - 1})">Previous</button> <span class="page-info">Page ${page} of ${Math.ceil(zoneHalls.length / rowsPerPage)}</span> <button class="btn btn-primary ${page === Math.ceil(zoneHalls.length / rowsPerPage) ? 'disabled' : ''}" onclick="changePage(${page + 1})">Next</button></div>
</div> <div class="modal-footer"> <button type="button" class="btn btn-warning custom-close-button" data-dismiss="modal">Close</button> <div class="btn-group" role="group" aria-label="Export Buttons"> <button type="button" class="btn btn-primary btn-export" id="export-excel">Excel</button> <button type="button" class="btn btn-primary btn-export" id="export-csv">CSV</button> <button type="button" class="btn btn-primary btn-export" id="export-pdf">PDF</button> </div> </div>`;
document.getElementById('zone-details-content').innerHTML = modalContent;
$('#DetailsModal').modal('show'); }
function changePage(page) { currentPage = page; renderTable(currentPage); }
// Expose changePage function to global scope window.changePage = changePage;
renderTable(currentPage); // Remove existing event listeners to prevent multiple triggers $(document).off('click', '#export-excel'); $(document).off('click', '#export-csv'); $(document).off('click', '#export-pdf');
// Use jQuery to attach event handlers to dynamically added elements $(document).on('click', '#export-excel', function() { exportToExcel('Zonetable'); }); $(document).on('click', '#export-csv', function() { exportToCSV('Zonetable'); }); $(document).on('click', '#export-pdf', function() { exportToPDF('Zonetable'); });
// Attach click event handler to the close button $(document).on('click', '.custom-close-button', function() { $('#DetailsModal').modal('hide'); }); function exportToExcel(tableId) { const wb = XLSX.utils.table_to_book(document.getElementById(tableId), { sheet: "Zone Details" }); XLSX.writeFile(wb, 'Zone_Details.xlsx');}
function exportToCSV(tableId) { const wb = XLSX.utils.table_to_book(document.getElementById(tableId), { sheet: "Zone Details" }); XLSX.writeFile(wb, 'Zone_Details.csv', { bookType: 'csv' });}
function exportToPDF(tableId) { const { jsPDF } = window.jspdf; const doc = new jsPDF(); doc.autoTable({ html: '#' + tableId }); doc.save('Zone_Details.pdf');}}
document.addEventListener('DOMContentLoaded', function() { fetchData(); });
function fetchData() { fetch('/victoriahallbooking/user/api/getZonehalls') // Replace with your actual API endpoint .then(response => response.json()) .then(data => { populateDropdowns(data); }) .catch(error => console.error('Error fetching data:', error)); }
function populateDropdowns(data) { const zoneDropdown = document.getElementById('zone1'); const divisionDropdown = document.getElementById('division1'); const hallDropdown = document.getElementById('hall1');
const zones = new Set(); const divisionsByZone = {}; const hallsByDivision = {};
data.forEach(item => { zones.add(item.zone); if (!divisionsByZone[item.zone]) { divisionsByZone[item.zone] = []; } if (!divisionsByZone[item.zone].includes(item.division)) { divisionsByZone[item.zone].push(item.division); } if (!hallsByDivision[item.division]) { hallsByDivision[item.division] = []; } hallsByDivision[item.division].push({ hallName: item.hall_name, hallId: item.hall_id }); });
// Populate zones zones.forEach(zone => { const option = document.createElement('option'); option.value = zone; option.textContent = zone; zoneDropdown.appendChild(option); });
// Populate divisions for the first selected zone const selectedZone = zoneDropdown.value; populateDivisions(selectedZone, divisionsByZone);
// Store divisions and halls by zone and division for later use zoneDropdown.dataset.divisionsByZone = JSON.stringify(divisionsByZone); divisionDropdown.dataset.hallsByDivision = JSON.stringify(hallsByDivision); }
function populateDivisions(zone, divisionsByZone) { const divisionDropdown = document.getElementById('division1'); divisionDropdown.innerHTML = ''; // Clear existing options
// Add 'All' option const allOption = document.createElement('option'); allOption.value = 'ALL'; allOption.textContent = '--Select Div--'; divisionDropdown.appendChild(allOption);
if (zone === 'ALL') { // Get all unique divisions across all zones const allDivisions = new Set(); for (const zone in divisionsByZone) { divisionsByZone[zone].forEach(division => allDivisions.add(division)); } allDivisions.forEach(division => { const option = document.createElement('option'); option.value = division; option.textContent = division; divisionDropdown.appendChild(option); }); } else { // Populate divisions for the selected zone divisionsByZone[zone].forEach(division => { const option = document.createElement('option'); option.value = division; option.textContent = division; divisionDropdown.appendChild(option); }); } }
function filterDivisions() { const zoneDropdown = document.getElementById('zone1'); const selectedZone = zoneDropdown.value; const divisionsByZone = JSON.parse(zoneDropdown.dataset.divisionsByZone); if (selectedZone === 'ALL') { document.getElementById('divisionContainer').classList.add('hidden'); } else { document.getElementById('divisionContainer').classList.remove('hidden'); } populateDivisions(selectedZone, divisionsByZone); filterHalls(); // Reset and hide the hall dropdown when the zone changes }
function filterHalls() { const divisionDropdown = document.getElementById('division1'); const selectedDivision = divisionDropdown.value; const hallDropdown = document.getElementById('hall1'); const hallsByDivision = JSON.parse(divisionDropdown.dataset.hallsByDivision);
hallDropdown.innerHTML = ''; // Clear existing options const allOption = document.createElement('option'); allOption.value = '1000'; allOption.textContent = '--Select Hall--'; hallDropdown.appendChild(allOption);
if (selectedDivision === 'ALL') { document.getElementById('hallContainer').classList.add('hidden'); } else { document.getElementById('hallContainer').classList.remove('hidden'); // Populate halls for the selected division hallsByDivision[selectedDivision].forEach(hall => { const option = document.createElement('option'); option.value = hall.hallId; // Pass hall ID as value option.textContent = hall.hallName; hallDropdown.appendChild(option); }); } }
// Function to reset date fields function resetDate() {
window.location.href = "/victoriahallbooking/admin/dashboard";
}
function animateAmount(elementId, targetAmount, duration) { const element = document.getElementById(elementId); let startTime = null; const startAmount = 0;
function updateAmount(currentTime) { if (!startTime) startTime = currentTime; const progress = Math.min((currentTime - startTime) / duration, 1); const animatedAmount = Math.floor(progress * targetAmount);
if (elementId === 'totalAmount' || elementId === 'netAmount' || elementId === 'totalRefundedAmount' || elementId === 'gstAmount') { element.innerText = "Rs. " + animatedAmount; // Format with commas and prepend "Rs." } else { element.innerText = animatedAmount; // Format with commas }
if (progress < 1) { requestAnimationFrame(updateAmount); } else { if (elementId === 'totalAmount' || elementId === 'netAmount' || elementId === 'totalRefundedAmount' || elementId === 'gstAmount') { element.innerText = "Rs. " + targetAmount; // Ensure it ends exactly at targetAmount } else { element.innerText = targetAmount; // Ensure it ends exactly at targetAmount } } }
requestAnimationFrame(updateAmount);}
//Function to generate random dark color and ensure uniquenessfunction getRandomDarkColor(existingColors) { var letters = '0123456789ABCDEF'; var color = '#'; do { color = '#'; for (var i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } } while (existingColors.has(color) || !isDarkColor(color)); existingColors.add(color); return color;}
// Helper function to check if the color is darkfunction isDarkColor(color) { // Convert hex color to RGB var r = parseInt(color.slice(1, 3), 16); var g = parseInt(color.slice(3, 5), 16); var b = parseInt(color.slice(5, 7), 16);
// Calculate brightness using the formula for luminance var brightness = (r * 0.299 + g * 0.587 + b * 0.114) / 255; // Return true if the color is dark (brightness < 0.5) return brightness < 0.5;}
//03/
function fetchHallDetails(hall_id) { $.ajax({ url: '/victoriahallbooking/admin/api/byhallid', type: 'GET', data: { hallId: hall_id }, dataType: 'json', success: function(response) {
displayHallDetails(response); //console.log(response); }, error: function(error) { console.error("Error fetching hall details:", error); } }); }function displayHallDetails(response) { const rowsPerPage = 10; // Number of rows per page let currentPage = 1;
function renderTable(page) { const startIndex = (page - 1) * rowsPerPage; const endIndex = startIndex + rowsPerPage; const paginatedData = response.slice(startIndex, endIndex);
let hallDetailsContent = ` <div class="modal-header"> <h5 class="modal-title"><b>Hall Booking Details</b></h5> <button type="button" class="close custom-close-button" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <div class="table-responsive"> <table id="halldetails" class="table table-striped table-bordered table-hover"> <thead class="thead-dark"> <tr> <th>Booking Date</th> <th>User Name</th> <th>User Type</th> <th>Reason</th> <th>Event Date</th> <th>No of Days</th> <th>Status</th> <th>Amount Paid</th> <th>Amount Refunded</th> <th>Net Revenue</th>
</tr> </thead> <tbody>`;
paginatedData.forEach(booking => { hallDetailsContent += ` <tr> <td>${booking.booking_date}</td> <td>${booking.name}</td> <td>${booking.usertype}</td> <td>${booking.reason}</td> <td>${booking.start_date} to ${booking.end_date}</td> <td>${booking.no_of_days}</td> <td>${booking.booking_status}</td> <td>Rs.${booking.amount_received.toFixed(2)}</td> <td>Rs.${booking.amount_refunded}</td> <td>Rs.${booking.balance_amount}</td> </tr>`; });
hallDetailsContent += ` </tbody> </table> </div> <div class="pagination"> <button class="btn btn-primary ${page === 1 ? 'disabled' : ''}" onclick="changePage(${page - 1})">Previous</button> <span class="page-info">Page ${page} of ${Math.ceil(response.length / rowsPerPage)}</span> <button class="btn btn-primary ${page === Math.ceil(response.length / rowsPerPage) ? 'disabled' : ''}" onclick="changePage(${page + 1})">Next</button></div>
</div> <div class="modal-footer"> <button type="button" class="btn btn-warning custom-close-button" data-dismiss="modal">Close</button> <div class="btn-group" role="group" aria-label="Export Buttons"> <button type="button" class="btn btn-primary btn-export" id="export-excel">Excel</button> <button type="button" class="btn btn-primary btn-export" id="export-csv">CSV</button> <button type="button" class="btn btn-primary btn-export" id="export-pdf">PDF</button> </div> </div>`;
document.getElementById('hall-details-content').innerHTML = hallDetailsContent; $('#HallDetailsModal').modal('show'); }
function changePage(page) { currentPage = page; renderTable(currentPage); }
// Expose changePage function to global scope window.changePage = changePage;
renderTable(currentPage); // Remove existing event listeners to prevent multiple triggers $(document).off('click', '#export-excel'); $(document).off('click', '#export-csv'); $(document).off('click', '#export-pdf'); // Use jQuery to attach event handlers to dynamically added elements $(document).on('click', '#export-excel', function() { exportToExcel('halldetails'); }); $(document).on('click', '#export-csv', function() { exportToCSV('halldetails'); }); $(document).on('click', '#export-pdf', function() { exportToPDF('halldetails'); }); function exportToExcel(tableId) { const wb = XLSX.utils.table_to_book(document.getElementById(tableId), { sheet: "Halldetails" }); XLSX.writeFile(wb, 'Halldetails.xlsx');}
function exportToCSV(tableId) { const wb = XLSX.utils.table_to_book(document.getElementById(tableId), { sheet: "Halldetails" }); XLSX.writeFile(wb, 'Halldetails.csv', { bookType: 'csv' });}
function exportToPDF(tableId) { const { jsPDF } = window.jspdf; const doc = new jsPDF(); doc.autoTable({ html: '#' + tableId }); doc.save('Halldetails.pdf');}
}
$(document).ready(function() { // Attach click event handler to the total bookings links $(document).on('click', '.total-booking', function(event) { event.preventDefault(); $('#DetailsModal').modal('hide'); let hallId = $(this).data('hallid'); fetchHallDetails(hallId); });
// Close button event handler $(document).on('click', '.custom-close-button', function() { $('#DetailsModal').modal('hide'); $('#HallDetailsModal').modal('hide'); }); });
document.addEventListener('DOMContentLoaded', function() { const fromDate = document.getElementById('fromDate'); const toDate = document.getElementById('toDate');
// Initially disable the "To Date" field toDate.disabled = true;
fromDate.addEventListener('change', function() { if (fromDate.value) { // Enable the "To Date" field when "From Date" is selected toDate.disabled = false;
// Get the selected "From Date" const selectedFromDate = new Date(fromDate.value);
// Set the "To Date" minimum to the same day as the "From Date" const sameDayString = selectedFromDate.toISOString().split('T')[0]; toDate.setAttribute('min', sameDayString);
// Set the "To Date" value to the next day by default toDate.value = sameDayString;
} else { // Disable the "To Date" field if "From Date" is cleared toDate.disabled = true; toDate.value = ''; // Clear the "To Date" input } }); });
</script></body></html>
|