|
|
<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{fragments/head-cro :: head}"></head><style> .card-body table { width: 100%; padding: 100px; }
.card-body th, td { padding: 8px; text-align: left; }
.amount-cell { text-align: right; padding-right: 1rem; }
.form-control[readonly] { background-color: white; }
.modal { overflow-y: auto; }
/* OTP inputs */ .otp-input-box { display: flex; justify-content: center; gap: 10px; }
.cro-otp-input { width: 48px; height: 52px; text-align: center; font-size: 22px; font-weight: bold; border: 2px solid #ced4da; border-radius: 8px; transition: all 0.2s ease-in-out; }
.cro-otp-input:focus { border-color: #0d6efd; outline: none; box-shadow: 0 0 0 4px rgba(13, 110, 253, .2); }
#bookingSearchSection { border: 1px solid #dee2e6; border-radius: 8px; padding: 20px; background: #f8f9fa; margin-bottom: 20px; }
.detail-section th { background-color: #f2f2f2; font-weight: 600; }
.detail-section td, .detail-section th { padding: 0.45rem 0.75rem; border: 1px solid #dee2e6; }
.detail-section table { width: 100%; border-collapse: collapse; margin-bottom: 10px; }
#bookingDetailResult { display: none; }
.status-change-card { border: 2px solid #e2e8f0; border-radius: 10px; background: #ffffff; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); padding: 24px; margin-top: 25px; }
.status-badge-lg { font-size: 0.95rem; padding: 0.35rem 0.75rem; border-radius: 6px; font-weight: 600; }</style>
<body> <!-- Page Container --> <div id="page-container" class="sidebar-o sidebar-dark enable-page-overlay side-scroll page-header-fixed page-header-dark"> <!-- Sidebar Nav--> <aside th:replace="~{fragments/aside-right :: aside}"></aside> <!-- END Side Overlay (right)--> <!-- Sidebar Nav--> <nav th:replace="~{fragments/nav-cro :: nav}"></nav> <!-- END Sidebar --> <!-- Header --> <header th:replace="~{fragments/header-cro :: header}"></header> <!-- Main Container --> <main id="main-container"> <div class="content">
<!-- ═══ Search Booking by ID ═══ --> <div class="block block-rounded"> <div class="block-header block-header-default"> <h3 class="block-title"><i class="fa fa-search me-2 text-primary"></i>Change Booking Status</h3> </div> <div class="block-content p-4"> <div id="bookingSearchSection"> <div class="row align-items-end"> <div class="col-md-4 mb-2"> <label class="form-label fw-semibold" for="searchBookingId">Booking ID <span class="text-danger">*</span></label> <input type="number" class="form-control" id="searchBookingId" placeholder="Enter Booking ID" min="1" /> </div> <div class="col-md-3 mb-2"> <button type="button" class="btn btn-primary" id="btnSearchBooking" onclick="searchBookingById()"> <i class="fa fa-search me-1"></i> Search </button> <button type="button" class="btn btn-secondary ms-2" id="btnClearBookingSearch" onclick="clearBookingSearch()"> <i class="fa fa-times me-1"></i> Clear </button> </div> </div> </div>
<!-- Booking Detail Result --> <div id="bookingDetailResult"> <hr /> <div class="d-flex justify-content-between align-items-center mb-3"> <h5 class="mb-0">Booking Details <span class="text-primary" id="resultBookingId"></span> </h5> <span id="res_bookingStatusBadge" class="badge status-badge-lg bg-info"></span> </div> <div class="detail-section"> <!-- User Details --> <table> <tr> <th colspan="6">User Details</th> </tr> <tr> <th style="font-weight:normal;">User Name:</th> <td id="res_userName"></td> <th style="font-weight:normal;">Mobile Number:</th> <td id="res_mobileNumber"></td> <th style="font-weight:normal;">User Type:</th> <td id="res_usertype"></td> </tr> <tr> <th style="font-weight:normal;">User Address:</th> <td colspan="5" id="res_useraddress"></td> </tr> </table> <!-- Hall Details --> <table> <tr> <th colspan="6">Hall Details</th> </tr> <tr> <th style="font-weight:normal;">Hall Name:</th> <td colspan="5" id="res_hallName"></td> </tr> <tr> <th style="font-weight:normal;">Hall Address:</th> <td colspan="5" id="res_halladdress"></td> </tr> <tr> <th style="font-weight:normal;">Caretaker Name:</th> <td id="res_caretakername"></td> <th style="font-weight:normal;">Caretaker Mobile:</th> <td colspan="3" id="res_caretakermobileNumber"></td> </tr> </table> <!-- Booking Details --> <table> <tr> <th colspan="4">Booking Details (Booking Id: <span id="res_booking_id" style="color:blue;"></span>)</th> </tr> <tr> <th style="font-weight:normal;">Booking Date:</th> <td id="res_bookingDate"></td> <th style="font-weight:normal;">Booking Status:</th> <td id="res_bookingStatus" class="fw-bold"></td> </tr> <tr> <th style="font-weight:normal;">Start Date:</th> <td id="res_startDate"></td> <th style="font-weight:normal;">Deposit Amount:</th> <td class="amount-cell" id="res_depositeAmount"></td> </tr> <tr> <th style="font-weight:normal;">End Date:</th> <td id="res_endDate"></td> <th style="font-weight:normal;">Hall Amount:</th> <td class="amount-cell" id="res_hallAmount"></td> </tr> <tr> <th style="font-weight:normal;">Starting Slot:</th> <td id="res_startingSlot"></td> <th style="font-weight:normal;">GST @18%:</th> <td class="amount-cell" id="res_gst"></td> </tr> <tr> <th style="font-weight:normal;">Ending Slot:</th> <td id="res_endingSlot"></td> <th style="font-weight:normal;">Total Amount:</th> <td class="amount-cell" id="res_totalAmount"></td> </tr> <tr> <th style="font-weight:normal;">Reason:</th> <td colspan="3" id="res_reason"></td> </tr> </table> <!-- Payment Details --> <table> <tr> <th colspan="4">Booking Payment Details</th> </tr> <tr> <th style="font-weight:normal;">Transaction ID:</th> <td colspan="3" id="res_transactionId"></td> </tr> <tr> <th style="font-weight:normal;">Amount Received:</th> <td id="res_payamountReceived"></td> <th style="font-weight:normal;">Transaction Status:</th> <td id="res_paymentStatus"></td> </tr> </table> </div>
<!-- ═══ Change Booking Status Section (CRO) ═══ --> <div id="statusChangeSection" class="status-change-card" style="display: none;"> <div class="d-flex align-items-center mb-3"> <div class="bg-primary-light text-primary p-2 rounded-3 me-3" style="background: rgba(13,110,253,0.1);"> <i class="fa fa-exchange-alt fa-lg text-primary"></i> </div> <div> <h5 class="mb-0 fw-bold text-dark">Change Booking Status</h5> <small class="text-muted">CRO can update booking status to REJECTED or GCC_BLOCKED with OTP verification</small> </div> </div>
<div class="alert alert-warning py-2 mb-3"> <i class="fa fa-info-circle me-1"></i> Status changes require OTP verification sent to your registered CRO mobile number. </div>
<div class="row g-3"> <div class="col-md-5"> <label class="form-label fw-semibold" for="changeBookingStatusSelect"> Select New Booking Status <span class="text-danger">*</span> </label> <select class="form-select" id="changeBookingStatusSelect"> <option value="">-- Select New Status --</option> <option value="REJECTED">REJECTED</option> <option value="GCC_BLOCKED">GCC_BLOCKED</option> </select> </div> <div class="col-md-7"> <label class="form-label fw-semibold" for="statusChangeRemarks"> Reason / Remarks <span class="text-danger">*</span> </label> <textarea class="form-control" id="statusChangeRemarks" rows="2" placeholder="Enter reason or comments for changing status (required)..."></textarea> </div> <div class="col-12 text-end mt-3"> <button type="button" class="btn btn-danger px-4" id="btnInitiateStatusChange" onclick="initiateStatusChange()"> <i class="fa fa-paper-plane me-1"></i> Submit Status Change </button> </div> </div> </div>
<!-- ═══ Not Allowed Info Box ═══ --> <div id="statusChangeNotAllowedMsg" style="display: none; margin-top: 20px;"> <div class="alert alert-secondary mb-0"> <i class="fa fa-info-circle me-1"></i> Status change is <strong>not permitted</strong> for this booking. <span id="notAllowedDetailMsg">Status change is only permitted for <strong>Past events</strong> with status <strong>APPROVED</strong>, <strong>WAITING_FOR_NOC</strong>, or <strong>WAITING_FOR_NOC_APPROVAL</strong>.</span> <br /> <span class="small mt-1 d-inline-block"> Current status: <span class="badge bg-dark" id="notAllowedCurrentStatusBadge"></span> </span> </div> </div>
</div> </div> </div> </div> </main> <!-- END Main Container -->
<!-- ════ CRO OTP MODAL (MATCHES cro/booking-list.html) ════ --> <div class="modal fade" id="croStatusOtpModal" tabindex="-1" role="dialog" aria-labelledby="croStatusOtpModalLabel" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h6 class="modal-title m-0" id="croStatusOtpModalLabel">OTP Verification</h6> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <div class="row"> <div class="mb-3 text-center"> <img src="media/images/mobileotp.png" width="50%" alt="OTP"> </div> <div class="mb-0 text-center"> <h4>OTP Verification</h4> <p class="text-mute">Enter the OTP sent to <b class="text-info" id="croOtpMobileDisplay"></b></p> <p class="text-danger" id="croOtpErrorAlert"></p> </div> <div class="mb-3 text-center"> <div class="otp-input-box"> <input type="text" maxlength="1" class="otp-input cro-otp-input" id="croOtp1" required /> <input type="text" maxlength="1" class="otp-input cro-otp-input" id="croOtp2" required /> <input type="text" maxlength="1" class="otp-input cro-otp-input" id="croOtp3" required /> <input type="text" maxlength="1" class="otp-input cro-otp-input" id="croOtp4" required /> <input type="text" maxlength="1" class="otp-input cro-otp-input" id="croOtp5" required /> </div> </div> <div class="mb-3 text-center"> <p class="mb-0">Didn't receive OTP?</p> <p class="mb-0 text-info"> <span id="croResendText">Please wait..</span> <span id="croCountdown">60</span>s </p> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Close</button> <button type="button" class="btn btn-primary btn-sm" id="btnVerifyCroOtp" onclick="verifyAndSubmitStatusChange()">Verify OTP</button> </div> </div> </div> </div>
<footer th:replace="~{fragments/footer2 :: footer}"></footer>
<div th:replace="~{fragments/resetpassword :: div}"></div>
<script th:replace="~{fragments/loginscript :: script}"></script> <script> var currentSearchedBooking = null; var croResendTimer = null; var croMobileNumber = [[${ mobileno }]];
// ─── SEARCH BOOKING BY ID ─── function searchBookingById() { var input = document.getElementById('searchBookingId'); var bookingId = input ? input.value.trim() : ''; if (!bookingId || isNaN(bookingId) || parseInt(bookingId) <= 0) { Swal.fire({ icon: 'warning', title: 'Invalid Input', text: 'Please enter a valid Booking ID.' }); return; }
Swal.fire({ title: 'Fetching Booking...', text: 'Please wait while booking details are retrieved.', allowOutsideClick: false, didOpen: () => { Swal.showLoading(); } });
$.ajax({ type: 'GET', url: '/communityhall/cro/api/getBookingById', data: { bookingId: bookingId }, success: function (data) { Swal.close(); if (data && data.bookingId) { currentSearchedBooking = data; populateBookingDetails(data); $('#bookingDetailResult').show(); } else { Swal.fire({ icon: 'error', title: 'Not Found', text: 'No booking found for ID: ' + bookingId }); $('#bookingDetailResult').hide(); } }, error: function (xhr) { Swal.close(); var msg = (xhr.status === 404) ? 'Booking ID ' + bookingId + ' does not exist.' : 'Error fetching booking.'; Swal.fire({ icon: 'error', title: 'Error', text: msg }); $('#bookingDetailResult').hide(); } }); }
// ─── CLEAR BOOKING SEARCH ─── function clearBookingSearch() { var input = document.getElementById('searchBookingId'); if (input) input.value = ''; $('#bookingDetailResult').hide(); currentSearchedBooking = null; }
$(document).ready(function () { $('#searchBookingId').on('keypress', function (e) { if (e.key === 'Enter') searchBookingById(); });
// OTP input auto-advance and backspace handling $('.cro-otp-input').on('keyup', function (e) { var $this = $(this); if (e.key === 'Backspace' || e.key === 'Delete') { if ($this.val().length === 0) { $this.prev('.cro-otp-input').focus(); } } else if (e.key >= '0' && e.key <= '9') { if ($this.val().length === 1) { $this.next('.cro-otp-input').focus(); } } });
// Paste handling for OTP inputs $('.cro-otp-input').first().on('paste', function (e) { var pasteData = (e.originalEvent.clipboardData || window.clipboardData).getData('text').trim(); if (/^\d{5}$/.test(pasteData)) { e.preventDefault(); for (var i = 0; i < 5; i++) { $('#croOtp' + (i + 1)).val(pasteData[i]); } $('#croOtp5').focus(); } }); });
// ─── POPULATE BOOKING DETAILS ─── function populateBookingDetails(list) { var ud = list.users || {}; var hd = list.hallDetails || {}; var py = list.payments || {};
document.getElementById('res_userName').innerHTML = ud.name || 'N/A'; document.getElementById('res_mobileNumber').innerHTML = ud.mobileNo || 'N/A'; document.getElementById('res_usertype').innerHTML = ud.usertype || 'N/A'; document.getElementById('res_useraddress').innerHTML = ud.doorNo ? ud.doorNo + ', ' + ud.street + ', ' + ud.area + ', ' + ud.location + '- ' + ud.pinCode : 'N/A'; document.getElementById('res_hallName').innerHTML = hd.hallName || 'N/A'; document.getElementById('res_halladdress').innerHTML = hd.doorNo ? hd.doorNo + ', ' + hd.street + ', ' + hd.area + ', ' + hd.city + '- ' + hd.pinCode : 'N/A'; document.getElementById('res_caretakername').innerHTML = hd.hallInchargeName || 'N/A'; document.getElementById('res_caretakermobileNumber').innerHTML = hd.hallInchargeMobno || 'N/A'; document.getElementById('res_booking_id').innerHTML = list.bookingId; document.getElementById('resultBookingId').innerHTML = ' #' + list.bookingId; document.getElementById('res_bookingDate').innerHTML = list.bookingDate || 'N/A'; document.getElementById('res_bookingStatus').innerHTML = list.bookingStatus || 'N/A'; document.getElementById('res_startDate').innerHTML = list.startDate || 'N/A'; document.getElementById('res_endDate').innerHTML = list.endDate || 'N/A'; document.getElementById('res_depositeAmount').innerHTML = list.depositAmount ? '₹ ' + parseFloat(list.depositAmount).toFixed(2) : 'N/A'; document.getElementById('res_hallAmount').innerHTML = list.hallAmount ? '₹ ' + parseFloat(list.hallAmount).toFixed(2) : 'N/A'; document.getElementById('res_totalAmount').innerHTML = list.amountReceived ? '₹ ' + parseFloat(list.amountReceived).toFixed(2) : 'N/A'; var gst = (list.hallAmount && hd.gst) ? (parseFloat(list.hallAmount) * (hd.gst / 100)).toFixed(2) : '0.00'; document.getElementById('res_gst').innerHTML = '₹ ' + gst; document.getElementById('res_startingSlot').innerHTML = getSlotLabel(list.startingSlot); document.getElementById('res_endingSlot').innerHTML = getSlotLabel(list.endingSlot); document.getElementById('res_reason').innerHTML = list.reason || 'N/A'; document.getElementById('res_transactionId').innerHTML = py.transactionId || 'NA'; document.getElementById('res_payamountReceived').innerHTML = py.amountReceived ? '₹ ' + py.amountReceived : 'NA'; document.getElementById('res_paymentStatus').innerHTML = py.paymentStatus || 'NA';
// Status Badge var status = (list.bookingStatus || '').toUpperCase().trim(); var badgeEl = document.getElementById('res_bookingStatusBadge'); badgeEl.textContent = status; badgeEl.className = 'badge status-badge-lg ' + getStatusBadgeClass(status);
// ─── Status Change Eligibility Check ─── // 1. Status must be APPROVED, WAITING_FOR_NOC, or WAITING_FOR_NOC_APPROVAL // 2. Start date and End date must NOT be future dates (only completed events allowed) var eligibleStatuses = ['APPROVED', 'WAITING_FOR_NOC', 'WAITING_FOR_NOC_APPROVAL']; var isStatusEligible = (eligibleStatuses.indexOf(status) !== -1); var hasEbDetails = list.ebDetails != null && (list.ebDetails.id != null || list.ebDetails.startingReading != null);
// Date checks: var today = new Date(); var yyyy = today.getFullYear(); var mm = String(today.getMonth() + 1).padStart(2, '0'); var dd = String(today.getDate()).padStart(2, '0'); var todayStr = yyyy + '-' + mm + '-' + dd;
var startDateStr = (list.startDate || '').trim(); var endDateStr = (list.endDate || '').trim();
var isFutureEvent = false; if (startDateStr && startDateStr > todayStr) { isFutureEvent = true; } else if (endDateStr && endDateStr > todayStr) { isFutureEvent = true; }
if (isStatusEligible && !isFutureEvent && !hasEbDetails) { $('#statusChangeSection').show(); $('#statusChangeNotAllowedMsg').hide(); $('#changeBookingStatusSelect').val(''); $('#statusChangeRemarks').val(''); } else { $('#statusChangeSection').hide(); $('#statusChangeNotAllowedMsg').show(); $('#notAllowedCurrentStatusBadge').text(status || 'UNKNOWN'); if (isFutureEvent) { $('#notAllowedDetailMsg').html('Booking dates (<strong>' + (startDateStr || 'N/A') + ' to ' + (endDateStr || 'N/A') + '</strong>) are in the future. CRO is <strong>not permitted</strong> to change the status for future events. Only <strong>completed events</strong> can be marked as <strong>REJECTED</strong> or <strong>GCC_BLOCKED</strong>.'); } else { $('#notAllowedDetailMsg').html('Status change is only permitted for <strong>Past events</strong> with status <strong>APPROVED</strong>, <strong>WAITING_FOR_NOC</strong>, or <strong>WAITING_FOR_NOC_APPROVAL</strong>. EB Details must not have been entered for the booking.'); } } }
function getStatusBadgeClass(status) { switch (status) { case 'APPROVED': return 'bg-success'; case 'WAITING_FOR_NOC': case 'WAITING_FOR_NOC_APPROVAL': return 'bg-warning text-dark'; case 'REJECTED': case 'GCC_BLOCKED': case 'CANCELED': return 'bg-danger'; case 'COMPLETED': return 'bg-info text-dark'; case 'PENDING': return 'bg-secondary'; default: return 'bg-primary'; } }
function getSlotLabel(v) { var s = String(v).trim(); if (s === '1') return 'Morning'; if (s === '2') return 'Evening'; return 'Unknown'; }
// ─── INITIATE STATUS CHANGE (Trigger OTP) ─── function initiateStatusChange() { if (!currentSearchedBooking || !currentSearchedBooking.bookingId) { Swal.fire({ icon: 'warning', title: 'No Booking Selected', text: 'Please search and select a booking first.' }); return; }
// Check future event restriction var today = new Date(); var todayStr = today.getFullYear() + '-' + String(today.getMonth() + 1).padStart(2, '0') + '-' + String(today.getDate()).padStart(2, '0'); var sDate = (currentSearchedBooking.startDate || '').trim(); var eDate = (currentSearchedBooking.endDate || '').trim(); if ((sDate && sDate > todayStr) || (eDate && eDate > todayStr)) { Swal.fire({ icon: 'warning', title: 'Action Not Allowed', text: 'Status change is not permitted for future events. Only past events can be marked as REJECTED or GCC_BLOCKED.' }); return; }
var newStatus = $('#changeBookingStatusSelect').val(); if (!newStatus || (newStatus !== 'REJECTED' && newStatus !== 'GCC_BLOCKED')) { Swal.fire({ icon: 'warning', title: 'Status Required', text: 'Please select a new Booking Status (REJECTED or GCC_BLOCKED).' }); return; }
var remarks = $('#statusChangeRemarks').val().trim(); if (!remarks) { Swal.fire({ icon: 'warning', title: 'Remarks Required', text: 'Please enter reason / remarks for this status change.' }); $('#statusChangeRemarks').focus(); return; }
Swal.fire({ title: 'Confirm Status Change', html: 'Are you sure you want to change Booking <b>#' + currentSearchedBooking.bookingId + '</b> status to <b class="text-danger">' + newStatus + '</b>?<br/><small class="text-muted">An OTP will be sent to your CRO mobile number to authorize this change.</small>', icon: 'question', showCancelButton: true, confirmButtonText: 'Yes, Send OTP', cancelButtonText: 'Cancel', confirmButtonColor: '#d33' }).then((result) => { if (result.isConfirmed) { sendCroStatusOtp(newStatus, remarks); } }); }
// ─── SEND CRO OTP ─── function sendCroStatusOtp(newStatus, remarks) { Swal.fire({ title: 'Sending OTP...', text: 'Please wait while OTP is sent to your registered mobile number.', allowOutsideClick: false, didOpen: () => { Swal.showLoading(); } });
$.ajax({ type: 'GET', url: '/communityhall/user/api/sendOTP', data: { mobileNo: croMobileNumber, purpose: 'CRO Status Change' }, success: function (bodyMessage) { Swal.close(); if (bodyMessage && bodyMessage !== 'Error') { var mobStr = String(croMobileNumber); var maskedMobile = mobStr.length >= 10 ? mobStr.substring(0, 2) + 'XXXXXX' + mobStr.substring(mobStr.length - 2) : mobStr;
$('#croOtpMobileDisplay').text(maskedMobile || 'Registered CRO Number'); $('#modalBookingIdText').text('#' + currentSearchedBooking.bookingId); $('#modalNewStatusText').text(newStatus); $('#croOtpErrorAlert').hide().text('');
// Clear OTP boxes $('.cro-otp-input').val('');
// Show modal $('#croStatusOtpModal').modal('show'); setTimeout(function () { $('#croOtp1').focus(); }, 500);
// Start countdown startCroCountdown(); } else { Swal.fire({ icon: 'error', title: 'OTP Failed', text: 'Failed to send OTP. Please try again.' }); } }, error: function () { Swal.close(); Swal.fire({ icon: 'error', title: 'Error', text: 'Failed to send OTP. Please check your network connection.' }); } }); }
// ─── COUNTDOWN TIMER FOR RESEND OTP ─── function startCroCountdown() { if (croResendTimer) clearInterval(croResendTimer); var timeLeft = 60; $('#croResendText').text('Please wait..'); $('#croCountdown').text(timeLeft);
croResendTimer = setInterval(function () { timeLeft--; $('#croCountdown').text(timeLeft); if (timeLeft <= 0) { clearInterval(croResendTimer); $('#croResendText').html('<a href="javascript:void(0)" class="text-info" onclick="resendCroOtp()">Resend OTP</a>'); $('#croCountdown').text(''); } }, 1000); }
function resendCroOtp() { var newStatus = $('#changeBookingStatusSelect').val(); var remarks = $('#statusChangeRemarks').val().trim(); sendCroStatusOtp(newStatus, remarks); }
// ─── VERIFY OTP & SUBMIT STATUS CHANGE ─── function verifyAndSubmitStatusChange() { var otpValue = ''; for (var i = 1; i <= 5; i++) { otpValue += ($('#croOtp' + i).val() || '').trim(); }
if (otpValue.length !== 5 || isNaN(otpValue)) { $('#croOtpErrorAlert').text('Please enter the complete 5-digit OTP.').show(); return; }
var newStatus = $('#changeBookingStatusSelect').val(); var remarks = $('#statusChangeRemarks').val().trim(); var bookingId = currentSearchedBooking.bookingId;
$('#btnVerifyCroOtp').prop('disabled', true).html('<i class="fa fa-spinner fa-spin me-1"></i> Verifying...'); $('#croOtpErrorAlert').hide();
$.ajax({ type: 'POST', url: '/communityhall/cro/api/updateBookingStatus', data: { bookingId: bookingId, status: newStatus, comments: remarks, otp: otpValue }, success: function (response) { $('#btnVerifyCroOtp').prop('disabled', false).html('<i class="fa fa-check-circle me-1"></i> Verify & Update Status'); if (response && response.status === 'success') { $('#croStatusOtpModal').modal('hide'); if (croResendTimer) clearInterval(croResendTimer);
Swal.fire({ icon: 'success', title: 'Status Updated!', html: 'Booking <b>#' + bookingId + '</b> status has been successfully changed to <b class="text-danger">' + newStatus + '</b>.', confirmButtonText: 'OK' }).then(() => { // Re-fetch booking details to update view in real-time searchBookingById(); }); } else { var errMsg = (response && response.message) || 'Failed to update status.'; $('#croOtpErrorAlert').text(errMsg).show(); } }, error: function (xhr) { $('#btnVerifyCroOtp').prop('disabled', false).html('<i class="fa fa-check-circle me-1"></i> Verify & Update Status'); var errMsg = 'Verification failed. Please try again.'; if (xhr.responseJSON && xhr.responseJSON.message) { errMsg = xhr.responseJSON.message; } else if (xhr.responseText) { try { var parsed = JSON.parse(xhr.responseText); if (parsed.message) errMsg = parsed.message; } catch (e) { } } $('#croOtpErrorAlert').text(errMsg).show(); } }); } </script> </div></body>
</html>
|