1/** 2 * Event Booking Dashboard JavaScript 3 * Enhanced My Account Dashboard for Event Bookings 4 */ 5 6(function($) { 7 'use strict'; 8 9 const MPWEM_Dashboard = { 10 11 // Current filter state 12 currentFilter: 'all', 13 14 /** 15 * Initialize 16 */ 17 init: function() { 18 this.bindEvents(); 19 }, 20 21 /** 22 * Bind events 23 */ 24 bindEvents: function() { 25 // Search button 26 $(document).on('click', '#mpwem-search-btn', this.searchBookings.bind(this)); 27 28 // Reset button 29 $(document).on('click', '#mpwem-reset-btn', this.resetSearch.bind(this)); 30 31 // Enter key in search 32 $(document).on('keypress', '#mpwem-search-order', function(e) { 33 if (e.which === 13) { 34 e.preventDefault(); 35 MPWEM_Dashboard.searchBookings(); 36 } 37 }); 38 39 // Stats filter click 40 $(document).on('click', '.mpwem-stat-clickable', this.filterByStats.bind(this)); 41 42 // View booking details 43 $(document).on('click', '.mpwem-btn-view', this.viewBookingDetails.bind(this)); 44 45 // Close modal 46 $(document).on('click', '.mpwem-modal-close', this.closeModal.bind(this)); 47 $(document).on('click', '.mpwem-modal', function(e) { 48 if ($(e.target).hasClass('mpwem-modal')) { 49 MPWEM_Dashboard.closeModal(); 50 } 51 }); 52 53 // ESC key to close modal 54 $(document).on('keydown', function(e) { 55 if (e.key === 'Escape') { 56 MPWEM_Dashboard.closeModal(); 57 } 58 }); 59 60 // Cancel request button 61 $(document).on('click', '.mpwem-btn-cancel:not(.mpwem-btn-disabled)', this.openCancelModal.bind(this)); 62 }, 63 64 /** 65 * Filter bookings by stats 66 */ 67 filterByStats: function(e) { 68 const filter = $(e.currentTarget).data('filter'); 69 70 // Update active state 71 $('.mpwem-stat-clickable').removeClass('active'); 72 $(e.currentTarget).addClass('active'); 73 74 // Update current filter 75 this.currentFilter = filter; 76 77 // Load filtered bookings 78 this.searchBookings(); 79 }, 80 81 /** 82 * Search bookings 83 */ 84 searchBookings: function() { 85 const searchValue = $('#mpwem-search-order').val().trim(); 86 87 $('#mpwem-bookings-list').html('<tr><td colspan="6" class="mpwem-loading"><span class="spinner is-active"></span> ' + 88 'Loading...</td></tr>'); 89 90 $.ajax({ 91 url: mpwem_account_vars.ajax_url, 92 type: 'POST', 93 data: { 94 action: 'mpwem_search_bookings', 95 nonce: mpwem_account_vars.nonce, 96 search: searchValue, 97 filter: this.currentFilter 98 }, 99 success: function(response) { 100 if (response.success) { 101 $('#mpwem-bookings-list').html(response.data.html); 102 } else { 103 MPWEM_Dashboard.showNotification('error', response.data.message || 'An error occurred'); 104 } 105 }, 106 error: function() { 107 MPWEM_Dashboard.showNotification('error', 'Failed to search bookings. Please try again.'); 108 $('#mpwem-bookings-list').html('<tr><td colspan="6" class="mpwem-no-bookings">Failed to load bookings.</td></tr>'); 109 } 110 }); 111 }, 112 113 /** 114 * Reset search 115 */ 116 resetSearch: function() { 117 $('#mpwem-search-order').val(''); 118 $('.mpwem-stat-clickable').removeClass('active'); 119 $('.mpwem-stat-clickable[data-filter="all"]').addClass('active'); 120 this.currentFilter = 'all'; 121 this.searchBookings(); 122 }, 123 124 /** 125 * View booking details 126 */ 127 viewBookingDetails: function(e) { 128 e.preventDefault(); 129 130 const orderId = $(e.currentTarget).data('order-id'); 131 132 if (!orderId) { 133 this.showNotification('error', 'Invalid order ID'); 134 return; 135 } 136 137 // Show modal with loading state 138 $('#mpwem-booking-details-modal').fadeIn(300); 139 $('#mpwem-booking-details-content').html( 140 '<div class="mpwem-loading"><span class="spinner is-active"></span> Loading booking details...</div>' 141 ); 142 143 // Fetch booking details 144 $.ajax({ 145 url: mpwem_account_vars.ajax_url, 146 type: 'POST', 147 data: { 148 action: 'mpwem_get_booking_details', 149 nonce: mpwem_account_vars.nonce, 150 order_id: orderId 151 }, 152 success: function(response) { 153 if (response.success) { 154 $('#mpwem-booking-details-content').html(response.data.html); 155 MPWEM_Dashboard.scrollToTop('#mpwem-booking-details-modal .mpwem-modal-content'); 156 } else { 157 $('#mpwem-booking-details-content').html( 158 '<div class="mpwem-error" style="padding: 40px 20px; text-align: center; color: #d63638;">' + 159 '<p>' + (response.data.message || 'Failed to load booking details') + '</p>' + 160 '</div>' 161 ); 162 } 163 }, 164 error: function() { 165 $('#mpwem-booking-details-content').html( 166 '<div class="mpwem-error" style="padding: 40px 20px; text-align: center; color: #d63638;">' + 167 '<p>Failed to load booking details. Please try again.</p>' + 168 '</div>' 169 ); 170 } 171 }); 172 }, 173 174 /** 175 * Close modal 176 */ 177 closeModal: function() { 178 $('.mpwem-modal').fadeOut(300); 179 }, 180 181 /** 182 * Open cancel request modal 183 */ 184 openCancelModal: function(e) { 185 e.preventDefault(); 186 187 const cancelUrl = $(e.currentTarget).attr('href'); 188 if (!cancelUrl || cancelUrl === '#') { 189 return; 190 } 191 192 // Parse URL to get order details
193 const urlParams = new URLSearchParams(cancelUrl.split('?')[1]); 194 const orderId = urlParams.get('serial'); 195 196 if (!orderId) { 197 this.showNotification('error', 'Invalid order ID'); 198 return; 199 } 200 201 // Build modal content 202 const modalContent = ` 203 <div class="mpwem-cancel-request-form"> 204 <h3>Order Cancellation Request</h3> 205 <form id="mpwem-cancel-form" method="post"> 206 <div class="mpwem-form-group"> 207 <label><strong>Order No:</strong> #${orderId}</label> 208 </div> 209 <div class="mpwem-form-group"> 210 <label for="mpwem_order_cancel_reason"> 211 <strong>Cancel Reason</strong> 212 <p style="margin: 5px 0; color: #666; font-size: 13px;">Please write details about why you want to cancel.</p> 213 </label> 214 <textarea 215 name="mep_order_cancel_reason" 216 id="mpwem_order_cancel_reason" 217 class="mpwem-textarea" 218 rows="6" 219 required 220 placeholder="Enter your reason for cancellation..." 221 ></textarea> 222 </div> 223 <input type="hidden" name="action" value="mep_cancel_req_submit"> 224 <input type="hidden" name="order_id" value="${orderId}"> 225 <div class="mpwem-form-actions"> 226 <button type="submit" class="mpwem-btn mpwem-btn-primary" id="mpwem-submit-cancel"> 227 <span class="dashicons dashicons-yes"></span> 228 Send Request 229 </button> 230 <button type="button" class="mpwem-btn mpwem-btn-secondary mpwem-modal-close"> 231 <span class="dashicons dashicons-no"></span> 232 Cancel 233 </button> 234 </div> 235 </form>
236 </div> 237 `; 238 239 // Show modal 240 $('#mpwem-cancel-modal-content').html(modalContent); 241 $('#mpwem-cancel-modal').fadeIn(300); 242 243 // Focus on textarea 244 setTimeout(function() { 245 $('#mpwem_order_cancel_reason').focus(); 246 }, 350); 247 248 // Handle form submission 249 $('#mpwem-cancel-form').off('submit').on('submit', function(e) { 250 e.preventDefault(); 251 MPWEM_Dashboard.submitCancelRequest($(this)); 252 }); 253 }, 254 255 /** 256 * Submit cancel request 257 */ 258 submitCancelRequest: function($form) { 259 const reason = $('#mpwem_order_cancel_reason').val().trim(); 260 261 if (!reason) { 262 this.showNotification('error', 'Please provide a reason for cancellation'); 263 return; 264 } 265 266 const $submitBtn = $('#mpwem-submit-cancel'); 267 const originalText = $submitBtn.html(); 268 269 $submitBtn.prop('disabled', true).html('<span class="spinner is-active" style="float:none; margin:0;"></span> Sending...'); 270 271 $.ajax({ 272 url: window.location.href.split('?')[0], 273 type: 'POST', 274 data: $form.serialize(), 275 success: function(response) { 276 // Close modal 277 MPWEM_Dashboard.closeModal(); 278 279 // Show success message 280 MPWEM_Dashboard.showNotification('success', 'Your cancellation request has been received'); 281 282 // Reload page after a short delay 283 setTimeout(function() { 284 window.location.href = window.location.href.split('?')[0]; 285 }, 2000); 286 }, 287 error: function() { 288 $submitBtn.prop('disabled', false).html(originalText); 289 MPWEM_Dashboard.showNotification('error', 'Failed to submit request. Please try again.'); 290 } 291 }); 292 }, 293 294 /** 295 * Show notification 296 */ 297 showNotification: function(type, message) { 298 // Remove existing notifications 299 $('.mpwem-notification').remove(); 300 301 const typeClass = type === 'error' ? 'mpwem-notification-error' : 'mpwem-notification-success'; 302 const icon = type === 'error' ? '<span class="dashicons dashicons-warning"></span>' : '<span class="dashicons dashicons-yes"></span>'; 303 304 const notification = $('<div class="mpwem-notification ' + typeClass + '">' + icon + ' ' + message + '</div>'); 305 306 notification.css({ 307 position: 'fixed', 308 top: '20px', 309 right: '20px', 310 padding: '15px 20px', 311 background: type === 'error' ? '#d63638' : '#00a32a', 312 color: '#fff', 313 borderRadius: '4px', 314 boxShadow: '0 2px 10px rgba(0,0,0,0.2)', 315 zIndex: 999999, 316 display: 'flex', 317 alignItems: 'center', 318 gap: '10px', 319 fontSize: '14px', 320 fontWeight: '500', 321 animation: 'slideInRight 0.3s ease' 322 }); 323 324 $('body').append(notification); 325 326 setTimeout(function() { 327 notification.fadeOut(300, function() { 328 $(this).remove(); 329 }); 330 }, 5000); 331 }, 332 333 /** 334 * Scroll to top of element 335 */ 336 scrollToTop: function(element) { 337 const $element = $(element); 338 if ($element.length) { 339 $element.animate({ 340 scrollTop: 0 341 }, 300); 342 } 343 }, 344 345 /** 346 * Scroll page to element 347 */ 348 scrollToElement: function(element, offset) { 349 offset = offset || 100; 350 $('html, body').animate({ 351 scrollTop: $(element).offset().top - offset 352 }, 500); 353 } 354 }; 355 356 // Initialize when document is ready 357 $(document).ready(function() { 358 MPWEM_Dashboard.init(); 359 360 // Set default active state for "Total Bookings" 361 $('.mpwem-stat-clickable[data-filter="all"]').addClass('active'); 362 363 // Check if cancel request was triggered from URL 364 const urlParams = new URLSearchParams(window.location.search); 365 if (urlParams.get('action') === 'mep_order_cancel_req') { 366 // Find the cancel button for this order and trigger click 367 const orderId = urlParams.get('serial'); 368 if (orderId) { 369 setTimeout(function() { 370 $('.mpwem-btn-cancel[href*="serial=' + orderId + '"]').trigger('click'); 371 }, 500); 372 } 373 } 374 }); 375 376 // Add CSS animation 377 const style = document.createElement('style'); 378 style.textContent = ` 379 @keyframes slideInRight { 380 from { 381 transform: translateX(100%); 382 opacity: 0; 383 } 384 to { 385 transform: translateX(0); 386 opacity: 1; 387 } 388 } 389 `; 390 document.head.appendChild(style); 391 392})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.