You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1369 lines
48 KiB

1 year ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
  1. <!doctype html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head th:replace="~{fragments/head-public :: head}">
  4. </head>
  5. <style>
  6. .custom-close-button {
  7. background-color: red;
  8. border: none;
  9. color: #FFFFFF; /* Change the color to red */
  10. transition: color 0.2s ease-in-out, opacity 0.2s ease-in-out;
  11. }
  12. .custom-close-button:hover {
  13. color:black;
  14. opacity: 1; /* Fully opaque on hover */
  15. }
  16. .custom-close-button:focus {
  17. outline: none; /* Remove the default focus outline */
  18. }
  19. .modal-body {
  20. max-height: 500px; /* Adjust the height as needed */
  21. overflow-y: auto; /* Enable vertical scrolling */
  22. }
  23. .modal-body {
  24. max-height: 500px; /* Adjust the height as needed */
  25. overflow-y: auto; /* Enable vertical scrolling */
  26. }
  27. .pagination {
  28. display: flex;
  29. justify-content: center;
  30. align-items: center;
  31. margin-top: 20px;
  32. }
  33. .pagination .btn {
  34. margin: 0 10px;
  35. }
  36. .pagination .btn.disabled {
  37. background-color: #cccccc;
  38. border-color: #cccccc;
  39. cursor: not-allowed;
  40. }
  41. .pagination .btn:not(.disabled):hover {
  42. background-color: #0056b3; /* Darker shade for hover effect */
  43. border-color: #0056b3;
  44. }
  45. .page-info {
  46. margin: 0 10px;
  47. font-weight: bold;
  48. color: #333;
  49. }
  50. .pagination span {
  51. margin: 0 10px;
  52. line-height: 2;
  53. }
  54. .modal-header {
  55. background-color: darkcyan;
  56. color: white;
  57. }
  58. .modal-body {
  59. padding: 20px;
  60. }
  61. .table-responsive {
  62. margin-bottom: 20px;
  63. }
  64. .modal-footer {
  65. display: flex;
  66. justify-content: space-between;
  67. }
  68. .btn-secondary {
  69. background-color: #3cb371;
  70. }
  71. .btn-secondary:hover {
  72. background-color: #3cb371;
  73. }
  74. .btn-warning {
  75. background-color: red;
  76. }
  77. .btn-warning:hover {
  78. background-color: orange;
  79. }
  80. .btn-export {
  81. margin-left: 5px;
  82. }
  83. .hidden {
  84. display: none;
  85. }
  86. #page-container.page-header-fixed #main-container {
  87. padding-top: 1rem !important;
  88. }
  89. .card{
  90. box-shadow: rgba(0, 0, 0, 0.5) 0px 3px 8px !important;
  91. }
  92. </style>
  93. <body>
  94. <link rel="stylesheet" href="node_modules/amcharts3/amcharts/plugins/export/export.css" type="text/css" media="all" />
  95. <!-- Page Container -->
  96. <div id="page-container"
  97. class="sidebar-o sidebar-dark enable-page-overlay side-scroll page-header-fixed page-header-dark">
  98. <!-- Sidebar Nav-->
  99. <nav th:replace="~{fragments/nav-officer :: nav}"></nav>
  100. <!-- END Sidebar -->
  101. <!-- Header -->
  102. <header th:replace="~{fragments/header-officer :: header}"></header>
  103. <!-- END Header -->
  104. <!-- Main Container -->
  105. <main id="main-container" style="background-color: #F6F7FB;">
  106. <!-- Hero -->
  107. <div class="">
  108. <br><br>
  109. <div class="content content-full">
  110. <div class="d-flex flex-column flex-sm-row justify-content-sm-between align-items-sm-center">
  111. <h3 class="flex-grow-1 fs-5 fw-semibold my-2 my-sm-3">Welcome Zone: <span th:text="${zone}"></span>&nbsp;officer!</h3>
  112. </div>
  113. </div>
  114. </div>
  115. <!-- END Hero -->
  116. <div class="block-content">
  117. <div class="col-md-12">
  118. <div class="card-header">
  119. <h3>
  120. <i class="fas fa-chart-pie pr2"></i>&nbsp;<b>Dashboard</b>
  121. </h3>
  122. </div>
  123. <div class="card">
  124. <diV class="card-body">
  125. <div class="row" >
  126. <div class="col-sm-3 mb-3">
  127. <label for="fromDate" style="font-size:medium; ;margin-bottom: 0px;">From Date:</label>
  128. <input type="date" id="fromDate" name="fromDate" value="${fromDate}" class="form-control">
  129. </div>
  130. <div class="col-sm-3 mb-3">
  131. <label for="toDate" style="font-size:medium;margin-bottom: 0px;">To Date:</label>
  132. <input type="date" id="toDate" name="toDate" value="${toDate}" class="form-control">
  133. </div>
  134. <input type="hidden" id="zoneValue" th:value="${zone}">
  135. <div class="col-sm-3 mb-3">
  136. <label for="division1" class="pr-2" style="font-size:medium;margin-bottom: 0px;">Select Ward:</label>
  137. <select id="division1" name="division1" class="form-select custom-select" onchange="filterHalls()">
  138. <option value="ALL">ALL</option>
  139. <!-- Division options will be populated dynamically -->
  140. </select>
  141. </div>
  142. <div class="col-sm-3 mb-3 hidden" id="hallContainer">
  143. <label for="hall1" class="pr-2" style="font-size:medium;margin-bottom: 0px;">Select Hall:</label>
  144. <select id="hall1" name="hall1" class="form-select custom-select">
  145. <option value="1000">ALL</option> <!-- "All" option with value 1000 -->
  146. <!-- Hall options will be populated dynamically -->
  147. </select>
  148. </div>
  149. <div class="col-sm-3 mb-3">
  150. <label for="userType" class="pr-2" style="font-size:medium;margin-bottom: 0px;">User Type:</label>
  151. <select id="userType" name="userType" class="form-select custom-select" >
  152. <option value="ALL">ALL</option>
  153. <option value="PUBLIC">PUBLIC</option>
  154. <option value="PENSIONER">PENSIONER</option>
  155. <option value="GCC_EMPLOYEE">GCC EMPLOYEE</option>
  156. <option value="COUNCILLOR">COUNCILLOR</option>
  157. </select>
  158. </div>
  159. </div>
  160. <div class="row">
  161. <div class="col-12 d-flex justify-content-center">
  162. <button type="submit" id="filterButton" class="btn btn-primary mx-2">Filter</button>
  163. <button class="btn btn-danger mx-2" onclick="resetData()" name="reset" type="reset">Reset</button>
  164. </div>
  165. </div>
  166. </div>
  167. </div>
  168. <br>
  169. <div class="card-block" style="text-align:center;background-color: #F6F7FB;">
  170. <div id="chart" class="row">
  171. <div class="col-sm-12 col-lg-6">
  172. <div class="card" style="height: 100px;">
  173. <div class="card-body">
  174. <h5 class="card-title" style="font-size:14px;">Total Bookings</h5>
  175. <p class="card-text" id="totalBookings" style="font-size:large; font-weight: bold;"></p>
  176. </div>
  177. </div>
  178. </div>
  179. <div class="col-sm-12 col-lg-6">
  180. <div class="card" style="height: 100px;">
  181. <div class="card-body">
  182. <h5 class="card-title" style="font-size:14px;">Total Amount Received</h5>
  183. <p class="card-text" id="totalAmount" style="font-size: large;font-weight: bold;">Rs.</p>
  184. </div>
  185. </div>
  186. </div>
  187. </div>
  188. </div>
  189. <br>
  190. <div class="card-block" style="text-align:center;background-color: #F6F7FB;">
  191. <div class="row" >
  192. <div class="col-sm-12 col-lg-4" >
  193. <div class="card" style="width:100%;" >
  194. <div id="booking-status-chartdiv" class="chart-shadow" style="height:420px;"></div>
  195. </div>
  196. </div>
  197. <div class="col-sm-12 col-lg-4">
  198. <div class="card" style="width:100%;">
  199. <div id="refund-status-chartdiv" class="chart-shadow" style="height:420px;"></div>
  200. </div>
  201. </div>
  202. <div class="col-sm-12 col-lg-4">
  203. <div class="card" style="width:100%;">
  204. <div id="reason-chartdiv" class="chart-shadow" style="height:420px;"></div>
  205. </div>
  206. </div>
  207. </div>
  208. </div>
  209. <br>
  210. <div class="row">
  211. <div class="col-sm-12 col-lg-6">
  212. <div class="card" style="width:100%;">
  213. <div id="paymentStatus-chartdiv" class="chart-shadow" style="height:150px;"></div>
  214. </div>
  215. </div>
  216. <div class="col-sm-12 col-lg-6">
  217. <div class="card" style="width:100%;">
  218. <div id="past_future-chartdiv" class="chart-shadow" style="height:150px;"></div>
  219. </div>
  220. </div>
  221. </div>
  222. <br>
  223. <div class="row">
  224. <div class="col-sm-12 col-lg-12">
  225. <div class="card">
  226. <div id="zonewise-chartdiv" class="chart-shadow" style="height:600px;"></div>
  227. </div>
  228. </div>
  229. </div>
  230. </div>
  231. </div>
  232. </main>
  233. <!-- END Main Container -->
  234. <!--modal for pening-->
  235. <!-- Modal -->
  236. <div class="modal fade" id="DetailsModal" tabindex="-1"
  237. role="dialog" aria-labelledby="zoneDetailsModalLabel"
  238. aria-hidden="true" data-backdrop="static" data-keyboard="false">
  239. <div class="modal-dialog modal-xl" role="document">
  240. <div class="modal-content">
  241. <div id="zone-details-content"></div>
  242. </div>
  243. </div>
  244. </div>
  245. <div class="modal fade" id="HallDetailsModal" tabindex="-1" role="dialog" aria-labelledby="HallDetailsModalTitle" aria-hidden="true" data-backdrop="static" data-keyboard="false">
  246. <div class="modal-dialog modal-xl" role="document">
  247. <div class="modal-content" id="hall-details-content">
  248. <!-- Content will be injected by JavaScript -->
  249. </div>
  250. </div>
  251. </div>
  252. <!-- End Modal User -->
  253. <!-- Footer -->
  254. <footer th:replace="~{fragments/footer2 :: footer}"></footer>
  255. <!-- END Footer -->
  256. </div>
  257. <!-- Scripts -->
  258. <script th:replace="~{fragments/script :: script}"></script>
  259. <div th:replace="~{fragments/resetpassword :: div}"></div>
  260. <!-- Include AmCharts JavaScript libraries -->
  261. <script src="node_modules/amcharts3/amcharts/amcharts.js"></script>
  262. <script src="node_modules/amcharts3/amcharts/serial.js"></script>
  263. <script src="node_modules/amcharts3/amcharts/plugins/export/export.min.js"></script>
  264. <script src="node_modules/amcharts3/amcharts/plugins/animate/animate.min.js"></script>
  265. <script src="node_modules/amcharts3/amcharts/pie.js"></script>
  266. <script src="node_modules/amcharts3/amcharts/themes/light.js"></script>
  267. <script src="node_modules/tempusdominus-bootstrap-4/build/js/tempusdominus-bootstrap-4.min.js"></script>
  268. <!-- DataTables JS -->
  269. <!-- Bootstrap JavaScript -->
  270. <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.bundle.min.js"></script>
  271. <!-- SheetJS -->
  272. <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
  273. <!-- jsPDF -->
  274. <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"></script>
  275. <!-- jsPDF-AutoTable -->
  276. <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.13/jspdf.plugin.autotable.min.js"></script>
  277. <!-- Script to handle fetching data and rendering charts -->
  278. <script>
  279. //Function to generate random dark color and ensure uniqueness
  280. function getRandomDarkColor(existingColors) {
  281. var letters = '0123456789ABCDEF';
  282. var color = '#';
  283. do {
  284. color = '#';
  285. for (var i = 0; i < 6; i++) {
  286. color += letters[Math.floor(Math.random() * 16)];
  287. }
  288. } while (existingColors.has(color) || !isDarkColor(color));
  289. existingColors.add(color);
  290. return color;
  291. }
  292. // Helper function to check if the color is dark
  293. function isDarkColor(color) {
  294. // Convert hex color to RGB
  295. var r = parseInt(color.slice(1, 3), 16);
  296. var g = parseInt(color.slice(3, 5), 16);
  297. var b = parseInt(color.slice(5, 7), 16);
  298. // Calculate brightness using the formula for luminance
  299. var brightness = (r * 0.299 + g * 0.587 + b * 0.114) / 255;
  300. // Return true if the color is dark (brightness < 0.5)
  301. return brightness < 0.5;
  302. }
  303. // Function to fetch data and update charts
  304. function fetchDataAndDisplayCharts(fromDate, toDate, zone, division, hallid,userType) {
  305. var apiUrl = "/communityhall/api/officer/bookingstatistics";
  306. var queryParams = [];
  307. if (fromDate) {
  308. queryParams.push("fromDate=" + encodeURIComponent(fromDate));
  309. }
  310. if (toDate) {
  311. queryParams.push("toDate=" + encodeURIComponent(toDate));
  312. }
  313. if (zone) {
  314. queryParams.push("zone=" + encodeURIComponent(zone));
  315. }
  316. if (division) {
  317. queryParams.push("division=" + encodeURIComponent(division));
  318. }
  319. if (hallid){
  320. queryParams.push("hallid=" + encodeURIComponent(hallid));
  321. }
  322. if (userType) {
  323. queryParams.push("userType=" + encodeURIComponent(userType));
  324. }
  325. if (queryParams.length > 0) {
  326. apiUrl += "?" + queryParams.join("&");
  327. }
  328. $.ajax({
  329. url: apiUrl,
  330. type: "GET",
  331. dataType:'json',
  332. success: function(response) {
  333. const data = response;
  334. // Check and create charts if data is available, otherwise display an image
  335. if (data.main && Object.keys(data.main).length > 0) {
  336. document.getElementById('totalBookings').innerText = data.main.total;
  337. document.getElementById('totalAmount').innerText = "Rs. " + data.main.main_total_amount;
  338. animateAmount('totalBookings', data.main.total, 2000); // Duration in milliseconds
  339. animateAmount('totalAmount', data.main.main_total_amount, 2000); // Duration in milliseconds
  340. }
  341. else{
  342. document.getElementById("totalBookings").innerHTML = `
  343. <div class="d-flex justify-content-center align-items-center" style="height: 100%;">
  344. <img src='media/images/nodata-founds.png' alt='No data available' width='50' height='50' />
  345. </div>
  346. `;
  347. document.getElementById("totalAmount").innerHTML = `
  348. <div class="d-flex justify-content-center align-items-center" style="height: 100%;">
  349. <img src='media/images/nodata-founds.png' alt='No data available' width='50' height='50' />
  350. </div>
  351. `;
  352. }
  353. if (data.bookingStatus && Object.keys(data.bookingStatus).length > 0)
  354. {
  355. createDonutChart("booking-status-chartdiv", data.bookingStatus, "Booking Status","bookingStatus");
  356. }
  357. else
  358. {
  359. document.getElementById("booking-status-chartdiv").innerHTML = `
  360. <div class="d-flex justify-content-center align-items-center" style="height: 100%;">
  361. <img src='media/images/nodata-founds.png' alt='No data available' width='100' height='100' />
  362. </div>
  363. `;
  364. }
  365. if (data.refundStatus && Object.keys(data.refundStatus).length > 0) {
  366. createDonutChart("refund-status-chartdiv", data.refundStatus, "Refund Status", "refundStatus");
  367. } else {
  368. document.getElementById("refund-status-chartdiv").innerHTML = `
  369. <div class="d-flex justify-content-center align-items-center" style="height: 100%;">
  370. <img src='media/images/nodata-founds.png' alt='No data available' width='100' height='100' />
  371. </div>
  372. `; }
  373. if (data.reason && Object.keys(data.reason).length > 0) {
  374. createReasonChart("reason-chartdiv", data.reason, "Event Types");
  375. } else {
  376. document.getElementById("reason-chartdiv").innerHTML = `
  377. <div class="d-flex justify-content-center align-items-center" style="height: 100%;">
  378. <img src='media/images/nodata-founds.png' alt='No data available' width='100' height='100' />
  379. </div>
  380. `; }
  381. if (data.zonewise && Object.keys(data.zonewise).length > 0) {
  382. createZoneChart("zonewise-chartdiv", data.zonewise, "Zone Bookings","zonewise");
  383. } else {
  384. document.getElementById("zonewise-chartdiv").innerHTML = `
  385. <div class="d-flex justify-content-center align-items-center" style="height: 100%;">
  386. <img src='media/images/nodata-founds.png' alt='No data available' width='100' height='100' />
  387. </div>
  388. `; }
  389. if (data.paymentStatus && Object.keys(data.paymentStatus).length > 0)
  390. {
  391. createZoneCharts("paymentStatus-chartdiv", data.paymentStatus, "Payment Status","paymentStatus");
  392. }
  393. else
  394. {
  395. document.getElementById("paymentStatus-chartdiv").innerHTML = `
  396. <div class="d-flex justify-content-center align-items-center" style="height: 100%;">
  397. <img src='media/images/nodata-founds.png' alt='No data available' width='100' height='100' />
  398. </div>
  399. `;
  400. }
  401. if (data.past_future && Object.keys(data.past_future).length > 0) {
  402. // Extract only the desired fields
  403. const filteredData = {
  404. "PAST_Events": data.past_future.PAST_Events,
  405. "FUTURE_Events": data.past_future.FUTURE_Events
  406. };
  407. createZoneCharts("past_future-chartdiv", filteredData, "Booking Summary","past_future");
  408. } else {
  409. document.getElementById("past_future-chartdiv").innerHTML = `
  410. <div class="d-flex justify-content-center align-items-center" style="height: 100%;">
  411. <img src='media/images/nodata-founds.png' alt='No data available' width='100' height='100' />
  412. </div>
  413. `; }
  414. },
  415. error: function(error) {
  416. console.error("Error fetching data:", error);
  417. }
  418. });
  419. }
  420. function animateAmount(elementId, targetAmount, duration) {
  421. const element = document.getElementById(elementId);
  422. let startTime = null;
  423. const startAmount = 0;
  424. function updateAmount(currentTime) {
  425. if (!startTime) startTime = currentTime;
  426. const progress = Math.min((currentTime - startTime) / duration, 1);
  427. const animatedAmount = Math.floor(progress * targetAmount);
  428. if (elementId === 'totalAmount') {
  429. element.innerText = "Rs. " + animatedAmount; // Format with commas and prepend "Rs."
  430. } else {
  431. element.innerText = animatedAmount; // Format with commas
  432. }
  433. if (progress < 1) {
  434. requestAnimationFrame(updateAmount);
  435. } else {
  436. if (elementId === 'totalAmount') {
  437. element.innerText = "Rs. " + targetAmount; // Ensure it ends exactly at targetAmount
  438. } else {
  439. element.innerText = targetAmount; // Ensure it ends exactly at targetAmount
  440. }
  441. }
  442. }
  443. requestAnimationFrame(updateAmount);
  444. }
  445. // Initial call to fetch and display charts with default parameters or initial load
  446. fetchDataAndDisplayCharts();
  447. // Example of handling date input changes to update charts
  448. document.getElementById("filterButton").addEventListener("click", function(event) {
  449. event.preventDefault();
  450. var fromDate = document.getElementById("fromDate").value;
  451. var toDate = document.getElementById("toDate").value;
  452. var zone = document.getElementById("zoneValue").value;
  453. var division = document.getElementById("division1").value;
  454. var hallid = document.getElementById("hall1").value;
  455. var userType = document.getElementById("userType").value;
  456. fetchDataAndDisplayCharts(fromDate, toDate, zone, division, hallid ,userType);
  457. });
  458. // colors for each field
  459. function getColorByCategory(category, key) {
  460. const colors = {
  461. bookingStatus: {
  462. "PENDING": "#DBAE58", // Orange
  463. "APPROVED": "#B3C100", // Greenish
  464. "REJECTED": "#D32D41",
  465. "COMPLETED" : "#009900",
  466. "CANCELED" : "#ff9933",
  467. "PAYMENT_FAILURE": "#b35900",
  468. "GCC_BLOCKED" : "#ff6600"
  469. },
  470. refundStatus: {
  471. "WAITING": "#D32D41",
  472. "INITIATED": "#DBAE58",
  473. "APPROVED": "#B3C100",
  474. "COMPLETED" : "#009900",
  475. },
  476. past_future:{
  477. "PAST_Events":"#D32D41",
  478. "FUTURE_Events":"#B3C100"
  479. },
  480. paymentStatus:{
  481. "Not Completed":"#D32D41",
  482. "Success": "#B3C100"
  483. },
  484. zonewise:{
  485. "01":"#46659b",
  486. "02":"#46659b",
  487. "03":"#46659b",
  488. "04":"#46659b",
  489. "05":"#46659b",
  490. "06":"#46659b",
  491. "08":"#46659b",
  492. "07":"#46659b",
  493. "09":"#46659b",
  494. "10":"#46659b",
  495. "11":"#46659b",
  496. "12":"#46659b",
  497. "13":"#46659b",
  498. "14":"#46659b",
  499. "15":"#46659b",
  500. }
  501. };
  502. if (!colors[category] || !colors[category][key]) {
  503. return "#000000"; // Default color
  504. }
  505. return colors[category][key];
  506. }
  507. //Function to create a booking status and refund status chart
  508. function createDonutChart(chartId, chartData, chartTitle,category) {
  509. chartData = Object.keys(chartData).map(key => ({
  510. "title": key,
  511. "value": chartData[key],
  512. "color": getColorByCategory(category,key)
  513. }));
  514. /* chartData.forEach(data => {
  515. data.color = getRandomDarkColor();
  516. }); */
  517. var zone = document.getElementById("zoneValue").value;
  518. var division = document.getElementById("division1").value;
  519. AmCharts.makeChart(chartId, {
  520. "type": "pie",
  521. "theme": "dark",
  522. "dataProvider": chartData,
  523. "valueField": "value",
  524. "titleField": "title",
  525. "colorField": "color",
  526. "startEffect":"elastic",
  527. "innerRadius": "45%",
  528. "pullOutRadius": "12%",
  529. "labelText": "[[[[value]]]]",
  530. "labelsEnabled": true,
  531. "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],
  532. "balloonText": "[[[[title]]]]<br><span style='font-size:14px'><b>[[[[value]]]]</b></span>",
  533. "export": {
  534. "enabled": true,
  535. "fileName": `Zone:${zone}_Div:${division}_${chartTitle}`
  536. },
  537. "responsive": {
  538. "enabled": true,
  539. },
  540. "legend": {
  541. "position": "bottom",
  542. "markerType": "diamond",
  543. "valueAlign": "left",
  544. "align": "center",
  545. "labelText": "[[[[title]]]] - ",
  546. //"reversedOrder": true,
  547. "enabled": true,
  548. },
  549. "titles": [{
  550. "text": `Zone:${zone} Div:${division} \n \n ${chartTitle}`,
  551. "size": 15
  552. }]
  553. });
  554. }
  555. //Function to create a reason chart
  556. function createReasonChart(chartId, chartData, chartTitle) {
  557. chartData = Object.keys(chartData).map(key => ({
  558. "title": key,
  559. "value": chartData[key],
  560. }));
  561. var existingColors = new Set();
  562. chartData.forEach(data => {
  563. data.color = getRandomDarkColor(existingColors);
  564. });
  565. var zone = document.getElementById("zoneValue").value;
  566. var division = document.getElementById("division1").value;
  567. AmCharts.makeChart(chartId, {
  568. "type": "pie",
  569. "theme": "dark",
  570. "dataProvider": chartData,
  571. "valueField": "value",
  572. "titleField": "title",
  573. "colorField": "color",
  574. "startEffect":"elastic",
  575. "innerRadius": "45%",
  576. "pullOutRadius": "12%",
  577. "labelText": "[[[[value]]]]",
  578. "labelsEnabled": true,
  579. "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],
  580. "balloonText": "[[[[title]]]]<br><span style='font-size:14px'><b>[[[[value]]]]</b></span>",
  581. "export": {
  582. "enabled": true,
  583. "fileName": `Zone:${zone}_Div:${division}_${chartTitle}`
  584. },
  585. "responsive": {
  586. "enabled": true,
  587. },
  588. "legend": {
  589. "position": "bottom",
  590. "markerType": "diamond",
  591. "valueAlign": "left",
  592. "align": "center",
  593. "labelText": "[[[[title]]]] - ",
  594. //"reversedOrder": true,
  595. "enabled": true,
  596. },
  597. "titles": [{
  598. "text": `Zone:${zone} Div:${division} \n \n ${chartTitle}`,
  599. "size": 15
  600. }]
  601. });
  602. }
  603. // Function for payment and Booking period
  604. function createZoneCharts(chartId, chartData, chartTitle,category) {
  605. chartData = Object.keys(chartData).map(key => ({
  606. "category": key,
  607. "value": chartData[key] ,
  608. "color": getColorByCategory(category,key)
  609. })).sort((a, b) => b.value - a.value);
  610. /* chartData.forEach(data => {
  611. data.color = getRandomDarkColor();
  612. }); */
  613. var zone = document.getElementById("zoneValue").value;
  614. var division = document.getElementById("division1").value;
  615. // console.log("Chart Data for", chartId, chartData);
  616. const chartElement = document.getElementById(chartId);
  617. const minHeight = 150; // Minimum height in pixels
  618. const heightPerZone = 30; // Height per zone in pixels
  619. // Calculate height dynamically
  620. const dynamicHeight = Math.max(minHeight, chartData.length * heightPerZone);
  621. chartElement.style.height = dynamicHeight + 'px';
  622. AmCharts.makeChart(chartId, {
  623. "type": "serial",
  624. "theme": "light",
  625. "dataProvider": chartData,
  626. "depth3D": 2,
  627. "angle": 10,
  628. "valueAxes": [{
  629. "gridColor": "#808080",
  630. "gridAlpha": 0,
  631. "dashLength": 0,
  632. "axisAlpha": 0,
  633. "labelsEnabled": false,
  634. "dashLength": 0
  635. }],
  636. "gridAboveGraphs": true,
  637. "startDuration": 1,
  638. "startEffect":"easeInSine",
  639. "graphs": [{
  640. "balloonText": "[[[[category]]]]<br><span style='font-size:14px'><b>[[[[value]]]]</b></span>",
  641. "fillAlphas": 0.8,
  642. "lineAlpha": 0.2,
  643. "topRadius": 1,
  644. "type": "column",
  645. "valueField": "value",
  646. "fillColorsField": "color",
  647. "labelText": "[[[[value]]]]",
  648. "labelColorField": "#ffffff",
  649. }],
  650. "chartCursor": {
  651. "valueLineEnabled": false,
  652. "valueLineBalloonEnabled": false,
  653. "cursorAlpha": 0,
  654. "valueLineAlpha": 0.2,
  655. "pan": false
  656. },
  657. "categoryField": "category",
  658. "categoryAxis": {
  659. "gridPosition": "start",
  660. "gridAlpha": 0,
  661. "axisAlpha": 0,
  662. "autoWrap": false,
  663. //"position": "left"
  664. },
  665. "rotate": true,
  666. "export": {
  667. "enabled": true,
  668. "fileName": `Zone:${zone}_Div:${division}_${chartTitle}`
  669. },
  670. "titles": [{
  671. "text": `${chartTitle} \n \n Zone:${zone} Div:${division}`,
  672. "size": 15
  673. }],
  674. });
  675. }
  676. // Function to create a Zone column chart
  677. function createZoneChart(chartId, chartData, chartTitle,category) {
  678. chartData = Object.keys(chartData).map(key => ({
  679. "category": key,
  680. "value": chartData[key] ,
  681. "color": getColorByCategory(category,key)
  682. })).sort((a, b) => b.value - a.value);
  683. /* chartData.forEach(data => {
  684. data.color = getRandomDarkColor();
  685. }); */
  686. var zone = document.getElementById("zoneValue").value;
  687. var division = document.getElementById("division1").value;
  688. // console.log("Chart Data for", chartId, chartData);
  689. const chartElement = document.getElementById(chartId);
  690. const minHeight = 150; // Minimum height in pixels
  691. const heightPerZone = 30; // Height per zone in pixels
  692. // Calculate height dynamically
  693. const dynamicHeight = Math.max(minHeight, chartData.length * heightPerZone);
  694. chartElement.style.height = dynamicHeight + 'px';
  695. AmCharts.makeChart(chartId, {
  696. "type": "serial",
  697. "theme": "light",
  698. "dataProvider": chartData,
  699. "depth3D": 2,
  700. "angle": 10,
  701. "valueAxes": [{
  702. "gridColor": "#808080",
  703. "gridAlpha": 0,
  704. "dashLength": 0,
  705. "axisAlpha": 0,
  706. "labelsEnabled": false,
  707. "dashLength": 0
  708. }],
  709. "gridAboveGraphs": true,
  710. "startDuration": 1,
  711. "startEffect":"easeInSine",
  712. "graphs": [{
  713. "balloonText": "[[[[category]]]]<br><span style='font-size:14px'><b>[[[[value]]]]</b></span>",
  714. "fillAlphas": 0.8,
  715. "lineAlpha": 0.2,
  716. "topRadius": 1,
  717. "type": "column",
  718. "valueField": "value",
  719. "fillColorsField": "color",
  720. "labelText": "[[[[value]]]]",
  721. "labelColorField": "#ffffff",
  722. "showHandOnHover":true
  723. }],
  724. "chartCursor": {
  725. "valueLineEnabled": false,
  726. "valueLineBalloonEnabled": false,
  727. "cursorAlpha": 0,
  728. "valueLineAlpha": 0.2,
  729. "pan": false
  730. },
  731. "categoryField": "category",
  732. "categoryAxis": {
  733. "gridPosition": "start",
  734. "gridAlpha": 0,
  735. "axisAlpha": 0,
  736. "autoWrap": false,
  737. //"position": "left"
  738. },
  739. "rotate": true,
  740. "export": {
  741. "enabled": true,
  742. "fileName": `Zone:${zone}_Div:${division}_${chartTitle}`
  743. },
  744. "titles": [{
  745. "text": `${chartTitle} \n \n Zone:${zone} Div:${division}`,
  746. "size": 15
  747. }],
  748. "listeners": [{
  749. "event": "clickGraphItem",
  750. "method": function(event) {
  751. let zone = event.item.category;
  752. fetchZoneDetails(zone);
  753. }
  754. }]
  755. });
  756. }
  757. function fetchZoneDetails(zone) {
  758. $.ajax({
  759. url: '/communityhall/api/officer/getHallsDetailsByZone',
  760. type: 'GET',
  761. data: { zone: zone },
  762. dataType: 'json', // Ensure response is parsed as JSON
  763. success: function(response) {
  764. //console.log("response received:",response);
  765. displayZoneDetails(response, zone);
  766. },
  767. error: function(error) {
  768. //console.error("Error fetching zone details:", error);
  769. }
  770. });
  771. }
  772. function displayZoneDetails(response, zone) {
  773. //console.log("Display Zone Details Response:", response);
  774. let totalBooking = response.totalBooking;
  775. let amountReceived = response.amountReceived;
  776. let approvedCount = response.approvedCount;
  777. let rejectedCount = response.rejectedCount;
  778. let completedCount = response.completedCount;
  779. let canceledCount = response.canceledCount;
  780. let paymentFailureCount = response.paymentFailureCount;
  781. let gccBlockedCount = response.gccBlockedCount;
  782. let zoneHalls = response.zonehalls;
  783. if (!Array.isArray(zoneHalls)) {
  784. //console.error("zoneHalls is not an array or is undefined:", zoneHalls);
  785. return;
  786. }
  787. amountReceived = amountReceived.toFixed(2);
  788. const rowsPerPage = 10; // Number of rows per page
  789. let currentPage = 1;
  790. function renderTable(page) {
  791. const startIndex = (page - 1) * rowsPerPage;
  792. const endIndex = startIndex + rowsPerPage;
  793. const paginatedData = zoneHalls.slice(startIndex, endIndex);
  794. let modalContent = `
  795. <div class="modal-header">
  796. <h5 class="modal-title" id="DetailsModalTitle"><b>Zone: ${zone} Details</b></h5>
  797. <button type="button" class="close custom-close-button" data-dismiss="modal" aria-label="Close">
  798. <span aria-hidden="true">&times;</span>
  799. </button>
  800. </div>
  801. <div class="modal-body">
  802. <div class="table-responsive" style="max-height: 400px; overflow-y: auto;">
  803. <table id="Zonetable" class="table table-striped table-bordered table-hover">
  804. <thead class="thead-dark">
  805. <tr>
  806. <th>Zone</th>
  807. <th>Division</th>
  808. <th>Hall Name</th>
  809. <th>Approved</th>
  810. <th>Rejected</th>
  811. <th>Completed</th>
  812. <th>Cancelled</th>
  813. <th>Payment Failure</th>
  814. <th>GCC Blocked</th>
  815. <th>Total Bookings</th>
  816. <th>Total Amount</th>
  817. </tr>
  818. </thead>
  819. <tbody>`;
  820. paginatedData.forEach(hall => {
  821. modalContent += `
  822. <tr>
  823. <td>${hall.zonename}</td>
  824. <td>${hall.division}</td>
  825. <td>${hall.hallName}</td>
  826. <td>${hall.approvedCount}</td>
  827. <td>${hall.rejectedCount}</td>
  828. <td>${hall.completedCount}</td>
  829. <td>${hall.canceledCount}</td>
  830. <td>${hall.paymentFailureCount}</td>
  831. <td>${hall.gccBlockedCount}</td>
  832. <td><b><button style="cursor: pointer;
  833. background-color: darkcyan;
  834. color: white;
  835. border: none;
  836. padding: 4px 10px;
  837. font-size: 12px;
  838. border-radius: 5px;"
  839. href="#" class="total-booking" data-hallid="${hall.hall_id}">${hall.totalBookings}</button></b></td>
  840. <td>Rs.${hall.totalAmount.toFixed(2)}</td>
  841. </tr>`;
  842. });
  843. modalContent += `
  844. <tr>
  845. <td>Nil</td>
  846. <td>Nil</td>
  847. <td><b>Total:</b></td>
  848. <td><b>${approvedCount}</b></td>
  849. <td><b>${rejectedCount}</b></td>
  850. <td><b>${completedCount}</b></td>
  851. <td><b>${canceledCount}</b></td>
  852. <td><b>${paymentFailureCount}</b></td>
  853. <td><b>${gccBlockedCount}</b></td>
  854. <td><b>${totalBooking}</b></td>
  855. <td><b>Rs.${amountReceived}</b></td>
  856. </tr>
  857. </tbody>
  858. </table>
  859. </div>
  860. <div class="pagination">
  861. <button class="btn btn-primary ${page === 1 ? 'disabled' : ''}" onclick="changePage(${page - 1})">Previous</button>
  862. <span class="page-info">Page ${page} of ${Math.ceil(zoneHalls.length / rowsPerPage)}</span>
  863. <button class="btn btn-primary ${page === Math.ceil(zoneHalls.length / rowsPerPage) ? 'disabled' : ''}" onclick="changePage(${page + 1})">Next</button>
  864. </div>
  865. </div>
  866. <div class="modal-footer">
  867. <button type="button" class="btn btn-warning custom-close-button" data-dismiss="modal">Close</button>
  868. <div class="btn-group" role="group" aria-label="Export Buttons">
  869. <button type="button" class="btn btn-primary btn-export" id="export-excel">Excel</button>
  870. <button type="button" class="btn btn-primary btn-export" id="export-csv">CSV</button>
  871. <button type="button" class="btn btn-primary btn-export" id="export-pdf">PDF</button>
  872. </div>
  873. </div>`;
  874. document.getElementById('zone-details-content').innerHTML = modalContent;
  875. $('#DetailsModal').modal('show');
  876. }
  877. function changePage(page) {
  878. currentPage = page;
  879. renderTable(currentPage);
  880. }
  881. // Expose changePage function to global scope
  882. window.changePage = changePage;
  883. renderTable(currentPage);
  884. // Remove existing event listeners to prevent multiple triggers
  885. $(document).off('click', '#export-excel');
  886. $(document).off('click', '#export-csv');
  887. $(document).off('click', '#export-pdf');
  888. // Use jQuery to attach event handlers to dynamically added elements
  889. $(document).on('click', '#export-excel', function() { exportToExcel('Zonetable'); });
  890. $(document).on('click', '#export-csv', function() { exportToCSV('Zonetable'); });
  891. $(document).on('click', '#export-pdf', function() { exportToPDF('Zonetable'); });
  892. // Attach click event handler to the close button
  893. $(document).on('click', '.custom-close-button', function() {
  894. $('#DetailsModal').modal('hide');
  895. });
  896. }
  897. function exportToExcel(tableId) {
  898. const wb = XLSX.utils.table_to_book(document.getElementById(tableId), { sheet: "Zone Details" });
  899. XLSX.writeFile(wb, 'Zone_Details.xlsx');
  900. }
  901. function exportToCSV(tableId) {
  902. const wb = XLSX.utils.table_to_book(document.getElementById(tableId), { sheet: "Zone Details" });
  903. XLSX.writeFile(wb, 'Zone_Details.csv', { bookType: 'csv' });
  904. }
  905. function exportToPDF(tableId) {
  906. const { jsPDF } = window.jspdf;
  907. const doc = new jsPDF();
  908. doc.autoTable({ html: '#' + tableId });
  909. doc.save('Zone_Details.pdf');
  910. }
  911. function fetchHallDetails(hall_id) {
  912. $.ajax({
  913. url: '/communityhall/api/officer/byhallid',
  914. type: 'GET',
  915. data: { hallId: hall_id },
  916. dataType: 'json',
  917. success: function(response) {
  918. displayHallDetails(response);
  919. //console.log(response);
  920. },
  921. error: function(error) {
  922. console.error("Error fetching hall details:", error);
  923. }
  924. });
  925. }
  926. function displayHallDetails(response) {
  927. const rowsPerPage = 10; // Number of rows per page
  928. let currentPage = 1;
  929. function renderTable(page) {
  930. const startIndex = (page - 1) * rowsPerPage;
  931. const endIndex = startIndex + rowsPerPage;
  932. const paginatedData = response.slice(startIndex, endIndex);
  933. let hallDetailsContent = `
  934. <div class="modal-header">
  935. <h5 class="modal-title"><b>Hall Booking Details</b></h5>
  936. <button type="button" class="close custom-close-button" data-dismiss="modal" aria-label="Close">
  937. <span aria-hidden="true">&times;</span>
  938. </button>
  939. </div>
  940. <div class="modal-body">
  941. <div class="table-responsive">
  942. <table id="halldetails" class="table table-striped table-bordered table-hover">
  943. <thead class="thead-dark">
  944. <tr>
  945. <th>Booking Date</th>
  946. <th>User Name</th>
  947. <th>User Type</th>
  948. <th>Reason</th>
  949. <th>Event Date</th>
  950. <th>No of Days</th>
  951. <th>Status</th>
  952. <th>Amount Paid</th>
  953. <th>Amount Refunded</th>
  954. <th>Net Revenue</th>
  955. </tr>
  956. </thead>
  957. <tbody>`;
  958. paginatedData.forEach(booking => {
  959. hallDetailsContent += `
  960. <tr>
  961. <td>${booking.booking_date}</td>
  962. <td>${booking.name}</td>
  963. <td>${booking.usertype}</td>
  964. <td>${booking.reason}</td>
  965. <td>${booking.start_date} to ${booking.end_date}</td>
  966. <td>${booking.no_of_days}</td>
  967. <td>${booking.booking_status}</td>
  968. <td>Rs.${booking.amount_received.toFixed(2)}</td>
  969. <td>Rs.${booking.amount_refunded}</td>
  970. <td>Rs.${booking.balance_amount}</td>
  971. </tr>`;
  972. });
  973. hallDetailsContent += `
  974. </tbody>
  975. </table>
  976. </div>
  977. <div class="pagination">
  978. <button class="btn btn-primary ${page === 1 ? 'disabled' : ''}" onclick="changePage(${page - 1})">Previous</button>
  979. <span class="page-info">Page ${page} of ${Math.ceil(response.length / rowsPerPage)}</span>
  980. <button class="btn btn-primary ${page === Math.ceil(response.length / rowsPerPage) ? 'disabled' : ''}" onclick="changePage(${page + 1})">Next</button>
  981. </div>
  982. </div>
  983. <div class="modal-footer">
  984. <button type="button" class="btn btn-warning custom-close-button" data-dismiss="modal">Close</button>
  985. <div class="btn-group" role="group" aria-label="Export Buttons">
  986. <button type="button" class="btn btn-primary btn-export" id="export-excel">Excel</button>
  987. <button type="button" class="btn btn-primary btn-export" id="export-csv">CSV</button>
  988. <button type="button" class="btn btn-primary btn-export" id="export-pdf">PDF</button>
  989. </div>
  990. </div>`;
  991. document.getElementById('hall-details-content').innerHTML = hallDetailsContent;
  992. $('#HallDetailsModal').modal('show');
  993. }
  994. function changePage(page) {
  995. currentPage = page;
  996. renderTable(currentPage);
  997. }
  998. // Expose changePage function to global scope
  999. window.changePage = changePage;
  1000. renderTable(currentPage);
  1001. // Remove existing event listeners to prevent multiple triggers
  1002. $(document).off('click', '#export-excel');
  1003. $(document).off('click', '#export-csv');
  1004. $(document).off('click', '#export-pdf');
  1005. // Use jQuery to attach event handlers to dynamically added elements
  1006. $(document).on('click', '#export-excel', function() { exportToExcel('halldetails'); });
  1007. $(document).on('click', '#export-csv', function() { exportToCSV('halldetails'); });
  1008. $(document).on('click', '#export-pdf', function() { exportToPDF('halldetails'); });
  1009. }
  1010. $(document).ready(function() {
  1011. // Attach click event handler to the total bookings links
  1012. $(document).on('click', '.total-booking', function(event) {
  1013. event.preventDefault();
  1014. $('#DetailsModal').modal('hide');
  1015. let hallId = $(this).data('hallid');
  1016. fetchHallDetails(hallId);
  1017. });
  1018. // Close button event handler
  1019. $(document).on('click', '.custom-close-button', function() {
  1020. $('#DetailsModal').modal('hide');
  1021. $('#HallDetailsModal').modal('hide');
  1022. });
  1023. });
  1024. function exportToExcel(tableId) {
  1025. const wb = XLSX.utils.table_to_book(document.getElementById(tableId), { sheet: "Halldetails" });
  1026. XLSX.writeFile(wb, 'Zone_Details.xlsx');
  1027. }
  1028. function exportToCSV(tableId) {
  1029. const wb = XLSX.utils.table_to_book(document.getElementById(tableId), { sheet: "Halldetails" });
  1030. XLSX.writeFile(wb, 'Zone_Details.csv', { bookType: 'csv' });
  1031. }
  1032. function exportToPDF(tableId) {
  1033. const { jsPDF } = window.jspdf;
  1034. const doc = new jsPDF();
  1035. doc.autoTable({ html: '#' + tableId });
  1036. doc.save('Halldetails.pdf');
  1037. }
  1038. document.addEventListener('DOMContentLoaded', function() {
  1039. fetchData();
  1040. });
  1041. function fetchData() {
  1042. const zone = document.getElementById('zoneValue').value;
  1043. fetch('/communityhall/user/api/getZonehalls') // Replace with your actual API endpoint
  1044. .then(response => response.json())
  1045. .then(data => {
  1046. populateDropdowns(data, zone);
  1047. })
  1048. .catch(error => console.error('Error fetching data:', error));
  1049. }
  1050. function populateDropdowns(data, zone) {
  1051. const divisionDropdown = document.getElementById('division1');
  1052. const hallDropdown = document.getElementById('hall1');
  1053. const divisionsByZone = {};
  1054. const hallsByDivision = {};
  1055. data.forEach(item => {
  1056. if (item.zone === zone) {
  1057. if (!divisionsByZone[item.zone]) {
  1058. divisionsByZone[item.zone] = [];
  1059. }
  1060. if (!divisionsByZone[item.zone].includes(item.division)) {
  1061. divisionsByZone[item.zone].push(item.division);
  1062. }
  1063. if (!hallsByDivision[item.division]) {
  1064. hallsByDivision[item.division] = [];
  1065. }
  1066. hallsByDivision[item.division].push({ hallName: item.hall_name, hallId: item.hall_id });
  1067. }
  1068. });
  1069. // Populate divisions for the selected zone
  1070. populateDivisions(zone, divisionsByZone);
  1071. // Store halls by division for later use
  1072. divisionDropdown.dataset.hallsByDivision = JSON.stringify(hallsByDivision);
  1073. }
  1074. function populateDivisions(zone, divisionsByZone) {
  1075. const divisionDropdown = document.getElementById('division1');
  1076. divisionDropdown.innerHTML = ''; // Clear existing options
  1077. // Add 'All' option
  1078. const allOption = document.createElement('option');
  1079. allOption.value = 'ALL';
  1080. allOption.textContent = 'ALL';
  1081. divisionDropdown.appendChild(allOption);
  1082. divisionsByZone[zone].forEach(division => {
  1083. const option = document.createElement('option');
  1084. option.value = division;
  1085. option.textContent = division;
  1086. divisionDropdown.appendChild(option);
  1087. });
  1088. }
  1089. function filterHalls() {
  1090. const divisionDropdown = document.getElementById('division1');
  1091. const selectedDivision = divisionDropdown.value;
  1092. const hallDropdown = document.getElementById('hall1');
  1093. const hallsByDivision = JSON.parse(divisionDropdown.dataset.hallsByDivision);
  1094. hallDropdown.innerHTML = ''; // Clear existing options
  1095. // Add 'All' option with value 1000
  1096. const allOption = document.createElement('option');
  1097. allOption.value = '1000';
  1098. allOption.textContent = 'ALL';
  1099. hallDropdown.appendChild(allOption);
  1100. if (selectedDivision === 'ALL') {
  1101. document.getElementById('hallContainer').classList.add('hidden');
  1102. } else {
  1103. document.getElementById('hallContainer').classList.remove('hidden');
  1104. hallsByDivision[selectedDivision].forEach(hall => {
  1105. const option = document.createElement('option');
  1106. option.value = hall.hallId; // Pass hall ID as value
  1107. option.textContent = hall.hallName;
  1108. hallDropdown.appendChild(option);
  1109. });
  1110. }
  1111. }
  1112. // Function to reset date fields
  1113. function resetData() {
  1114. window.location.href = "/communityhall/officer/officer-dashboard";
  1115. }
  1116. document.addEventListener('DOMContentLoaded', function() {
  1117. const fromDate = document.getElementById('fromDate');
  1118. const toDate = document.getElementById('toDate');
  1119. // Initially disable the "To Date" field
  1120. toDate.disabled = true;
  1121. fromDate.addEventListener('change', function() {
  1122. if (fromDate.value) {
  1123. // Enable the "To Date" field when "From Date" is selected
  1124. toDate.disabled = false;
  1125. // Get the selected "From Date"
  1126. const selectedFromDate = new Date(fromDate.value);
  1127. // Set the "To Date" minimum to the same day as the "From Date"
  1128. const sameDayString = selectedFromDate.toISOString().split('T')[0];
  1129. toDate.setAttribute('min', sameDayString);
  1130. // Set the "To Date" value to the next day by default
  1131. toDate.value = sameDayString;
  1132. } else {
  1133. // Disable the "To Date" field if "From Date" is cleared
  1134. toDate.disabled = true;
  1135. toDate.value = ''; // Clear the "To Date" input
  1136. }
  1137. });
  1138. });
  1139. </script>
  1140. </body>
  1141. </html>