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.

1517 lines
55 KiB

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