templates/FrontCommun/SejourHotel/availability/vuejs-components/item-hotel.html.twig line 1

Open in your IDE?
  1. {% if app.request.get('product') =="appartement" %}
  2.     {% include checkCustomTemplate("SejourAppartement/availability/vuejs-components/item-hotel-content.html.twig") %}
  3. {% else %}
  4.     {% include checkCustomTemplate("SejourHotel/availability/vuejs-components/item-hotel-content.html.twig") %}
  5. {% endif %}
  6. {{ macro('sejour-hotel.availability').jsComponentSupplement() }}
  7. {% include checkCustomTemplate("SejourHotel/availability/vuejs-components/item-pension-room/#{resultView}.html.twig") %}
  8. <script>
  9.     let allHotels = {{ getAllHotels(null, false, app.request.get('product') == "appartement")|json_encode|raw }};
  10.     var globalState = Vue.observable({
  11.         minPrix2Loading: true
  12.     });
  13.     function showBtnReserver(StopReservation) {
  14.         if (StopReservation instanceof Array) {
  15.             if (StopReservation.filter(i => i).length > 0)
  16.                 return false
  17.         } else {
  18.             if (StopReservation)
  19.                 return false
  20.         }
  21.         return true
  22.     }
  23.     let itemHotel = {
  24.         template: "#item-hotel",
  25.         props: ['response', 'index_hotel'],
  26.         data: function () {
  27.             return {
  28.                 pricesLoaded: false,
  29.                 loadingPrices: false
  30.             }
  31.         },
  32.         computed: {
  33.             minPrix2Loading: function () {
  34.                 return globalState.minPrix2Loading
  35.             },
  36.             isInWishlist() {
  37.                 var idH = (this.response.Hotel.IdLocal !== undefined ? this.response.Hotel.IdLocal : this.response.Hotel.Id)
  38.                 return wishlist.includes(idH);
  39.             },
  40.             hotel: function () {
  41.                 if (this.response == null)
  42.                     return null
  43.                 {% if hotelSearchOnlyDetails|default('false') == 'true' %}
  44.                 if (!this.pricesLoaded) {
  45.                     {% if resultView == 'room-pension' %}
  46.                     this.response.Price = {BoardingByRooms: []};
  47.                     {% elseif resultView == 'pension-room' %}
  48.                     this.response.Price = {Boarding: []};
  49.                     {% elseif resultView == 'pension-combin-room' %}
  50.                     this.response.Price = {Boarding: []};
  51.                     {% elseif resultView == 'combin-room-pension' %}
  52.                     this.response.Price = {BoardingByRooms: [{Rooms: []}]};
  53.                     {% endif %}
  54.                 }
  55.                 {% endif %}
  56.                 var photo = this.response.Hotel.Image;
  57.                 if (photo == null || photo.indexOf('https://via.placeholder.com') > -1)
  58.                     photo = '{{ asset('assets-commun/images/img_placeholder.jpg') }}'
  59.                 var ville = this.response.Hotel.City.Name
  60.                 if (this.response.Hotel.City.Region !== undefined && this.response.Hotel.City.Region != '')
  61.                     ville += ', ' + this.response.Hotel.City.Region
  62.                 if (this.response.Hotel.City.Zone != '')
  63.                     ville += ', ' + this.response.Hotel.City.Zone
  64.                 {% if enabled_hotel_stay_worldwide == 'true' %}
  65.                 if (this.response.Hotel.Adress != '')
  66.                     ville += "\n" + this.response.Hotel.Adress
  67.                 {% endif %}
  68.                 var nombreEtoiles = parseInt(this.response.Hotel.Category.Star)
  69.                 {% if app.request.get('product') == "appartement" %}
  70.                 var idH = this.response.Hotel.Id
  71.                 {% else %}
  72.                 var idH = (this.response.Hotel.IdLocal !== undefined ? this.response.Hotel.IdLocal : this.response.Hotel.Id)
  73.                 {% endif %}
  74.                 var paramsRouteDetails = {
  75.                     // id: this.response.Hotel.SourceDetails.Hotel,
  76.                     id: idH,
  77.                     checkin: window.checkin_en,
  78.                     nuitees: window.nuitees,
  79.                     rooms: window.rooms,
  80.                     slug: this.response.Hotel.Slug,
  81.                     // source: this.response.Hotel.SourceDetails.Source,
  82.                     {% if app.request.get('product') == "appartement" %}
  83.                     source: this.response.Source,
  84.                     {% else %}
  85.                     source: (this.response.Hotel.IdLocal !== undefined || this.response.Source == 'local-2') ? 'all' : this.response.Source,
  86.                     {% endif %}
  87.                     // city: this.response.Hotel.SourceDetails.City
  88.                     city: this.response.Hotel.City.Id
  89.                 };
  90.                 let nbrChambresPromo = []
  91.                 {% if resultView == 'room-pension' %}
  92.                 this.response.Price.BoardingByRooms.map((pax, idx) => {
  93.                     pax.Rooms.map((room, idx) => {
  94.                         room.Boarding.map(arr => {
  95.                             if (!arr.surDemande && arr.BasePrice > arr.Price && (nbrChambresPromo[arr.IdRoom] === undefined || arr.disponible > nbrChambresPromo[arr.IdRoom]))
  96.                                 nbrChambresPromo[arr.IdRoom] = arr.disponible
  97.                         })
  98.                     });
  99.                 });
  100.                 {% elseif resultView == 'pension-room' %}
  101.                 this.response.Price.Boarding.map((arr, idx) => {
  102.                     arr.Pax.map((occp, idx) => {
  103.                         occp.Rooms.map(function (room) {
  104.                             if (!room.surDemande && room.BasePrice > room.Price && (nbrChambresPromo[room.Id] === undefined || room.disponible > nbrChambresPromo[room.Id]))
  105.                                 nbrChambresPromo[room.Id] = room.disponible
  106.                         })
  107.                     })
  108.                 });
  109.                 {% elseif resultView == 'pension-combin-room' %}
  110.                 this.response.Price.Boarding.map((arr, idx_arr) => {
  111.                     arr.Pax[0].Rooms.map((room, idx_room) => {
  112.                         if (!room.surDemande && room.BasePrice > room.Price && (nbrChambresPromo[room.Id] === undefined || room.disponible > nbrChambresPromo[room.Id]))
  113.                             nbrChambresPromo[room.Id] = room.Quantity
  114.                     })
  115.                 });
  116.                 {% elseif resultView == 'combin-room-pension' %}
  117.                 this.response.Price.BoardingByRooms[0].Rooms.map((room, idx_room) => {
  118.                     room.Boarding.map((arr, idx_arr) => {
  119.                         if (!arr.surDemande && arr.BasePrice > arr.Price && (nbrChambresPromo[arr.IdRoom] === undefined || arr.disponible > nbrChambresPromo[arr.IdRoom]))
  120.                             nbrChambresPromo[arr.IdRoom] = arr.Quantity
  121.                     })
  122.                 });
  123.                 {% endif %}
  124.                 let allEtiquettes = [];
  125.                 if (this.response.etiquettes !== undefined)
  126.                     Object.values(this.response.etiquettes).map(etq => {
  127.                         etq.nature = 'etiquette'
  128.                         if (allEtiquettes.findIndex(e => e.libelle === etq.libelle) == -1) allEtiquettes.push(etq)
  129.                     })
  130.                 if (this.response.etiquettesSaison !== undefined)
  131.                     Object.values(this.response.etiquettesSaison).map(etq => {
  132.                         etq.nature = 'etiquette-saison'
  133.                         if (allEtiquettes.findIndex(e => e.libelle === etq.libelle) == -1) allEtiquettes.push(etq)
  134.                     })
  135.                 if (this.response.etiquettesEmplacement !== undefined)
  136.                     Object.values(this.response.etiquettesEmplacement).map(etq => {
  137.                         etq.nature = 'etiquette-emplacement'
  138.                         if (allEtiquettes.findIndex(e => e.libelle === etq.libelle) == -1) allEtiquettes.push(etq)
  139.                     })
  140.                 if (wishlist !== undefined)
  141.                     return {
  142.                         details: (details = allHotels.filter(h => h.id == idH)).length > 0 ? details[0] : null,
  143.                         photo: photo,
  144.                         tripAdvisor: this.response.Hotel.TripAdvisor,
  145.                         Price: this.response.Price,
  146.                         StopSales: this.response.StopSales !== undefined ? [this.response.StopSales.Title] : [],
  147.                         description: this.response.Hotel.ShortDescription,
  148.                         descriptionHotel: this.response.Hotel.HotelDescription !== undefined ? this.response.Hotel.HotelDescription : null,
  149.                         recommander: this.response.Recommended,
  150.                         minPrix: parseFloat(this.response.min_arrangement.min_prices).formatMoney(3, ',', ' '),
  151.                         tags: this.response.Hotel.tags,
  152.                         token: this.response.Token !== undefined ? this.response.Token : null,
  153.                         amenagements: this.response.Hotel.Facilities,
  154.                         etoile: nombreEtoiles > 0 ? nombreEtoiles : this.response.Hotel.Category.Title,
  155.                         id: idH,
  156.                         idville: this.response.Hotel.City.Id,
  157.                         nom: this.response.Hotel.Name,
  158.                         ville: ville,
  159.                         autresInformations: this.response.Hotel.OtherDetails !== undefined ? this.response.Hotel.OtherDetails : {},
  160.                         paramsRouteDetails: paramsRouteDetails,
  161.                         nbrChambresPromo: Object.values(nbrChambresPromo).reduce((accumulator, currentValue) => {
  162.                             return accumulator + currentValue
  163.                         }, 0),
  164.                         Recap: {
  165.                             checkin: window.checkin,
  166.                             nuitees: window.nuitees,
  167.                             occupations: window.rooms
  168.                         },
  169.                         {% if app.request.get('product') == "appartement" %}
  170.                         urlDetails: Routing.generate('details_appartement', paramsRouteDetails),
  171.                         {% else %}
  172.                         urlDetails: Routing.generate('details_hotel', paramsRouteDetails),
  173.                         {% endif %}
  174.                         minBasePrix: parseFloat(this.response.min_arrangement.price).formatMoney(3, ',', ' '),
  175.                         minArrangement: this.response.min_arrangement.libelle,
  176.                         earlyBooking: this.response.etiquettes ? Object.values(this.response.etiquettes).filter(etq => {
  177.                             return etq.codeType === 6
  178.                             //return etq.debutReservation
  179.                         }) : [],
  180.                         etiquettesEmplacement: this.response.etiquettesEmplacement ? Object.values(this.response.etiquettesEmplacement).map((etq, idx) => {
  181.                             if (etq.age !== undefined)
  182.                                 etq.slug = 'gratuite-enfant'
  183.                             else if (etq.promotion !== undefined)
  184.                                 etq.slug = 'promotion'
  185.                             else
  186.                                 etq.slug = slugify(etq.libelle)
  187.                             return etq;
  188.                         }) : [],
  189.                         etiquettes: this.response.etiquettes ? Object.values(this.response.etiquettes).sort((a, b) => {
  190.                             return a.ordre > b.ordre ? 1 : -1
  191.                         }).map((etq, idx) => {
  192.                             if (etq.age !== undefined)
  193.                                 etq.slug = 'gratuite-enfant'
  194.                             else if (etq.promotion !== undefined)
  195.                                 etq.slug = 'promotion'
  196.                             else
  197.                                 etq.slug = slugify(etq.libelle)
  198.                             etq.top = idx * 30 + 5
  199.                             return etq;
  200.                         }) : [],
  201.                         etiquettesSaison: this.response.etiquettesSaison ? Object.values(this.response.etiquettesSaison).sort((a, b) => {
  202.                             return a.ordre > b.ordre ? 1 : -1
  203.                         }).map((etq, idx) => {
  204.                             if (etq.age !== undefined)
  205.                                 etq.slug = 'gratuite-enfant'
  206.                             else if (etq.promotion !== undefined)
  207.                                 etq.slug = 'promotion'
  208.                             else
  209.                                 etq.slug = slugify(etq.libelle)
  210.                             return etq;
  211.                         }) : [],
  212.                         allEtiquettes: allEtiquettes,
  213.                         retrocession: this.response.retrocession,
  214.                     }
  215.             },
  216.             minPrix2() {
  217.                 if (this.response.min_arrangement2 !== undefined)
  218.                     return {
  219.                         arrangement: this.response.min_arrangement2.libelle,
  220.                         chambre: this.response.min_arrangement2.chambre.libelle,
  221.                         surDemande: this.response.min_arrangement2.chambre.surDemande,
  222.                         msgSurDemande: this.response.min_arrangement2.chambre.msgSurDemande,
  223.                         prix: parseFloat(this.response.min_arrangement2.min_prices / window.nuitees / 2).formatMoney(3, ',', ' '),
  224.                         base_prix: parseFloat(this.response.min_arrangement2.price / window.nuitees / 2).formatMoney(3, ',', ' ')
  225.                     }
  226.                 return {
  227.                     arrangement: '',
  228.                     chambre: '',
  229.                     surDemande: false,
  230.                     disponible: 0,
  231.                     prix: 0
  232.                 }
  233.             }
  234.         },
  235.         mounted() {
  236.             var el = $(this.$refs.countdown)
  237.             var countDownDate = new Date(el.data('time')).getTime();
  238.             var x = setInterval(function () {
  239.                 var now = new Date().getTime();
  240.                 var distance = countDownDate - now;
  241.                 var days = Math.floor(distance / (1000 * 60 * 60 * 24));
  242.                 var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
  243.                 var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
  244.                 var seconds = Math.floor((distance % (1000 * 60)) / 1000);
  245.                 el.html(days + "j " + hours + "h " + minutes + "m " + seconds + "s ");
  246.                 if (distance < 0) {
  247.                     clearInterval(x);
  248.                     el.html("EXPIRED");
  249.                 }
  250.             }, 1000);
  251.         },
  252.         methods: {
  253.             loadPrices(event) {
  254.                 {% if hotelSearchOnlyDetails|default('false') == 'true' %}
  255.                 if (this.pricesLoaded || this.loadingPrices) {
  256.                     $(`#tarifs-hotel-${this.index_hotel}`).collapse('toggle');
  257.                     return;
  258.                 }
  259.                 this.loadingPrices = true;
  260.                 // Ajouter l'animation de loading au bouton
  261.                 let loadBtn = $(event.target).closest('.btn');
  262.                 let originalHtml = loadBtn.html();
  263.                 loadBtn.prop('disabled', true).addClass('loading');
  264.                 loadBtn.html('<span class="fa fa-spinner fa-spin" role="status" aria-hidden="true"></span> Chargement...');
  265.                 // Build search parameters from cache, only updating Hotel
  266.                 let searchParams = window.lastHotelSearchParams;
  267.                 delete searchParams.SearchDetails.OnlyHotelDetails;
  268.                 searchParams.SearchDetails.OnlyPrices = true;
  269.                 searchParams.SearchDetails.Filters.Source = (this.response.Hotel.IdLocal !== undefined || this.response.Source == 'local-2') ? 'all' : this.response.Source;
  270.                 if (searchParams.SearchDetails.Filters.Source != 'all') {
  271.                     delete searchParams.SearchDetails.BookingDetails.City;
  272.                     searchParams.SearchDetails.BookingDetails.XMLCity = this.response.Hotel.City.Id;
  273.                 }
  274.                 searchParams.SearchDetails.BookingDetails.Hotel = this.response.Hotel.IdLocal !== undefined ? this.response.Hotel.IdLocal : this.response.Hotel.Id;
  275.                 // Make AJAX call to get prices
  276.                 axios.get("{{ path('sejour_hotel_ajax_availability') }}", {
  277.                     params: {
  278.                         HotelSearch: utf8_to_b64(JSON.stringify(searchParams))
  279.                     }
  280.                 }).then(response => {
  281.                     if (response.data && response.data.HotelSearch && response.data.HotelSearch[0]) {
  282.                         this.pricesLoaded = true;
  283.                         // Update the Price in the response using Vue.set for reactivity
  284.                         this.$set(this.response, 'Price', response.data.HotelSearch[0].Price);
  285.                         this.$set(this.response, 'Token', response.data.HotelSearch[0].Token);
  286.                     }
  287.                     this.loadingPrices = false;
  288.                     // Retirer l'animation de loading
  289.                     loadBtn.prop('disabled', false).removeClass('loading');
  290.                     loadBtn.html(originalHtml);
  291.                     // Trigger collapse after prices are loaded
  292.                     $(`#tarifs-hotel-${this.index_hotel}`).collapse('show');
  293.                 }).catch(error => {
  294.                     console.error('Error loading prices:', error);
  295.                     this.loadingPrices = false;
  296.                     // Retirer l'animation de loading en cas d'erreur
  297.                     loadBtn.prop('disabled', false).removeClass('loading');
  298.                     loadBtn.html(originalHtml);
  299.                     // Still show collapse even if error
  300.                     $(`#tarifs-hotel-${this.index_hotel}`).collapse('show');
  301.                 });
  302.                 {% else %}
  303.                 // If HOTEL_SEARCH_ONLY_DETAILS is not enabled, just toggle collapse
  304.                 $(`#tarifs-hotel-${this.index_hotel}`).collapse('toggle');
  305.                 {% endif %}
  306.             }
  307.         },
  308.         components: {itemPensionRoom}
  309.     }
  310.     $(document).ready(function () {
  311.         $(".invisible-content").hide();
  312.         $(document).on('click', '.btn-more', function () {
  313.             var moreLessButton = $(".invisible-content").is(':visible') ? ' Lire la suite ' : 'Reduire';
  314.             $(this).text(moreLessButton);
  315.             $(this).parent('.large-content').find(".invisible-content").toggle();
  316.             $(this).parent('.large-content').find(".visible-content").toggle();
  317.         });
  318.     });
  319. </script>