Hotel Raxa - Advanced Booking System Implementation
🏨 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>
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
/*! elementor - v3.24.0 - 15-10-2024 */
|
||||
"use strict";
|
||||
(self["webpackChunkelementor"] = self["webpackChunkelementor"] || []).push([["video"],{
|
||||
|
||||
/***/ "../assets/dev/js/frontend/handlers/video.js":
|
||||
/*!***************************************************!*\
|
||||
!*** ../assets/dev/js/frontend/handlers/video.js ***!
|
||||
\***************************************************/
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
|
||||
|
||||
Object.defineProperty(exports, "__esModule", ({
|
||||
value: true
|
||||
}));
|
||||
exports["default"] = void 0;
|
||||
class Video extends elementorModules.frontend.handlers.Base {
|
||||
getDefaultSettings() {
|
||||
return {
|
||||
selectors: {
|
||||
imageOverlay: '.elementor-custom-embed-image-overlay',
|
||||
video: '.elementor-video',
|
||||
videoIframe: '.elementor-video-iframe',
|
||||
playIcon: '.elementor-custom-embed-play'
|
||||
}
|
||||
};
|
||||
}
|
||||
getDefaultElements() {
|
||||
const selectors = this.getSettings('selectors');
|
||||
return {
|
||||
$imageOverlay: this.$element.find(selectors.imageOverlay),
|
||||
$video: this.$element.find(selectors.video),
|
||||
$videoIframe: this.$element.find(selectors.videoIframe),
|
||||
$playIcon: this.$element.find(selectors.playIcon)
|
||||
};
|
||||
}
|
||||
handleVideo() {
|
||||
if (this.getElementSettings('lightbox')) {
|
||||
return;
|
||||
}
|
||||
if ('youtube' === this.getElementSettings('video_type')) {
|
||||
this.apiProvider.onApiReady(apiObject => {
|
||||
this.elements.$imageOverlay.remove();
|
||||
this.prepareYTVideo(apiObject, true);
|
||||
});
|
||||
} else {
|
||||
this.elements.$imageOverlay.remove();
|
||||
this.playVideo();
|
||||
}
|
||||
}
|
||||
playVideo() {
|
||||
if (this.elements.$video.length) {
|
||||
// This.youtubePlayer exists only for YouTube videos, and its play function is different.
|
||||
if (this.youtubePlayer) {
|
||||
this.youtubePlayer.playVideo();
|
||||
} else {
|
||||
this.elements.$video[0].play();
|
||||
}
|
||||
return;
|
||||
}
|
||||
const $videoIframe = this.elements.$videoIframe,
|
||||
lazyLoad = $videoIframe.data('lazy-load');
|
||||
if (lazyLoad) {
|
||||
$videoIframe.attr('src', lazyLoad);
|
||||
}
|
||||
if (this.getElementSettings('autoplay')) {
|
||||
$videoIframe.attr('allow', 'autoplay');
|
||||
$videoIframe[0].src = this.apiProvider.getAutoplayURL($videoIframe[0].src);
|
||||
}
|
||||
}
|
||||
async animateVideo() {
|
||||
const lightbox = await elementorFrontend.utils.lightbox;
|
||||
lightbox.setEntranceAnimation(this.getCurrentDeviceSetting('lightbox_content_animation'));
|
||||
}
|
||||
async hideLightbox() {
|
||||
const lightbox = await elementorFrontend.utils.lightbox;
|
||||
lightbox.getModal().hide();
|
||||
}
|
||||
prepareYTVideo(YT, onOverlayClick) {
|
||||
const elementSettings = this.getElementSettings(),
|
||||
playerOptions = {
|
||||
videoId: this.videoID,
|
||||
events: {
|
||||
onReady: () => {
|
||||
if (elementSettings.mute) {
|
||||
this.youtubePlayer.mute();
|
||||
}
|
||||
if (elementSettings.autoplay || onOverlayClick) {
|
||||
this.youtubePlayer.playVideo();
|
||||
}
|
||||
},
|
||||
onStateChange: event => {
|
||||
if (event.data === YT.PlayerState.ENDED && elementSettings.loop) {
|
||||
this.youtubePlayer.seekTo(elementSettings.start || 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
playerVars: {
|
||||
controls: elementSettings.controls ? 1 : 0,
|
||||
rel: elementSettings.rel ? 1 : 0,
|
||||
playsinline: elementSettings.play_on_mobile ? 1 : 0,
|
||||
modestbranding: elementSettings.modestbranding ? 1 : 0,
|
||||
autoplay: elementSettings.autoplay ? 1 : 0,
|
||||
start: elementSettings.start,
|
||||
end: elementSettings.end
|
||||
}
|
||||
};
|
||||
|
||||
// To handle CORS issues, when the default host is changed, the origin parameter has to be set.
|
||||
if (elementSettings.yt_privacy) {
|
||||
playerOptions.host = 'https://www.youtube-nocookie.com';
|
||||
playerOptions.origin = window.location.hostname;
|
||||
}
|
||||
this.youtubePlayer = new YT.Player(this.elements.$video[0], playerOptions);
|
||||
}
|
||||
bindEvents() {
|
||||
this.elements.$imageOverlay.on('click', this.handleVideo.bind(this));
|
||||
this.elements.$playIcon.on('keydown', event => {
|
||||
const playKeys = [13,
|
||||
// Enter key.
|
||||
32 // Space bar key.
|
||||
];
|
||||
|
||||
if (playKeys.includes(event.keyCode)) {
|
||||
this.handleVideo();
|
||||
}
|
||||
});
|
||||
}
|
||||
onInit() {
|
||||
super.onInit();
|
||||
const elementSettings = this.getElementSettings();
|
||||
if (elementorFrontend.utils[elementSettings.video_type]) {
|
||||
this.apiProvider = elementorFrontend.utils[elementSettings.video_type];
|
||||
} else {
|
||||
this.apiProvider = elementorFrontend.utils.baseVideoLoader;
|
||||
}
|
||||
if ('youtube' !== elementSettings.video_type) {
|
||||
// Currently the only API integration in the Video widget is for the YT API
|
||||
return;
|
||||
}
|
||||
this.videoID = this.apiProvider.getVideoIDFromURL(elementSettings.youtube_url);
|
||||
|
||||
// If there is an image overlay, the YouTube video prep method will be triggered on click
|
||||
if (!this.videoID) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the user is using an image overlay, loading the API happens on overlay click instead of on init.
|
||||
if (elementSettings.show_image_overlay && elementSettings.image_overlay.url) {
|
||||
return;
|
||||
}
|
||||
if (elementSettings.lazy_load) {
|
||||
this.intersectionObserver = elementorModules.utils.Scroll.scrollObserver({
|
||||
callback: event => {
|
||||
if (event.isInViewport) {
|
||||
this.intersectionObserver.unobserve(this.elements.$video.parent()[0]);
|
||||
this.apiProvider.onApiReady(apiObject => this.prepareYTVideo(apiObject));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// We observe the parent, since the video container has a height of 0.
|
||||
this.intersectionObserver.observe(this.elements.$video.parent()[0]);
|
||||
return;
|
||||
}
|
||||
this.apiProvider.onApiReady(apiObject => this.prepareYTVideo(apiObject));
|
||||
}
|
||||
onElementChange(propertyName) {
|
||||
if (0 === propertyName.indexOf('lightbox_content_animation')) {
|
||||
this.animateVideo();
|
||||
return;
|
||||
}
|
||||
const isLightBoxEnabled = this.getElementSettings('lightbox');
|
||||
if ('lightbox' === propertyName && !isLightBoxEnabled) {
|
||||
this.hideLightbox();
|
||||
}
|
||||
}
|
||||
}
|
||||
exports["default"] = Video;
|
||||
|
||||
/***/ })
|
||||
|
||||
}]);
|
||||
//# sourceMappingURL=video.817bd6a65a1542503aac.bundle.js.map
|
||||
Reference in New Issue
Block a user