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.

1074 lines
29 KiB

6 days ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
  1. <!DOCTYPE html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Victoria public hall</title>
  7. <!-- Links to Bootstrap CSS and JS, jQuery, and SweetAlert -->
  8. <!-- Bootstrap CSS -->
  9. <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
  10. <style>
  11. label {
  12. color: black;
  13. }
  14. /* Header Styling */
  15. .header {
  16. background-color: #1d495a;
  17. padding: 10px 20px;
  18. display: flex;
  19. align-items: center;
  20. justify-content: space-between;
  21. color: white;
  22. font-family: Arial, sans-serif;
  23. }
  24. .header .logo {
  25. display: flex;
  26. align-items: center;
  27. }
  28. .header .logo img {
  29. height: 60px;
  30. }
  31. .header .center-text {
  32. position: absolute;
  33. /* Centered text */
  34. left: 50%;
  35. transform: translateX(-50%);
  36. text-align: center;
  37. font-size: 24px;
  38. }
  39. .header .menu-btn {
  40. background-color: transparent;
  41. border: none;
  42. font-size: 24px;
  43. color: white;
  44. }
  45. .header .menu-btn:hover {
  46. /* text-decoration: underline; */
  47. color: #ccc;
  48. }
  49. /* Menu Dropdown */
  50. .menu-dropdown {
  51. position: relative;
  52. margin-top: 10px;
  53. background-color: #1d495a;
  54. padding: 10px 20px;
  55. display: none;
  56. flex-direction: column;
  57. width: 100%;
  58. }
  59. .menu-dropdown a {
  60. color: white;
  61. margin-bottom: 5px;
  62. text-decoration: none;
  63. }
  64. .menu-dropdown a:hover {
  65. text-decoration: underline;
  66. }
  67. .menu-dropdown {
  68. right: 0;
  69. left: 0;
  70. z-index: 1000;
  71. /* Add z-index to bring the menu above other elements */
  72. }
  73. /* Mobile Specific Styling */
  74. @media (max-width : 768px) {
  75. .header {
  76. display: flex;
  77. justify-content: space-between;
  78. align-items: center;
  79. }
  80. .center-text {
  81. font-size: 18px !important;
  82. flex-grow: 1;
  83. text-align: center;
  84. }
  85. .menu-dropdown {
  86. right: 0;
  87. left: 0;
  88. z-index: 1000;
  89. /* Add z-index to bring the menu above other elements */
  90. }
  91. }
  92. /* Ensure content is not hidden behind the fixed navbar */
  93. body {
  94. margin: 0;
  95. /* margin-top: 90px; Adjust based on your header height */
  96. }
  97. .disclaimer-list li {
  98. font-size: 0.95rem;
  99. /* or 1rem */
  100. line-height: 1.6;
  101. }
  102. .flatpickr-calendar {
  103. z-index: 99999 !important;
  104. }
  105. /* Allow calendar to overflow cards */
  106. .card,
  107. .card-body,
  108. .container {
  109. overflow: visible !important;
  110. }
  111. .pickdate[readonly] {
  112. background-color: #fff !important;
  113. cursor: pointer;
  114. }
  115. .readonly-input {
  116. background-color: #e9ecef; /* Bootstrap disabled look */
  117. cursor: not-allowed;
  118. }
  119. </style>
  120. </head>
  121. <body style="background-color: #ebf1fa;">
  122. <!-- Header Start-->
  123. <header>
  124. <div class="header d-flex justify-content-between align-items-center">
  125. <!-- Left: Logo -->
  126. <div class="logo">
  127. <img src="https://gccservices.in/gcc/assets/images/logo.png" alt="Logo">
  128. </div>
  129. <!-- Center: Text -->
  130. <div class="center-text">VICTORIA PUBLIC HALL</div>
  131. </div>
  132. </header>
  133. <!-- Header End-->
  134. <main class="container mt-4">
  135. <div class="container mt-5">
  136. <div class="card">
  137. <div class="card-header bg-dark text-white">
  138. <h5>Request Information:-</h5>
  139. </div>
  140. <div class="card-body">
  141. <div class="container mt-4">
  142. <!-- Row 1: Name and Phone -->
  143. <div class="row mb-3">
  144. <div class="col-md-5">
  145. <label class="form-label" for="name">Name <span class="text-danger">*</span></label> <input type="text"
  146. class="form-control" placeholder="Enter Name here" id="name"
  147. oninput="this.value = this.value.replace(/[^a-zA-Z\s]/g, '')">
  148. </div>
  149. <div class="col-md-5">
  150. <label class="form-label" for="userinput"> Mobile Number/Email
  151. </label> <input type="text" id="userinput" class="form-control readonly-input"
  152. placeholder="Enter Phone number">
  153. </div>
  154. </div>
  155. <div class="row mb-3">
  156. <div class="col-md-5">
  157. <label class="form-label" for="category">
  158. Category <span class="text-danger">*</span>
  159. </label>
  160. <select class="form-control" id="category" name="categoryId" required>
  161. <option value="">-- Select Category --</option>
  162. </select>
  163. </div>
  164. <div class="col-md-5">
  165. <label class="form-label" for="preferdate">
  166. Preferred Date <span class="text-danger">*</span>
  167. </label>
  168. <div class="input-group">
  169. <input type="text"
  170. class="form-control pickdate"
  171. id="preferdate"
  172. placeholder="dd-mm-yyyy"
  173. >
  174. <div class="input-group-append">
  175. <span class="input-group-text" style="cursor:pointer">
  176. 📅
  177. </span>
  178. </div>
  179. </div>
  180. </div>
  181. </div>
  182. </div>
  183. </div>
  184. </div>
  185. <!-- School / College Card -->
  186. <div class="card mt-3 d-none" id="schoolCollegeCard">
  187. <div class="card-header bg-dark text-white">
  188. <h6 class="mb-0">School / College Details</h6>
  189. </div>
  190. <div class="card-body">
  191. <div class="row mb-3">
  192. <div class="col-md-5">
  193. <label for="privateInstitutionName">Institution Name <span class="text-danger">*</span></label>
  194. <input type="text" class="form-control" id="privateInstitutionName"
  195. placeholder="Enter School / College Name" oninput="allowOnlyAlphabets(this)">
  196. </div>
  197. <!-- ID Proof Dropdown -->
  198. <div class="col-md-5">
  199. <label class="form-label" for="idProof">
  200. ID Proof of accompanying staff <span class="text-danger">*</span>
  201. </label>
  202. <select class="form-control idProofSelect mb-2">
  203. <option value="">-- Select ID Proof --</option>
  204. </select>
  205. </div>
  206. <!-- ID Number Input -->
  207. <div class="col-md-5">
  208. <label class="form-label" for="idProofNumber">
  209. ID Proof Number <span class="text-danger">*</span>
  210. </label>
  211. <input class="form-control idProofNumber" placeholder="Select ID Proof first" disabled>
  212. </div>
  213. </div>
  214. </div>
  215. </div>
  216. <!-- Organization / Association Card -->
  217. <div class="card mt-3 d-none" id="organizationCard">
  218. <div class="card-header bg-dark text-white">
  219. <h6 class="mb-0">Organization / Association Details</h6>
  220. </div>
  221. <div class="card-body">
  222. <div class="row mb-3">
  223. <div class="col-md-5">
  224. <label>Organization Name <span class="text-danger">*</span></label>
  225. <input type="text" class="form-control" id="orgName" placeholder="Enter Organization Name" oninput="allowOnlyAlphabets(this)">
  226. </div>
  227. <!-- ID Proof Dropdown -->
  228. <div class="col-md-5">
  229. <label class="form-label" for="idProof">ID Proof of accompanying staff <span class="text-danger">*</span>
  230. </label>
  231. <select class="form-control idProofSelect mb-2">
  232. <option value="">-- Select ID Proof --</option>
  233. </select>
  234. </div>
  235. <!-- ID Number Input -->
  236. <div class="col-md-5">
  237. <label class="form-label" for="idProofNumber">
  238. ID Proof Number <span class="text-danger">*</span>
  239. </label>
  240. <input class="form-control idProofNumber" placeholder="Select ID Proof first" disabled>
  241. </div>
  242. </div>
  243. </div>
  244. </div>
  245. <div class="card mt-3 d-none" id="visitorDetailsCard">
  246. <div class="card-header bg-dark text-white">
  247. <h6 class="mb-0">Visitor Details</h6>
  248. </div>
  249. <div class="card-body">
  250. <!-- Dynamic User Type Rows -->
  251. <div id="userTypeContainer"></div>
  252. <hr>
  253. <!-- Summary -->
  254. <div class="d-flex justify-content-between">
  255. <strong>Total People:</strong>
  256. <span id="totalPeople">0</span>
  257. </div>
  258. <div class="d-flex justify-content-between mt-2">
  259. <strong>Total Amount:</strong>
  260. <span id="totalAmount">₹0</span>
  261. </div>
  262. </div>
  263. </div>
  264. <div class="card mt-3" id="termsCheckCard">
  265. <div class="card-header bg-dark text-white">
  266. <h6 class="mb-0">Disclaimer</h6>
  267. </div>
  268. <div class="card-body">
  269. <!-- Disclaimer Content -->
  270. <ul class="small text-muted mb-3 disclaimer-list ">
  271. <li>
  272. Submission of this application shall be treated as a <strong>request only</strong>
  273. and shall not be considered as confirmation of booking.
  274. </li>
  275. <li>
  276. The preferred visit date indicated is <strong>subject to availability</strong> and
  277. verification by the Competent Authority.
  278. </li>
  279. <li>
  280. In the event of non-availability of the preferred date, the Competent Authority
  281. reserves the right to allot an <strong>alternate visit date</strong>.
  282. </li>
  283. <li>
  284. The final visit date shall be communicated to the applicant upon approval.
  285. </li>
  286. <li>
  287. The booking shall be deemed confirmed only upon
  288. <strong>administrative approval and successful payment confirmation</strong>,
  289. wherever applicable.
  290. </li>
  291. <li>
  292. Payment shall be made within <strong>24 hours</strong> from the date and time of
  293. approval, failing which the request shall be liable for
  294. <strong>automatic cancellation</strong> without further notice.
  295. </li>
  296. </ul>
  297. <hr>
  298. <!-- Terms and Conditions Checkbox -->
  299. <div class="form-check mt-4 text-center">
  300. <input class="form-check-input" type="checkbox" id="termsCheck">
  301. <label class="form-check-label" for="termsCheck">
  302. I have read the above Disclaimer.
  303. <!-- <a href="#" data-bs-toggle="modal" data-bs-target="#termsModal">
  304. terms and conditions
  305. </a>. -->
  306. </label>
  307. </div>
  308. </div>
  309. </div>
  310. <div class="text-center mt-4">
  311. <button type="button" class="btn btn-success" id="submitBtn" onclick="saveBulkBooking()">Submit</button>
  312. <button type="button" class="btn btn-secondary" onclick="goBack()">Back</button>
  313. </div>
  314. <br>
  315. </div>
  316. </main>
  317. <div id="pageLoader"
  318. style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;">
  319. <div style="position: relative; top: 50%; transform: translateY(-50%);">
  320. <div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;">
  321. <span class="sr-only">Loading...</span>
  322. </div>
  323. <!-- Add the 'Please wait' text below the spinner -->
  324. <p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please
  325. wait...</p>
  326. </div>
  327. </div>
  328. <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  329. <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
  330. <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  331. <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js"></script>
  332. <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
  333. <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
  334. <!-- Flatpickr CSS -->
  335. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
  336. <!-- Flatpickr JS -->
  337. <script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
  338. <script>
  339. $(document).ready(function () {
  340. $.ajax({
  341. url: "/victoriapublichall/bookingapi/category",
  342. type: "GET",
  343. success: function (data) {
  344. const categorySelect = $("#category");
  345. categorySelect.empty();
  346. categorySelect.append('<option value="">-- Select Category --</option>');
  347. data.forEach(row => {
  348. categorySelect.append(
  349. `<option value="${row.id}">${row.category}</option>`
  350. );
  351. });
  352. },
  353. error: function () {
  354. alert("Unable to load categories");
  355. }
  356. });
  357. });
  358. $("#category").on("change", function () {
  359. const selectedVal = $(this).val();
  360. const selectedText = $("#category option:selected").text().toLowerCase();
  361. const isGovtSchool = selectedVal === "1";
  362. // Reset counts & set amounts correctly
  363. userTypes.forEach(u => {
  364. u.count = 0;
  365. u.amount = isGovtSchool ? 0 : u.originalAmount;
  366. });
  367. renderUserTypes();
  368. // Hide / show total amount section
  369. if (isGovtSchool) {
  370. $("#totalAmount").closest(".d-flex").hide();
  371. } else {
  372. $("#totalAmount").closest(".d-flex").show();
  373. }
  374. // Hide all cards first
  375. // $("#govtschoolCard").addClass("d-none");
  376. $("#schoolCollegeCard").addClass("d-none");
  377. $("#organizationCard").addClass("d-none");
  378. // Hide visitor details initially
  379. $("#visitorDetailsCard").addClass("d-none");
  380. // If category is selected
  381. if (selectedVal) {
  382. // Show visitor details (common for all)
  383. $("#visitorDetailsCard").removeClass("d-none");
  384. // School / College
  385. if (
  386. selectedText.includes("school") ||
  387. selectedText.includes("college")
  388. ) {
  389. $("#schoolCollegeCard").removeClass("d-none");
  390. }
  391. // Organization / Association / Tourism
  392. else if (
  393. selectedText.includes("organization") ||
  394. selectedText.includes("association") ||
  395. selectedText.includes("tourism")
  396. ) {
  397. $("#organizationCard").removeClass("d-none");
  398. }
  399. }
  400. });
  401. document.addEventListener("DOMContentLoaded", function () {
  402. const phoneInput = document.getElementById("userinput");
  403. const storedMobile = sessionStorage.getItem("bulkMobile");
  404. if (phoneInput && storedMobile) {
  405. phoneInput.value = storedMobile;
  406. phoneInput.readOnly = true; // enforce readonly
  407. phoneInput.classList.add("readonly"); // optional styling
  408. }
  409. });
  410. document.addEventListener("DOMContentLoaded", function () {
  411. const fp = flatpickr("#preferdate", {
  412. dateFormat: "Y-m-d", // backend format
  413. altInput: true,
  414. altFormat: "d-m-Y",
  415. minDate: new Date().fp_incr(10),
  416. disable: [
  417. function (date) {
  418. return date.getDay() === 2; // Tuesday
  419. }
  420. ],
  421. disableMobile: true
  422. });
  423. // Open calendar when icon is clicked
  424. document.querySelector(".input-group-text").addEventListener("click", function () {
  425. fp.open();
  426. });
  427. });
  428. /*document.addEventListener("DOMContentLoaded", function () {
  429. const dateInput = document.getElementById("preferdate");
  430. const today = new Date();
  431. today.setDate(today.getDate() + 10);
  432. const yyyy = today.getFullYear();
  433. const mm = String(today.getMonth() + 1).padStart(2, '0');
  434. const dd = String(today.getDate()).padStart(2, '0');
  435. dateInput.min = `${yyyy}-${mm}-${dd}`;
  436. dateInput.addEventListener("keydown", function (e) {
  437. e.preventDefault();
  438. });
  439. });*/
  440. // visitor category and calculate amount
  441. let userTypes = [];
  442. $(document).ready(function () {
  443. $.ajax({
  444. url: "/victoriapublichall/bookingapi/getamountbyusertype",
  445. type: "GET",
  446. success: function (data) {
  447. userTypes = data.map(row => ({
  448. id: row.id,
  449. type: row.user_type,
  450. amount: row.amount,
  451. originalAmount: row.amount,
  452. count: 0
  453. }));
  454. renderUserTypes();
  455. },
  456. error: function () {
  457. alert("Unable to load user types");
  458. }
  459. });
  460. });
  461. function renderUserTypes() {
  462. const container = $("#userTypeContainer");
  463. container.empty();
  464. const isGovtSchool = $("#category").val() === "1";
  465. userTypes.forEach((u, index) => {
  466. container.append(`
  467. <div class="row align-items-center mb-2">
  468. <div class="col-md-${isGovtSchool ? 6 : 4}">
  469. <strong>${u.type}</strong>
  470. ${isGovtSchool ? "" : `<span class="text-muted ms-1">(₹${u.amount})</span>`}
  471. </div>
  472. <!-- Count input -->
  473. <div class="col-md-${isGovtSchool ? 6 : 4}">
  474. <input type="text"
  475. class="form-control"
  476. maxlength="3"
  477. inputmode="numeric"
  478. value="${u.count}"
  479. oninput="
  480. this.value=this.value.replace(/[^0-9]/g,'').slice(0,3);
  481. updateCount(${index}, this.value)
  482. ">
  483. </div>
  484. <!-- Amount column (hidden for Govt School) -->
  485. ${isGovtSchool ? "" : `
  486. <div class="col-md-4 text-end">
  487. ₹<span id="amount-${index}">${u.count * u.amount}</span>
  488. </div>
  489. `}
  490. </div>
  491. `);
  492. });
  493. updateTotals();
  494. }
  495. function updateCount(index, value) {
  496. let newCount = parseInt(value, 10);
  497. if (isNaN(newCount) || newCount < 0) newCount = 0;
  498. // Calculate total EXCLUDING current index
  499. let totalWithoutCurrent = 0;
  500. userTypes.forEach((u, i) => {
  501. if (i !== index) {
  502. totalWithoutCurrent += u.count;
  503. }
  504. });
  505. // HARD LIMIT CHECK
  506. if (totalWithoutCurrent + newCount > 480) {
  507. Swal.fire(
  508. "Limit Exceeded",
  509. "Total visitor count cannot exceed 480.",
  510. "warning"
  511. );
  512. // Reset only this input
  513. renderUserTypes();
  514. return;
  515. }
  516. // Safe to update
  517. userTypes[index].count = newCount;
  518. // Update row amount safely
  519. const amountEl = document.getElementById(`amount-${index}`);
  520. if (amountEl) {
  521. amountEl.textContent = newCount * userTypes[index].amount;
  522. }
  523. updateTotals();
  524. }
  525. /* Update Totals */
  526. function updateTotals() {
  527. let totalPeople = 0;
  528. let totalAmount = 0;
  529. userTypes.forEach(u => {
  530. totalPeople += u.count;
  531. totalAmount += u.count * u.amount;
  532. });
  533. $("#totalPeople").text(totalPeople);
  534. $("#totalAmount").text("₹" + totalAmount);
  535. }
  536. $(document).ready(function () {
  537. $.ajax({
  538. url: "/victoriapublichall/bookingapi/getidproofs",
  539. type: "GET",
  540. success: function (data) {
  541. $(".idProofSelect").each(function () {
  542. const select = $(this);
  543. select.empty();
  544. select.append('<option value="">-- Select ID Proof --</option>');
  545. data.forEach(row => {
  546. select.append(
  547. `<option value="${row.id}">${row.id_name}</option>`
  548. );
  549. });
  550. });
  551. }
  552. });
  553. });
  554. $(document).on("change", ".idProofSelect", function () {
  555. const selectedText = $(this).find("option:selected").text().toLowerCase();
  556. const input = $(this).closest(".row").find(".idProofNumber");
  557. input.val("");
  558. input.prop("disabled", true);
  559. input.removeAttr("maxlength");
  560. input.off("input");
  561. if (!selectedText || selectedText.includes("select")) {
  562. input.attr("placeholder", "Select ID Proof first");
  563. return;
  564. }
  565. input.prop("disabled", false);
  566. if (selectedText.includes("aadhar")) {
  567. input.attr("placeholder", "Enter 12-digit Aadhaar Number");
  568. input.attr("maxlength", "12");
  569. input.on("input", function () {
  570. this.value = this.value.replace(/[^0-9]/g, "");
  571. });
  572. }
  573. else if (selectedText.includes("passport")) {
  574. input.attr("placeholder", "Enter Passport Number");
  575. input.attr("maxlength", "9");
  576. input.on("input", function () {
  577. this.value = this.value.replace(/[^a-zA-Z0-9]/g, "").toUpperCase();
  578. });
  579. }
  580. else {
  581. input.attr("placeholder", "Enter ID Proof Number");
  582. }
  583. });
  584. function validateBulkBookingForm() {
  585. // Name
  586. if (!$("#name").val().trim()) {
  587. Swal.fire("Validation Error", "Please enter Name", "warning");
  588. return false;
  589. }
  590. // Mobile / Email
  591. if (!$("#userinput").val().trim()) {
  592. Swal.fire("Validation Error", "Please enter Mobile Number or Email", "warning");
  593. return false;
  594. }
  595. // Category
  596. if (!$("#category").val()) {
  597. Swal.fire("Validation Error", "Please select Category", "warning");
  598. return false;
  599. }
  600. // Preferred Date
  601. if (!$("#preferdate").val()) {
  602. Swal.fire("Validation Error", "Please select Preferred Date", "warning");
  603. return false;
  604. }
  605. // Visitor Count
  606. let totalPeople = parseInt($("#totalPeople").text(), 10);
  607. if (!totalPeople || totalPeople <= 0) {
  608. Swal.fire("Validation Error", "Please enter visitor count", "warning");
  609. return false;
  610. }
  611. if ($("#schoolCollegeCard").is(":visible")) {
  612. if (!$("#privateInstitutionName").val().trim()) {
  613. Swal.fire("Validation Error", "Please enter School / College Name", "warning");
  614. return false;
  615. }
  616. const idTypeText = $("#schoolCollegeCard .idProofSelect option:selected")
  617. .text().toLowerCase();
  618. const idNumber = $("#schoolCollegeCard .idProofNumber").val().trim();
  619. if (!idTypeText || idTypeText.includes("select")) {
  620. Swal.fire("Validation Error", "Please select ID Proof", "warning");
  621. return false;
  622. }
  623. if (!idNumber) {
  624. Swal.fire("Validation Error", "Please enter ID Proof Number", "warning");
  625. return false;
  626. }
  627. // Aadhaar validation
  628. if (idTypeText.includes("aadhar") || idTypeText.includes("aadhaar")) {
  629. if (!/^[0-9]{12}$/.test(idNumber)) {
  630. Swal.fire(
  631. "Validation Error",
  632. "Aadhaar number must be exactly 12 digits",
  633. "warning"
  634. );
  635. return false;
  636. }
  637. }
  638. // Passport validation (Indian)
  639. if (idTypeText.includes("passport")) {
  640. if (!/^[A-Z][0-9]{7}$/.test(idNumber)) {
  641. Swal.fire(
  642. "Validation Error",
  643. "Passport number must be 1 uppercase letter followed by 7 digits ",
  644. "warning"
  645. );
  646. return false;
  647. }
  648. }
  649. }
  650. if ($("#organizationCard").is(":visible")) {
  651. if (!$("#orgName").val().trim()) {
  652. Swal.fire("Validation Error", "Please enter Organization Name", "warning");
  653. return false;
  654. }
  655. const idTypeText = $("#organizationCard .idProofSelect option:selected")
  656. .text().toLowerCase();
  657. const idNumber = $("#organizationCard .idProofNumber").val().trim();
  658. if (!idTypeText || idTypeText.includes("select")) {
  659. Swal.fire("Validation Error", "Please select ID Proof", "warning");
  660. return false;
  661. }
  662. if (!idNumber) {
  663. Swal.fire("Validation Error", "Please enter ID Proof Number", "warning");
  664. return false;
  665. }
  666. // Aadhaar
  667. if (idTypeText.includes("aadhar") || idTypeText.includes("aadhaar")) {
  668. if (!/^[0-9]{12}$/.test(idNumber)) {
  669. Swal.fire(
  670. "Validation Error",
  671. "Aadhaar number must be exactly 12 digits",
  672. "warning"
  673. );
  674. return false;
  675. }
  676. }
  677. // Passport
  678. if (idTypeText.includes("passport")) {
  679. if (!/^[A-Z][0-9]{7}$/.test(idNumber)) {
  680. Swal.fire(
  681. "Validation Error",
  682. "Passport number must be 1 uppercase letter followed by 7 digits",
  683. "warning"
  684. );
  685. return false;
  686. }
  687. }
  688. }
  689. return true;
  690. }
  691. function saveBulkBooking() {
  692. let totalPeople = userTypes.reduce((sum, u) => sum + u.count, 0);
  693. if (totalPeople <= 10) {
  694. Swal.fire(
  695. "Minimum Limit Required",
  696. "Total number of visitors must be more than 10.",
  697. "warning"
  698. );
  699. return;
  700. }
  701. if (totalPeople > 480) {
  702. Swal.fire("Limit Exceeded", "Total visitor count cannot exceed 480.", "warning");
  703. return;
  704. }
  705. // Terms check
  706. if (!$("#termsCheck").is(":checked")) {
  707. Swal.fire("Terms Required", "Please agree to the terms and conditions.", "warning");
  708. return;
  709. }
  710. // Local validation
  711. if (!validateBulkBookingForm()) return;
  712. const userInput = $("#userinput").val().trim();
  713. // CHECK DUPLICATE MOBILE / EMAIL
  714. $.ajax({
  715. url: "/victoriapublichall/bookingapi/checkBulkBookingExists",
  716. type: "POST",
  717. data: { userInput: userInput },
  718. success: function (res) {
  719. if (res.exists) {
  720. Swal.fire(
  721. "Booking Not Allowed",
  722. "This Mobile Number / Email is already used for a bulk booking.",
  723. "warning"
  724. );
  725. return;
  726. }
  727. // ONLY IF NOT EXISTS → PROCEED TO SAVE
  728. submitBulkBooking();
  729. }
  730. });
  731. }
  732. function submitBulkBooking() {
  733. let idType = null;
  734. let idProofNumber = null;
  735. if ($("#schoolCollegeCard").is(":visible")) {
  736. idType = $("#schoolCollegeCard .idProofSelect").val();
  737. idProofNumber = $("#schoolCollegeCard .idProofNumber").val();
  738. }
  739. if ($("#organizationCard").is(":visible")) {
  740. idType = $("#organizationCard .idProofSelect").val();
  741. idProofNumber = $("#organizationCard .idProofNumber").val();
  742. }
  743. let institutionName = null;
  744. let organizationName = null;
  745. if ($("#schoolCollegeCard").is(":visible")) {
  746. institutionName = $("#privateInstitutionName").val();
  747. }
  748. if ($("#organizationCard").is(":visible")) {
  749. organizationName = $("#orgName").val();
  750. }
  751. const peopleDetails = [];
  752. userTypes.forEach(u => {
  753. if (u.count > 0) {
  754. peopleDetails.push({ id: u.id, count: u.count });
  755. }
  756. });
  757. const data = {
  758. name: $("#name").val(),
  759. userInput: $("#userinput").val(),
  760. visitDate: $("#preferdate").val(),
  761. categoryId: $("#category").val(),
  762. institutionName,
  763. organizationName,
  764. idType,
  765. idProofNumber,
  766. no_of_people: $("#totalPeople").text(),
  767. totalAmount: $("#totalAmount").text().replace("₹", ""),
  768. peopleDetails: JSON.stringify(peopleDetails),
  769. source: 1
  770. };
  771. $.ajax({
  772. url: "/victoriapublichall/bookingapi/saveBulkRegistration",
  773. type: "POST",
  774. data: data,
  775. success: function (res) {
  776. Swal.fire({
  777. title: "Request Submitted",
  778. text: "Your request has been raised successfully.\nRef ID: " + res.refId,
  779. icon: "success",
  780. allowOutsideClick: false,
  781. allowEscapeKey: false,
  782. confirmButtonText: "OK"
  783. }).then(() => {
  784. sessionStorage.setItem("bulkMobile", $("#userinput").val());
  785. window.location.href =
  786. "/victoriapublichall/acknowledgement?refId=" + res.refId;
  787. });
  788. }
  789. });
  790. }
  791. function goBack() {
  792. window.location.href = "/victoriapublichall";
  793. }
  794. $(document).ready(function () {
  795. // Always keep submit disabled on load
  796. $("#submitBtn").prop("disabled", true);
  797. // Enable submit only if checkbox is checked
  798. $("#termsCheck").on("change", function () {
  799. $("#submitBtn").prop("disabled", !this.checked);
  800. });
  801. });
  802. function allowOnlyAlphabets(input) {
  803. input.value = input.value.replace(/[^a-zA-Z\s]/g, '');
  804. }
  805. </script>
  806. </body>
  807. </html>