🏨 Hotel Booking Enhancements: - Implemented Eagle Booking Advanced Pricing add-on - Added Booking.com-style rate management system - Created professional calendar interface for pricing - Integrated deals and discounts functionality 💰 Advanced Pricing Features: - Dynamic pricing models (per room, per person, per adult) - Base rates, adult rates, and child rates management - Length of stay discounts and early bird deals - Mobile rates and secret deals implementation - Seasonal promotions and flash sales 📅 Availability Management: - Real-time availability tracking - Stop sell and restriction controls - Closed to arrival/departure functionality - Minimum/maximum stay requirements - Automatic sold-out management 💳 Payment Integration: - Maintained Redsys payment gateway integration - Seamless integration with existing Eagle Booking - No modifications to core Eagle Booking plugin 🛠️ Technical Implementation: - Custom database tables for advanced pricing - WordPress hooks and filters integration - AJAX-powered admin interface - Data migration from existing Eagle Booking - Professional calendar view for revenue management 📊 Admin Interface: - Booking.com-style management dashboard - Visual rate and availability calendar - Bulk operations for date ranges - Statistics and analytics dashboard - Modal dialogs for quick editing 🔧 Code Quality: - WordPress coding standards compliance - Secure database operations with prepared statements - Proper input validation and sanitization - Error handling and logging - Responsive admin interface 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
455 lines
14 KiB
JavaScript
455 lines
14 KiB
JavaScript
/*================================================
|
|
* Plugin Name: Eagle Booking
|
|
* Version: 1.1.6
|
|
* Author Name: Jomin Muskaj (Eagle-Themes)
|
|
* Author URI: eagle-themes.com
|
|
=================================================*/
|
|
|
|
(function ($) {
|
|
"use strict";
|
|
|
|
/* Document is Raedy */
|
|
$(document).ready(function () {
|
|
|
|
// =============================================
|
|
// DATERANGEPICKER
|
|
// =============================================
|
|
var eb_calendar_min_date = new Date();
|
|
var eb_calendar_max_date = moment(eb_calendar_min_date).add(eb_js_settings.eb_calendar_availability_period, 'M').endOf('month');
|
|
var eagle_booking_date_format = eb_js_settings.eagle_booking_date_format.toUpperCase();
|
|
|
|
var eb_signle_room = false;
|
|
|
|
// Check if calendar is on single room
|
|
if ( $('form').hasClass('room-booking-form') ) {
|
|
|
|
eb_signle_room = true;
|
|
|
|
}
|
|
|
|
$(".eb-datepicker").each(function () {
|
|
|
|
var calendar = $(this);
|
|
|
|
$(calendar).daterangepicker({
|
|
autoUpdateInput: false,
|
|
autoApply: true,
|
|
alwaysShowCalendars: true,
|
|
linkedCalendars: true,
|
|
|
|
isInvalidDate: function(date) {
|
|
|
|
if ( typeof eb_booked_dates!== 'undefined' && eb_booked_dates != '' ) {
|
|
|
|
return !!(eb_booked_dates.indexOf(date.format('YYYY/MM/DD')) > 0);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
minDate: eb_calendar_min_date,
|
|
maxDate: eb_calendar_max_date,
|
|
locale: {
|
|
format: eagle_booking_date_format,
|
|
separator: " → ",
|
|
"daysOfWeek": [
|
|
eb_js_settings.eb_calendar_sunday,
|
|
eb_js_settings.eb_calendar_monday,
|
|
eb_js_settings.eb_calendar_tuesday,
|
|
eb_js_settings.eb_calendar_wednesday,
|
|
eb_js_settings.eb_calendar_thursday,
|
|
eb_js_settings.eb_calendar_friday,
|
|
eb_js_settings.eb_calendar_saturday,
|
|
],
|
|
"monthNames": [
|
|
eb_js_settings.eb_calendar_january,
|
|
eb_js_settings.eb_calendar_february,
|
|
eb_js_settings.eb_calendar_march,
|
|
eb_js_settings.eb_calendar_april,
|
|
eb_js_settings.eb_calendar_may,
|
|
eb_js_settings.eb_calendar_june,
|
|
eb_js_settings.eb_calendar_july,
|
|
eb_js_settings.eb_calendar_august,
|
|
eb_js_settings.eb_calendar_september,
|
|
eb_js_settings.eb_calendar_october,
|
|
eb_js_settings.eb_calendar_november,
|
|
eb_js_settings.eb_calendar_december,
|
|
],
|
|
"firstDay": 1
|
|
}
|
|
}),
|
|
|
|
$(calendar).on("apply.daterangepicker", function () {
|
|
|
|
// Displayd Format
|
|
var checkin = $(calendar).data('daterangepicker').startDate.format(eagle_booking_date_format);
|
|
var checkout = $(calendar).data('daterangepicker').endDate.format(eagle_booking_date_format);
|
|
|
|
// Display Date
|
|
$(this).val(checkin + " " + " " + " → " + " " + " " + checkout);
|
|
|
|
// Add value to hidden inouts
|
|
$('.eb_checkin').val(checkin);
|
|
$('.eb_checkout').val(checkout);
|
|
|
|
// Update Booking Filters only for the search page (filters)
|
|
if ($("div").hasClass("search-filters")) {
|
|
eb_search_filters();
|
|
}
|
|
|
|
if ($("div").hasClass("search-filters") || $("div").hasClass("calendar")) {
|
|
eb_get_nights(calendar);
|
|
}
|
|
|
|
// Disable all booked & blocked room on the signle room calendar
|
|
if ( eb_signle_room == true ) {
|
|
|
|
var i, eb_booked_date;
|
|
|
|
// Loop all booked dates until the condition
|
|
for( i = 0; i < eb_booked_dates.length; i++ ) {
|
|
|
|
eb_booked_date = moment(eb_booked_dates[i]).format('YYYY/MM/DD');
|
|
|
|
var checkin_new = $(calendar).data('daterangepicker').startDate.format('YYYY-MM-DD');
|
|
var checkout_new = $(calendar).data('daterangepicker').endDate.format('YYYY-MM-DD');
|
|
|
|
if ( moment(eb_booked_date).isBetween(checkin_new, checkout_new) ) {
|
|
|
|
$(this).data('daterangepicker').setStartDate(checkout);
|
|
$(this).val("").focus();
|
|
|
|
// Break loop on the first match
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
// =============================================
|
|
// CALCULATE NIGHTS NUMBER
|
|
// =============================================
|
|
function eb_get_nights( calendar ) {
|
|
|
|
var eagle_booking_checkin = $(calendar).parent().find('.eb_checkin').val();
|
|
var eagle_booking_checkout = $(calendar).parent().find('.eb_checkout').val();
|
|
|
|
var eagle_booking_start_date = moment(eagle_booking_checkin, eb_js_settings.eagle_booking_date_format.toUpperCase()).format('YYYY-MM-DD');;
|
|
var eagle_booking_end_date = moment(eagle_booking_checkout, eb_js_settings.eagle_booking_date_format.toUpperCase()).format('YYYY-MM-DD');;
|
|
|
|
var booking_nights = (new Date(eagle_booking_end_date)) - (new Date(eagle_booking_start_date));
|
|
var eagle_booking_nights_number = booking_nights / (1000 * 60 * 60 * 24);
|
|
if (eagle_booking_nights_number < 0) {
|
|
var eagle_booking_nights_number = '0';
|
|
}
|
|
|
|
return eagle_booking_nights_number;
|
|
|
|
}
|
|
|
|
// =============================================
|
|
// GUESTS SELECT
|
|
// =============================================
|
|
$('.eb-guestspicker .guestspicker').on('click', function (event) {
|
|
$('.eb-guestspicker').toggleClass('active');
|
|
event.preventDefault();
|
|
});
|
|
$(window).click(function () {
|
|
$('.eb-guestspicker').removeClass('active');
|
|
});
|
|
$('.eb-guestspicker').on('click', function (event) {
|
|
event.stopPropagation();
|
|
});
|
|
|
|
function guestsSum() {
|
|
var arr = $('.booking-guests');
|
|
var guests = 0;
|
|
for (var i = 0; i < arr.length; i++) {
|
|
if (parseInt(arr[i].value, 10))
|
|
guests += parseInt(arr[i].value, 10);
|
|
}
|
|
if (guests > 0) {
|
|
var cardQty = document.querySelector(".gueststotal");
|
|
cardQty.innerHTML = guests;
|
|
}
|
|
|
|
// Add the new value to geust input
|
|
$("#eagle_booking_guests").val(guests);
|
|
|
|
}
|
|
|
|
guestsSum();
|
|
|
|
$(function () {
|
|
$(".plus, .minus").on("click", function () {
|
|
var button = $(this);
|
|
var oldValue = button.parent().find("input").val();
|
|
var min_value = button.parent().find("input").attr("min");
|
|
|
|
if (button.hasClass('plus')) {
|
|
var newVal = parseFloat(oldValue) + 1;
|
|
} else {
|
|
|
|
if (oldValue > min_value) {
|
|
var newVal = parseFloat(oldValue) - 1;
|
|
} else {
|
|
newVal = min_value;
|
|
}
|
|
|
|
}
|
|
|
|
button.parent().find("input").val(newVal);
|
|
|
|
guestsSum();
|
|
|
|
if ($('form').hasClass('booking-search-form')) {
|
|
eagle_booking_filters();
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
/*----------------------------------------------------*/
|
|
/* Bookings Filters
|
|
/*----------------------------------------------------*/
|
|
// bind change event to select
|
|
$('.eb_bookings_filter').on('change', function () {
|
|
var url = $(this).val(); // get selected value
|
|
if (url) { // require a URL
|
|
window.location = url; // redirect
|
|
}
|
|
return false;
|
|
|
|
});
|
|
|
|
/*----------------------------------------------------*/
|
|
/* Bookings Calendar AJAX
|
|
/*----------------------------------------------------*/
|
|
function eb_calendar_room_availability() {
|
|
|
|
// handler to the ajax request
|
|
var eb_ajax_calendar_room_availability_xhr = null;
|
|
|
|
$('.eb-room-booked').on('mouseenter', function(event) {
|
|
|
|
// Remove any previous active
|
|
$('.eb-room-booked').removeClass("open");
|
|
|
|
var popover = $('#eb-room-availability-popup');
|
|
var eb_loader = '<div id="eb-loader"></div>';
|
|
|
|
popover.append(eb_loader);
|
|
|
|
$('#eb-calendar-title').hide();
|
|
$('#eb-calendar-title-loading').show();
|
|
|
|
// Empty any previous results
|
|
$("#eb-room-availability-popup #content").empty();
|
|
$("#eb-calendar-date").empty();
|
|
$("#eb-calendar-room-title").empty();
|
|
|
|
// Popover Position
|
|
var pos = $(this).position();
|
|
var date_width = $(this).outerWidth();
|
|
var calendar_width = $('.eb-calendar-view').outerWidth();
|
|
var popover_width = $('#eb-room-availability-popup').outerWidth();
|
|
|
|
// Display popover in the left side
|
|
if ( (calendar_width - pos.left) < popover_width + 50 ) {
|
|
|
|
var popover_pos = pos.left - popover_width;
|
|
popover.removeClass('right');
|
|
popover.addClass('left');
|
|
|
|
// Display popover in the right side
|
|
} else {
|
|
|
|
var popover_pos = pos.left + date_width;
|
|
popover.removeClass('left');
|
|
popover.addClass('right');
|
|
|
|
}
|
|
|
|
popover.css({
|
|
position: "absolute",
|
|
top: pos.top + "px",
|
|
left: (popover_pos) + "px",
|
|
|
|
}).show();
|
|
|
|
|
|
var eb_date = $(this).data("date");
|
|
var eb_displayed_date = $(this).data("displayed-date");
|
|
var eb_room_id = $(this).data("room-id");
|
|
var eb_room_title = $(this).data("room-title");
|
|
|
|
// if there is a previous ajax request, then abort it
|
|
if( eb_ajax_calendar_room_availability_xhr != null ) {
|
|
eb_ajax_calendar_room_availability_xhr.abort();
|
|
eb_ajax_calendar_room_availability_xhr = null;
|
|
}
|
|
|
|
// Start the AJAX request
|
|
eb_ajax_calendar_room_availability_xhr = $.ajax({
|
|
|
|
url: eb_admin_ajax.eb_admin_calendar_ajax,
|
|
method: 'GET',
|
|
dataType: 'json',
|
|
data: {
|
|
action: 'eb_admin_calendar_action',
|
|
eb_date: eb_date,
|
|
eb_room_id: eb_room_id,
|
|
eb_calendar_nonce: eb_admin_ajax.eb_admin_ajax_nonce,
|
|
},
|
|
|
|
// Success
|
|
success: function (eb_calendar_room_availability_data) {
|
|
|
|
// Appened new results
|
|
$("#eb-room-availability-popup #content").append(eb_calendar_room_availability_data.output);
|
|
|
|
$("#eb-room-availability-popup #content #bookings").append(eb_calendar_room_availability_data.bookings);
|
|
|
|
$('#eb-calendar-title-loading').hide();
|
|
$('#eb-calendar-title').show();
|
|
$('#eb-calendar-date').text(eb_displayed_date);
|
|
$('#eb-calendar-room-title').text(eb_room_title);
|
|
|
|
},
|
|
|
|
error: function (eb_ajax_calendar_room_availability_xhr, textStatus, errorThrown) {
|
|
// Console mssg - debug purpose
|
|
console.log(errorThrown);
|
|
|
|
},
|
|
|
|
complete: function () {
|
|
|
|
// Remove loader
|
|
$('#eb-loader').remove();
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
|
|
|
/*----------------------------------------------------*/
|
|
/* Booking Calendar POPOVER
|
|
/*----------------------------------------------------*/
|
|
$('.eb-room-booked').on('click', function(event) {
|
|
|
|
$(this).addClass("open").siblings().removeClass("open");
|
|
|
|
});
|
|
|
|
$('.eb-room-booked').on('mouseleave', function(event) {
|
|
|
|
if ( !$(this).hasClass('open') ) {
|
|
|
|
$('#eb-room-availability-popup').hide();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
$('body').on('click', function(event) {
|
|
|
|
if ( !$(event.target).closest('.eb-room-booked, #eb-room-availability-popup').length ) {
|
|
|
|
$('#eb-room-availability-popup').hide();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
eb_calendar_room_availability();
|
|
|
|
/*----------------------------------------------------*/
|
|
/* Media Upload
|
|
/*----------------------------------------------------*/
|
|
function media_upload(button_class) {
|
|
|
|
$('body').on('click', button_class, function (e) {
|
|
|
|
var upload_file_box = $(this);
|
|
|
|
// If the media frame already exists, reopen it.
|
|
if (frame) {
|
|
frame.open();
|
|
return;
|
|
}
|
|
|
|
// Create a new media frame
|
|
var frame = wp.media({
|
|
library: {
|
|
type: 'image'
|
|
},
|
|
multiple: false
|
|
});
|
|
|
|
frame.on('select', function () {
|
|
|
|
// Get media attachment details from the frame state
|
|
var attachment = frame.state().get('selection').first().toJSON();
|
|
|
|
upload_file_box.parent().find('.eb-upload-file-url').val(attachment.url);
|
|
upload_file_box.find('.eb-upload-file-remove').css('display', 'block');
|
|
upload_file_box.find('.eb-upload-file-text').css('display', 'none');
|
|
upload_file_box.find('.eb-upload-file-preview').attr('src', attachment.url).css('display', 'block');
|
|
|
|
});
|
|
|
|
frame.open();
|
|
return false;
|
|
});
|
|
|
|
}
|
|
|
|
media_upload('.eb-upload-file');
|
|
|
|
// Remove File
|
|
$('body').on('click', ".eb-upload-file-remove", function (e) {
|
|
|
|
var upload_file_remove = $(this);
|
|
upload_file_remove.css('display', 'none');
|
|
upload_file_remove.parent().find('.eb-upload-file-text').css('display', 'block');
|
|
upload_file_remove.parent().find('.eb-upload-file-url').val("");
|
|
upload_file_remove.parent().find('.eb-upload-file-preview').attr('src', "").css('display', 'none');
|
|
|
|
preventDefault(e);
|
|
|
|
});
|
|
|
|
|
|
// Clear the form after the submit
|
|
$('#submit').click(function () {
|
|
|
|
|
|
var upload_file_submit_button = $(this);
|
|
|
|
// Look for a div WordPress produces for an invalid form element
|
|
if ( !$('#addtag .form-invalid').length ) {
|
|
|
|
upload_file_submit_button.parent().parent().find('.eb-upload-file-preview').attr('src', "").css('display', 'none');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
})(jQuery);
|