templates/FrontCommun/vuejs-advanced-search.html.twig line 1

Open in your IDE?
  1. {% set nuitees = app.request.get('nuitees',1) %}
  2. {% set checkin = app.request.get('checkin',"now"|date('Y-m-d')) %}
  3. {% set rooms = roomsToArray(app.request.get('rooms','2')) %}
  4. {% if searchPackageVoyages is defined %}
  5.     {% set produit = "" %}
  6.     {% set resultView = "" %}
  7.     {% set onlySearchCity = 0 %}
  8.     {% set rooms = roomsToArray(app.request.get('occupations','2')) %}
  9.     {% set checkin = app.request.get('debut',"now"|date('Y-m-d')) %}
  10.     {% set checkout = app.request.get('fin',"now"|date_modify("+1 day")|date("Y-m-d")) %}
  11.     {% set difference = date(checkout).diff(date(checkin)) %}
  12.     {% set nuitees = difference.days %}
  13. {% endif %}
  14. {% if configAffichage is not defined %}
  15.     {% set configAffichage = getConfigAffichage() %}
  16. {% endif %}
  17. {% if configAffichage.HOTEL["MODELE_SELECT_VILLE_HOTEL#{is_mobile() ? '_MOBILE' : ''}"] == 'jsuites' %}
  18.     <script src="{{ asset('assets-commun/js/jsuites.js') }}"></script>
  19. {% elseif configAffichage.HOTEL["MODELE_SELECT_VILLE_HOTEL#{is_mobile() ? '_MOBILE' : ''}"] == 'typeahead' %}
  20.     {#{% if is_mobile() %}
  21.         <script type="text/javascript" src="{{ asset('assets-commun/js/bootstrap3-typeahead.min.js') }}"></script>
  22.     {% else %}#}
  23.     <script src="{{ asset('assets-commun/jquery-typeahead-2.11.0/dist/jquery.typeahead.min.js') }}"></script>
  24.     {#{% endif %}#}
  25. {% endif %}
  26. {% if app.request.server.get('FORCE_SEARCH_HOTEL_ONLY_BY_CITY') %}
  27.     {% set onlySearchCity = 1 %}
  28. {% endif %}
  29. {% if destination is defined %}
  30.     {% set villes_hotels = [] %}
  31.     {% set selected_destination = destination %}
  32. {% else %}
  33.     {% set villes_hotels = getVillesHotels(produit==''?'SHT':produit,onlySearchCity, _destination is defined ? _destination : '', configAffichage.HOTEL["MODELE_SELECT_VILLE_HOTEL#{is_mobile() ? '_MOBILE' : ''}"] , appartement is defined and appartement) %}
  34.     {% set selected_destination = villes_hotels.selected_destination %}
  35.     {% set villes_hotels = villes_hotels.destinations %}
  36. {% endif %}
  37. <script>
  38.     var vjsAdvancedSearch{{ produit }} = new Vue({
  39.         el: '#vjs-advanced-search{{ produit!=''?'-'~produit|lower:'' }}',
  40.         data: {
  41.             module: "hotel",
  42.             rooms:{{ rooms|json_encode|raw }},
  43.             checkin_fr: '{{ checkin|date('d/m/Y') }}',
  44.             checkout_fr: '{{ checkin|date_modify("+" ~ nuitees ~ " day")|date('d/m/Y') }}',
  45.             checkin_en: '{{ checkin|date('Y-m-d') }}',
  46.             checkout_en: '{{ checkin|date_modify("+" ~ nuitees ~ " day")|date('Y-m-d') }}',
  47.             nuitees: {{ nuitees }},
  48.             {% if app.request.get('_route') == 'sejour_hotel_availability_landing_page' %}
  49.             pays: 'multi',
  50.             ville: 'destination',
  51.             hotel: '{{ hotel_to_ids(app.request.get('hotel')) }}',
  52.             destination: 'v-tous',
  53.             lbl_destination: 'multi destination',
  54.             {% else %}
  55.             pays: '{{ (selected_destination and selected_destination.pays is defined) ? selected_destination.pays : 'all' }}',
  56.             ville: '{{ (selected_destination and selected_destination.ville is defined) ? selected_destination.ville : 'all' }}',
  57.             hotel: '{{ (selected_destination and selected_destination.hotel is defined) ? selected_destination.hotel : 'tous' }}',
  58.             destination: '{{ selected_destination ? selected_destination.type ~ '-' ~ selected_destination.id : 'all' }}',
  59.             lbl_destination: '{{ selected_destination ? selected_destination.name : '' }}',
  60.             {% endif %}
  61.             occupations: '',
  62.             recap_occupations: '',
  63.             recap_occupationsAppartement: '',
  64.             _recap_occupations: '',
  65.         },
  66.         methods: {
  67.             callAvailabilityVoyages() {
  68.                 var routeAvail = Routing.generate('front_package_liste', {
  69.                     ...{
  70.                         debut: this.checkin_en,
  71.                         fin: this.checkout_en,
  72.                         occupations: this.occupations
  73.                     }, ...{{ app.request.query.all|json_encode|raw }}
  74.                 });
  75.                 window.location = routeAvail;
  76.             },
  77.             callAvailability() {
  78.                 this.callAvailabilityVoyages();
  79.             },
  80.             callAvailability{{ produit }}() {
  81.               if ($('#form-search input#search-type').val() == 'voyages' && '{{ produit }}' === '') {
  82.     var routeAvail = Routing.generate('front_package_liste', {
  83.         ...{
  84.             debut: this.checkin_en,
  85.             fin: this.checkout_en,
  86.             occupations: this.occupations
  87.         }, ...{{ app.request.query.all|json_encode|raw }}
  88.     });
  89.     window.location = routeAvail;
  90. } else {
  91.     if (($('.typeahead_destination{{ produit }}').val() == '') || this.destination == "all") {
  92.         viewAlert('Veuillez choisir une ville ou un hôtel', 'danger')
  93.         return
  94.     }
  95.                     {% if product is defined and  product=="appartement" %}
  96.                     {% set route_avail_hotel = app.request.server.get('ROUTE_AVAIL_HOTEL','sejour_appartement_availability') %}
  97.                     {% else %}
  98.                     {% set route_avail_hotel = app.request.server.get('ROUTE_AVAIL_HOTEL','sejour_hotel_availability') %}
  99.                     {% endif %}
  100.                     {% if route_avail_hotel == 'details_hotel' or route_avail_hotel == 'details_appartement' %}
  101.                     var routeAvail = Routing.generate('{{ route_avail_hotel }}', {
  102.                         ...{
  103.                             checkin: this.checkin_en,
  104.                             nuitees: this.nuitees,
  105.                             rooms: this.occupations,
  106.                             city: this.ville,
  107.                             slug: this.hotel,
  108.                             id: this.destination.slice(2),
  109.                             source: "{{ app.request.get('source','all') }}"
  110.                         }, ...{{ app.request.server.get('PARAMS_ROUTE_AVAIL_HOTEL','{}')|raw }}
  111.                     })
  112.                     {% else %}
  113.                     var routeAvail = Routing.generate('{{ route_avail_hotel }}', {
  114.                         ...{
  115.                             checkin: this.checkin_en,
  116.                             nuitees: this.nuitees,
  117.                             rooms: this.occupations,
  118.                             pays: this.pays,
  119.                             ville: this.ville,
  120.                             hotel: this.hotel,
  121.                             destination: this.destination,
  122.                             source: "{{ app.request.get('source','all') }}",
  123.                             hotelMonde: "{{ enabled_hotel_stay_worldwide == 'true' ? 1 : app.request.get('hotelMonde','0') }}"
  124.                         }, ...{{ app.request.query.all|json_encode|raw }}
  125.                     })
  126.                     {% endif %}
  127.                 }
  128.                 $('#mobile-destination').html(`<i class="fa fa-${this.destination.split('-')[0] == 'v' ? 'map-marker-alt' : 'hotel'} fa-1" aria-hidden="true" style=" margin-left: 1px;"></i> ` + this.lbl_destination);
  129.                 $('#mobile-sejour').html(`Du ${this.checkin_fr.substr(0, 5)} au ${this.checkout_fr.substr(0, 5)} soit ${this.nuitees == 1 ? 'une' : this.nuitees} nuitée${this.nuitees > 1 ? 's' : ''}`);
  130.                 $('#mobile-occupations').html(this.recap_occupations);
  131.                 {% if app.request.get('_route') in ['accueil'] %}
  132.                 window.location = routeAvail
  133.                 {% else %}
  134.                 {% if app.request.get('_route') == route_avail_hotel %}
  135.                 window.history.pushState('data', 'title', routeAvail);
  136.                 {% endif %}
  137.                 vjsListHotels.hotels = []
  138.                 var hotel_loading = this.destination.split('-')[0] == 'v' ? vjsListHotels.paginate_per : 1
  139.                 vjsListHotels.hotel_loading = hotel_loading
  140.                 $('#faq').html("")
  141.                 $('#description-ville').html("")
  142.                 $('#read-more-desc-ville').hide()
  143.                 if (typeof vjsSearchNomsHotels !== 'undefined') {
  144.                     vjsSearchNomsHotels.hotel_loading = hotel_loading
  145.                     vjsSearchNomsHotels.visible = true
  146.                 }
  147.                 if (typeof vjsSortResult !== 'undefined') {
  148.                     vjsSortResult.hotel_loading = hotel_loading
  149.                     vjsSortResult.visible = true
  150.                 }
  151.                 if (typeof vjsRecapSearch !== 'undefined')
  152.                     vjsRecapSearch.hotel_loading = hotel_loading
  153.                 if (typeof vjsRefineResult !== 'undefined') {
  154.                     vjsRefineResult.hotel_loading = hotel_loading
  155.                     vjsRefineResult.visible = true
  156.                 }
  157.                 if (typeof vjsMinPrice !== 'undefined')
  158.                     vjsMinPrice.min_arrangement = []
  159.                 if (typeof vjsMinPrice2 !== 'undefined')
  160.                     vjsMinPrice2.min_arrangement = []
  161.                 if (typeof vjsEtiquette !== 'undefined') {
  162.                     vjsEtiquette.etiquettes = []
  163.                     vjsEtiquette.etiquettesEmplacement = []
  164.                     vjsEtiquette.etiquettesSaison = []
  165.                 }
  166.                 var ajaxTime = new Date().getTime();
  167.                 window.checkin = this.checkin_en
  168.                 window.dispatchEvent(new Event("checkinUpdated")); // Émission de l'événement "checkinUpdated"
  169.                 window.nuitees = this.nuitees
  170.                 window.dispatchEvent(new Event("nuiteesUpdated")); // Émission de l'événement "nuiteesUpdated"
  171.                 window.rooms = this.occupations
  172.                 window.array_rooms = this.rooms
  173.                 vjsListHotels.nbr_room = this.rooms.length
  174.                 vjsListHotels.recap = {
  175.                     ville: this.ville,
  176.                     hotel: this.hotel,
  177.                     checkin: this.checkin_fr,
  178.                     checkout: this.checkout_fr,
  179.                     destination: this.lbl_destination,
  180.                     nuitees: this.nuitees,
  181.                     nbrRoom: window.nbrRoom,
  182.                     nbrAdult: window.nbrAdult,
  183.                     nbrChild: window.nbrChild,
  184.                     occupations: this.recap_occupations
  185.                 }
  186.                 if (typeof vjsRecapResult !== 'undefined')
  187.                     vjsRecapResult.result = null
  188.                 if (typeof vjsSortResult !== 'undefined')
  189.                     vjsSortResult.destination = this.lbl_destination
  190.                 if (typeof vjsRefineResult !== 'undefined') {
  191.                     vjsRefineResult.checkin = this.checkin_fr
  192.                     vjsRefineResult.checkout = this.checkout_fr
  193.                     vjsRefineResult.destination = this.lbl_destination
  194.                     vjsRefineResult.occupations = this.recap_occupations
  195.                     vjsRefineResult.nuitees = this.nuitees
  196.                     vjsRefineResult.result = null
  197.                 }
  198.                 var BookingDetails = {
  199.                     "CheckIn": this.checkin_en,
  200.                     "CheckOut": this.checkout_en
  201.                 }
  202.                 if (this.destination.split('-')[0] == 'v')
  203.                     BookingDetails['City'] = this.destination.split('-')[1]
  204.                 else
  205.                     BookingDetails['Hotel'] = this.destination.split('-')[1]
  206.                 {% if app.request.get('_route') == 'sejour_hotel_availability_landing_page' %}
  207.                 BookingDetails['Hotels'] = "{{ hotel_to_ids(app.request.get('hotel')) }}".split('-')
  208.                 {% endif %}
  209.                 {% if app.request.get('source','~') != '~' and app.request.get('city','~') != '~' %}
  210.                 BookingDetails['XMLCity'] = '{{ app.request.get('city') }}'
  211.                 {% endif %}
  212.                 window.dispatchEvent(new Event("callRequestAvailHotel"));
  213.                 // Store search parameters in cache for later use
  214.                 window.lastHotelSearchParams = {
  215.                     SearchDetails: {
  216.                         BookingDetails: BookingDetails,
  217.                         Rooms: this.rooms,
  218.                         GroupingHotel: true,
  219.                         Product: "{{ app.request.get('product','hotel') }}",
  220.                         {% if app.request.get('_route') == 'front_evenement_details' %}
  221.                         Event: true,
  222.                         {% endif %}
  223.                         {% if route_avail_hotel == 'sejour_hotel_availability' and hotelSearchOnlyDetails|default('false') == 'true' %}
  224.                         OnlyHotelDetails: true,
  225.                         {% endif %}
  226.                         CombinationRooms: {{ resultView in ['pension-combin-room','combin-room-pension'] ? 'true' : 'false' }},
  227.                         BoardingByRooms: {{ resultView in ['room-pension','combin-room-pension'] ? 'true' : 'false' }},
  228.                         Filters: {
  229.                             Source: "{{ app.request.get('source','all')=='~'?'all':app.request.get('source','all') }}"
  230.                         }
  231.                     }
  232.                 };
  233.                 axios
  234.                     .get('{{ path('sejour_hotel_ajax_availability') }}',
  235.                         {
  236.                             params: {
  237.                                 HotelSearch: utf8_to_b64(JSON.stringify(window.lastHotelSearchParams))
  238.                             }
  239.                         })
  240.                     .then(response => {
  241.                             vjsListHotels.hotel_loading = 0
  242.                             if (typeof vjsSearchNomsHotels !== 'undefined') {
  243.                                 vjsSearchNomsHotels.hotel_loading = 0
  244.                                 vjsSearchNomsHotels.filtre_noms.length = 0
  245.                             }
  246.                             if (typeof vjsSortResult !== 'undefined') {
  247.                                 vjsSortResult.hotel_loading = 0
  248.                                 vjsSortResult.trie = '{{ configAffichage.HOTEL.TRI_RESULTAT }}'
  249.                             }
  250.                             if (typeof vjsRecapSearch !== 'undefined')
  251.                                 vjsRecapSearch.hotel_loading = 0
  252.                             if (typeof vjsRefineResult !== 'undefined') {
  253.                                 vjsRefineResult.hotel_loading = 0
  254.                                 vjsRefineResult.filtre_etoiles.length = 0
  255.                                 vjsRefineResult.filtre_arrangements.length = 0
  256.                                 vjsRefineResult.filtre_zones.length = 0
  257.                                 vjsRefineResult.filtre_tags.length = 0
  258.                                 vjsRefineResult.filtre_chambres.length = 0
  259.                                 vjsRefineResult.collect_chambre = 1
  260.                             }
  261.                             if (response.data.Erreur !== undefined)
  262.                                 viewAlert(response.data.Erreur, 'danger')
  263.                             else if (response.data.Error !== undefined) {
  264.                                 viewAlert('Erreur', 'danger')
  265.                                 console.error(response.data.Error)
  266.                             } else {
  267.                                 this.fetchAllHotelsPaginated(response.data)
  268.                                 var hotels = response.data.HotelSearch
  269.                                 var filtres = response.data.DataFiltre
  270.                                 var duration = response.data.Timing.Duration
  271.                                 if (typeof response.data.AutreInfos !== 'undefined') {
  272.                                     let advancedSearchInstance = this
  273.                                     if (typeof window !== 'undefined' && window['{{ 'vjsAdvancedSearch' ~ produit }}'] !== undefined) {
  274.                                         advancedSearchInstance = window['{{ 'vjsAdvancedSearch' ~ produit }}']
  275.                                     }
  276.                                     const destinationValue = (advancedSearchInstance.destination || '').toString()
  277.                                     const destinationParts = destinationValue.split('-')
  278.                                     const isVilleSelection = destinationValue.startsWith('v-') && destinationParts[1] && destinationParts[1] !== 'tous'
  279.                                     const isDetailsRoute = {{ app.request.get('_route') in ['details_hotel', 'details_hotel_custom', 'details_appartement', 'details_appartement_custom'] ? 'true' : 'false' }}
  280.                                     const descriptionVille = response.data.AutreInfos.Description
  281.                                     const hasDescriptionVille = isVilleSelection && (
  282.                                         (typeof descriptionVille === 'string' && descriptionVille.trim() !== '') ||
  283.                                         (typeof descriptionVille !== 'string' && descriptionVille)
  284.                                     )
  285.                                     if (hasDescriptionVille) {
  286.                                         $('#description-ville').html(descriptionVille)
  287.                                         $('#read-more-desc-ville').show()
  288.                                     } else {
  289.                                         $('#description-ville').html('')
  290.                                         $('#read-more-desc-ville').hide()
  291.                                     }
  292.                                     const hasFAQ = Array.isArray(response.data.AutreInfos.FAQ) && response.data.AutreInfos.FAQ.length > 0
  293.                                     const shouldShowFAQ = hasFAQ && (isVilleSelection || isDetailsRoute)
  294.                                     if (shouldShowFAQ) {
  295.                                         let lignesFAQ = response.data.AutreInfos.FAQ.map((item, i) => `{{ macro('sejour-hotel.availability').ligneFAQ() }}`).join('')
  296.                                         $('#faq').html(`{{ macro('sejour-hotel.availability').templateFAQ() }}`)
  297.                                     } else {
  298.                                         $('#faq').html('')
  299.                                     }
  300.                                 }
  301.                                 vjsListHotels.hotels = hotels;
  302.                                 if (typeof vjsRefineResult !== 'undefined') {
  303.                                     vjsRefineResult.visible = (hotels.length > 0)
  304.                                     if (hotels.length > 0) {
  305.                                         vjsRefineResult.min_prix = parseInt(filtres.minPrix);
  306.                                         vjsRefineResult.max_prix = parseInt(filtres.maxPrix) + 1;
  307.                                         vjsRefineResult.filre_prix = [vjsRefineResult.min_prix, vjsRefineResult.max_prix]
  308.                                         vjsRefineResult.nbr_enfant_gratuit = filtres.enfantGratuit;
  309.                                         vjsRefineResult.nbr_promo = filtres.promo;
  310.                                         vjsRefineResult.nbr_recommander = filtres.recommander;
  311.                                         vjsRefineResult.nbr_rembourssable = filtres.rembourssable;
  312.                                         vjsRefineResult.nbr_disponible = filtres.disponible;
  313.                                         vjsRefineResult.liste_tags = filtres.tags;
  314.                                         vjsRefineResult.liste_etoiles = filtres.etoiles;
  315.                                         vjsRefineResult.liste_arrangements = filtres.arrangements;
  316.                                         vjsRefineResult.liste_zones = filtres.zones;
  317.                                         vjsRefineResult.liste_chambres = Object.entries(filtres.chambres);
  318.                                         {% if app.request.get('export-rooms') %}
  319.                                         var encodedUri = encodeURI("data:text/csv;charset=utf-8," + vjsRefineResult.liste_chambres.map(x => x[0]).toString().replaceAll(',', "\n"));
  320.                                         var link = document.createElement("a");
  321.                                         link.setAttribute("href", encodedUri);
  322.                                         link.setAttribute("download", "list-rooms.csv");
  323.                                         document.body.appendChild(link);
  324.                                         link.click();
  325.                                         {% endif %}
  326.                                     }
  327.                                 }
  328.                                 if (typeof vjsMinPrice !== 'undefined')
  329.                                     if (hotels.length > 0) {
  330.                                         vjsMinPrice.min_arrangement = hotels[0].min_arrangement
  331.                                         vjsMinPrice.Recap = `${this._recap_occupations} du ${this.checkin_fr} au ${this.checkout_fr}`
  332.                                     } else
  333.                                         vjsMinPrice.min_arrangement = null
  334.                                 if (typeof vjsMinPrice2 !== 'undefined')
  335.                                     if (hotels.length > 0) {
  336.                                         vjsMinPrice2.min_arrangement = hotels[0].min_arrangement
  337.                                         vjsMinPrice2.Recap = `${this._recap_occupations} du ${this.checkin_fr} au ${this.checkout_fr}`
  338.                                     } else
  339.                                         vjsMinPrice2.min_arrangement = null
  340.                                 if (typeof vjsEtiquette !== 'undefined' && hotels.length > 0) {
  341.                                     vjsEtiquette.etiquettes = hotels[0].etiquettes
  342.                                     vjsEtiquette.etiquettesEmplacement = hotels[0].etiquettesEmplacement
  343.                                     vjsEtiquette.etiquettesSaison = hotels[0].etiquettesSaison
  344.                                 }
  345.                                 if (typeof vjsSearchNomsHotels !== 'undefined') {
  346.                                     vjsSearchNomsHotels.liste_noms = Object.values(filtres.noms);
  347.                                     vjsSearchNomsHotels.visible = (hotels.length > 0)
  348.                                 }
  349.                                 if (typeof vjsSortResult !== 'undefined') {
  350.                                     vjsSortResult.recapSearch = {% if app.request.get('product') =="appartement" %}  {{ macro('sejour-hotel.availability').recapSearchAppartement() }} {% else %} {{ macro('sejour-hotel.availability').recapSearch() }} {% endif %};
  351.                                     vjsSortResult.visible = (hotels.length > 0)
  352.                                 }
  353.                                 if (typeof vjsRecapSearch !== 'undefined')
  354.                                     vjsRecapSearch.recapSearch = {% if app.request.get('product') =="appartement" %}  {{ macro('sejour-hotel.availability').recapSearchAppartement() }} {% else %} {{ macro('sejour-hotel.availability').recapSearch() }} {% endif %};
  355.                                 var totalTime = new Date().getTime() - ajaxTime;
  356.                                 console.log(`first timing ${duration} second timing ${totalTime}`)
  357.                                 window.dispatchEvent(new Event("getResponseAvailHotel")); // Émission de l'événement "getResponseAvailHotel"
  358.                                 {% if configAffichage.HOTEL.DISPLAY_PRICE_HALF_DOUBLE == 'oui' and app.request.get('_route') == route_avail_hotel %}
  359.                                 globalState.minPrix2Loading = true;
  360.                                 axios
  361.                                     .get('{{ path('sejour_hotel_ajax_availability') }}',
  362.                                         {
  363.                                             params: {
  364.                                                 HotelSearch: utf8_to_b64(JSON.stringify({
  365.                                                     SearchDetails: {
  366.                                                         BookingDetails: BookingDetails,
  367.                                                         Rooms: [{Adult: 2}],
  368.                                                         GroupingHotel: true,
  369.                                                         Product: "{{ app.request.get('product','hotel') }}",
  370.                                                         CombinationRooms: {{ resultView in ['pension-combin-room','combin-room-pension'] ? 'true' : 'false' }},
  371.                                                         BoardingByRooms: {{ resultView in ['room-pension','combin-room-pension'] ? 'true' : 'false' }},
  372.                                                         Filters: {
  373.                                                             Source: "{{ app.request.get('source','all')=='~'?'all':app.request.get('source','all') }}"
  374.                                                         }
  375.                                                     }
  376.                                                 }))
  377.                                             }
  378.                                         })
  379.                                     .then(response => {
  380.                                             globalState.minPrix2Loading = false;
  381.                                             if (response.data.Error !== undefined) {
  382.                                                 viewAlert('{{ "Erreur"|trans }}', 'danger')
  383.                                                 console.error(response.data.Error)
  384.                                             } else if (vjsListHotels.hotels !== undefined) {
  385.                                                 response.data.HotelSearch.map(h => {
  386.                                                     var i = vjsListHotels.hotels.findIndex(htl => h.Hotel.IdLocal !== undefined ? htl.Hotel.IdLocal == h.Hotel.IdLocal : htl.Hotel.Id == h.Hotel.Id)
  387.                                                     if (i >= 0) {
  388.                                                         this.$set(vjsListHotels.hotels[i], 'min_arrangement2', h.min_arrangement);
  389.                                                     }
  390.                                                 })
  391.                                             }
  392.                                         }
  393.                                     );
  394.                                 {% endif %}
  395.                             }
  396.                         }
  397.                     );
  398.                 {% endif %}
  399.             },
  400.             Recap() {
  401.                 let nbrR = this.rooms.length,
  402.                     nbrA = 0,
  403.                     nbrC = 0;
  404.                 let rooms = []
  405.                 this.rooms.map(x => {
  406.                     nbrA += parseInt(x['Adult']);
  407.                     nbrC += parseInt(x['children']);
  408.                     rooms.push(([x['Adult']].concat(x['Child'])).join(','))
  409.                 });
  410.                 let text = {{ macro('sejour-hotel.availability').recapOccupation(app.request.get('_route')) }};
  411.                 let textApprtement = {{ macro('sejour-hotel.availability').recapOccupationAppartement(app.request.get('_route')) }};
  412.                 let _textAppartement = (nbrA == 1 ? '{{ "un"|trans }}' : nbrA) + ' {{ "adulte"|trans }}' + (nbrA > 1 ? '{{ "s"|trans }}' : '')
  413.                 let _text = (nbrA == 1 ? '{{ "un"|trans }}' : nbrA) + ' {{ "adulte"|trans }}' + (nbrA > 1 ? '{{ "s"|trans }}' : '')
  414.                 if (nbrC > 0)
  415.                     _text += ' et ' + (nbrC == 1 ? '{{ "un"|trans }}' : nbrC) + ' {{ "enfant"|trans }}' + (nbrC > 1 ? '{{ "s"|trans }}' : '')
  416.                 $('[data-target="#occupations{{ produit }}"]').val(text);
  417.                 $('[data-target="#occupationsAppartement{{ produit }}"]').val(textApprtement);
  418.                 $('.rooms-descSHT').html(text);
  419.                 this.occupations = rooms.join(';')
  420.                 {% if app.request.get('product') == "appartement" %}
  421.                 this.recap_occupations = textApprtement
  422.                 this._recap_occupations = _textAppartement
  423.                 {% else %}
  424.                 this.recap_occupations = text
  425.                 this._recap_occupations = _text
  426.                 {% endif %}
  427.                 window.nbrRoom = nbrR
  428.                 window.nbrAdult = nbrA
  429.                 window.nbrChild = nbrC
  430.                 {% if app.request.get('_route') not in ['front_evenement_details'] %}
  431.                 if (typeof $('#occupations{{ produit }}').modal === "function")
  432.                     $('#occupations{{ produit }}').modal('hide')
  433.                 {% endif %}
  434.             },
  435.             editChildren(index) {
  436.                 let old_child = this.rooms[index]['Child'].length;
  437.                 let new_child = this.rooms[index]['children'];
  438.                 if (old_child > new_child)
  439.                     this.rooms[index]['Child'].length = new_child;
  440.                 else
  441.                     do
  442.                         this.rooms[index]['Child'].push({{ configAffichage.HOTEL.MIN_AGE_ENFANT }})
  443.                     while (this.rooms[index]['Child'].length < new_child);
  444.             },
  445.             removeRoom(index) {
  446.                 this.rooms.splice(index, 1);
  447.             },
  448.             addRoom() {
  449.                 this.rooms.push({
  450.                     Adult: 2,
  451.                     children: 0,
  452.                     Child: []
  453.                 })
  454.             },
  455.             fetchAllHotelsPaginated(response) {
  456.                 vjsListHotels.totalHotels = response.CountResults;
  457.                 vjsListHotels.loadedHotels = response.HotelSearch.length;
  458.                 vjsListHotels.progressHotels = Math.round((vjsListHotels.loadedHotels / vjsListHotels.totalHotels) * 100);
  459.                 let offset = vjsListHotels.loadedHotels;
  460.                 let limit = vjsListHotels.loadedHotels;
  461.                 function fetchNextBatch() {
  462.                     if (vjsListHotels.loadedHotels >= vjsListHotels.totalHotels) return;
  463.                     axios.get("{{ path('sejour_hotel_ajax_availability') }}", {
  464.                         params: {
  465.                             HotelSearch: utf8_to_b64(JSON.stringify({
  466.                                 offset: offset,
  467.                                 limit: limit,
  468.                                 search_id: response.SearchId
  469.                             }))
  470.                         }
  471.                     }).then(function (res) {
  472.                         if (res.data && res.data.HotelSearch) {
  473.                             // Ajouter les nouveaux hôtels à la liste
  474.                             vjsListHotels.hotels = vjsListHotels.hotels.concat(res.data.HotelSearch);
  475.                             vjsListHotels.loadedHotels += res.data.HotelSearch.length;
  476.                             offset += res.data.HotelSearch.length;
  477.                             vjsListHotels.progressHotels = Math.round((vjsListHotels.loadedHotels / vjsListHotels.totalHotels) * 100);
  478.                             // Appel récursif si pas fini
  479.                             if (vjsListHotels.loadedHotels < vjsListHotels.totalHotels) {
  480.                                 fetchNextBatch();
  481.                             }
  482.                         }
  483.                     });
  484.                 }
  485.                 // Démarrer la récupération si besoin
  486.                 if (vjsListHotels.loadedHotels < vjsListHotels.totalHotels) {
  487.                     fetchNextBatch();
  488.                 }
  489.             },
  490.         },
  491.         mounted() {
  492.             window.checkin_en = this.checkin_en
  493.             window.checkout_en = this.checkout_en
  494.             $('.typeahead_destination{{ produit }}').val(this.lbl_destination)
  495.             $('.typeahead.destination{{ produit }}').val(this.lbl_destination)
  496.             $('#nuitees{{ produit }}').val(this.nuitees)
  497.             this.Recap()
  498.             if (typeof $(this.$refs.select).selectpicker === "function") {
  499.                 $(this.$refs.select).selectpicker('refresh')
  500.                 $('.btn-group.bootstrap-select button').attr('title', '')
  501.             }
  502.         },
  503.         updated() {
  504.             if (typeof $(this.$refs.select).selectpicker === "function") {
  505.                 $(this.$refs.select).selectpicker('refresh')
  506.                 $('.btn-group.bootstrap-select button').attr('title', '')
  507.             }
  508.         },
  509.         destroyed() {
  510.             if (typeof $(this.$refs.select).selectpicker === "function")
  511.                 $(this.$refs.select).off().selectpicker('destroy')
  512.         }
  513.     })
  514.     var date = new Date();
  515.     var currentMonth = date.getMonth();
  516.     var currentDate = date.getDate();
  517.     var currentYear = date.getFullYear();
  518.     $('input[name="daterange{{ produit }}"]').daterangepicker({
  519.             opens: 'left',
  520.             startDate: vjsAdvancedSearch{{ produit }}.checkin_fr,
  521.             endDate: vjsAdvancedSearch{{ produit }}.checkout_fr,
  522.             locale: {
  523.                 format: "DD/MM/YYYY",
  524.                 cancelLabel: '{{ "Effacer"|trans }}',
  525.                 applyLabel: '{{ "Valider"|trans }}',
  526.                 "firstDay": 1,
  527.             },
  528.             minDate: new Date(currentYear, currentMonth, currentDate),
  529.             beforeShowDay: function (d) {
  530.                 var dmy = (d.getMonth() + 1);
  531.                 if (d.getMonth() < 9)
  532.                     dmy = "0" + dmy;
  533.                 if ($.inArray(dmy, availableDates) != -1) {
  534.                     return [true, "", "Available"];
  535.                 } else {
  536.                     return [false, "", "unAvailable"];
  537.                 }
  538.             }
  539.         },
  540.         function (start, end, label) {
  541.             vjsAdvancedSearch{{ produit }}.checkin_en = start.format('YYYY-MM-DD')
  542.             vjsAdvancedSearch{{ produit }}.checkout_en = end.format('YYYY-MM-DD')
  543.             window.checkin_en = start.format('YYYY-MM-DD')
  544.             window.checkout_en = end.format('YYYY-MM-DD')
  545.             vjsAdvancedSearch{{ produit }}.checkin_fr = start.format('DD/MM/YYYY')
  546.             vjsAdvancedSearch{{ produit }}.checkout_fr = end.format('DD/MM/YYYY')
  547.             let nuitees = (new Date(window.checkout_en) - new Date(window.checkin_en)) / 86400000;
  548.             vjsAdvancedSearch{{ produit }}.nuitees = nuitees
  549.             $('#nuitees{{ produit }}').val(nuitees)
  550.         });
  551.     $('#nuitees{{ produit }}').change(function () {
  552.         vjsAdvancedSearch{{ produit }}.nuitees = parseInt($(this).val())
  553.         let checkin = new Date(vjsAdvancedSearch{{ produit }}.checkin_en)
  554.         let checkout = checkin.addDays(parseInt($(this).val()))
  555.         $('input[name="daterange{{ produit }}"]').data('daterangepicker').setEndDate(checkout)
  556.         vjsAdvancedSearch{{ produit }}.checkout_en = checkout.toISOString().slice(0, 10)
  557.         window.checkout_en = checkout.toISOString().slice(0, 10)
  558.         vjsAdvancedSearch{{ produit }}.checkout_fr = checkout.toISOString().slice(0, 10).split('-').reverse().join('/')
  559.     })
  560.     {% if configAffichage.HOTEL["MODELE_SELECT_VILLE_HOTEL#{is_mobile() ? '_MOBILE' : ''}"] == 'jsuites' %}
  561.     var jSuites = jSuites.dropdown(document.getElementById('dropdown{{ produit }}'), {
  562.         data:{{ villes_hotels|json_encode|raw }},
  563.         /* width: '280px',*/
  564.         placeholder: 'Ville ou Hôtel',
  565.         autocomplete: true,
  566.         onopen: function () {
  567.             $('div.jdropdown-content').animate({
  568.                 scrollTop: 0
  569.             }, 100);
  570.         },
  571.         onchange: function (el, val) {
  572.             if (val.currentIndex === undefined)
  573.                 return
  574.             var item = val.items[val.currentIndex].data
  575.             vjsAdvancedSearch{{ produit }}.pays = item.pays
  576.             vjsAdvancedSearch{{ produit }}.ville = item.ville
  577.             vjsAdvancedSearch{{ produit }}.hotel = (item.hotel === undefined ? 'tous' : item.hotel)
  578.             vjsAdvancedSearch{{ produit }}.destination = item.value
  579.             vjsAdvancedSearch{{ produit }}.lbl_destination = item.text
  580.         }
  581.     });
  582.     {% if selected_destination %}
  583.     jSuites.setValue('{{ selected_destination.type }}-{{ selected_destination.id }}')
  584.     {% endif %}
  585.     {% elseif configAffichage.HOTEL["MODELE_SELECT_VILLE_HOTEL#{is_mobile() ? '_MOBILE' : ''}"] == 'typeahead' %}
  586.     {% if is_mobile() %}
  587.     var $input = $("input.typeahead.destination{{ produit }}");
  588.     window.query_cache = {};
  589.     $input.typeahead({
  590.         maxItem: 30,
  591.         accent: true,
  592.         {% if produit == 'SHE' or enabled_hotel_stay_worldwide == 'true' %}
  593.         source: function (query, process) {
  594.             if (query_cache[query]) {  // if in cache use cached value, if don't wanto use cache remove this if statement
  595.                 process(query_cache[query]);
  596.                 return;
  597.             }
  598.             if (typeof searching != "undefined") {
  599.                 clearTimeout(searching);
  600.                 process([]);
  601.             }
  602.             searching = setTimeout(function () {
  603.                 $.ajax({
  604.                     url: "{{ path('source_typeahead_ville_hotel') }}",
  605.                     data: {Keywords: query, onlySearchCity: {{ onlySearchCity ? 1 : 0 }} },
  606.                     dataType: "json",
  607.                     beforeSend: function () {
  608.                         $input.parent().removeClass('input-marker').addClass('input-spinner');
  609.                     },
  610.                     success: function (data) {
  611.                         query_cache[query] = data;  // save result to cache, remove next line if you don't want to use cache
  612.                         process(data);
  613.                     },
  614.                     complete: function () {
  615.                         $input.parent().addClass('input-marker').removeClass('input-spinner');
  616.                     }
  617.                 });
  618.             }, 300); // 300 ms only search if stop typing for 300ms aka fast typers
  619.         },
  620.         highlight: true,
  621.         minLength: 1,
  622.         hint: true,
  623.         {% else %}
  624.         source: {{ villes_hotels|json_encode|raw }},
  625.         {% endif %}
  626.         autoSelect: true,
  627.         displayText: function (item) {
  628.             return item.name
  629.         },
  630.         //highlighter: Object,
  631.         afterSelect: function (item) {
  632.             $input.val(item.name).change();
  633.             vjsAdvancedSearch{{ produit }}.pays = item.pays
  634.             vjsAdvancedSearch{{ produit }}.ville = item.ville
  635.             vjsAdvancedSearch{{ produit }}.hotel = (item.hotel === undefined ? 'tous' : item.hotel)
  636.             vjsAdvancedSearch{{ produit }}.destination = `${item.type}-${item.id}`
  637.             vjsAdvancedSearch{{ produit }}.lbl_destination = item.name
  638.         }
  639.     });
  640.     {% endif %}
  641.     window.query_cache = {};
  642.     //http://www.runningcoder.org/jquerytypeahead/demo
  643.     $.typeahead({
  644.         input: '.typeahead_destination{{ produit }}',
  645.         minLength: 1,
  646.         maxItem: 30,
  647.         hint: true,
  648.         accent: true,
  649.         dynamic: true,
  650.         loadingAnimation: false,
  651.         cancelButton: false,
  652.         delay: 500,
  653.         // backdrop: {"background-color": "#fff"},
  654.         template: function (query, item) {
  655.             var fa = (item.type == 'v' ? 'map-marker-alt' : 'hotel')
  656.             return `
  657.             <div class="suggestion-content">
  658.                 <span class="icon-hotel"><i class="fa fa-${fa}"></i></span>
  659.                 <div class="hotel-info">
  660.                     <strong>${item.name}</strong> <span>${item.destination}</span>
  661.                 </div>
  662.             </div> `;
  663.         },
  664.         emptyTemplate: "<span color='red'>Aucun résultat pour la chaîne saisie <b>'{{ '{{query}}' }}'</b></span>",
  665.         source: {
  666.             ville: {
  667.                 display: "name",
  668.                 {% if produit == 'SHE' or enabled_hotel_stay_worldwide == 'true' %}
  669.                 ajax: function (query) {
  670.                     // if (query_cache[query])  // if in cache use cached value, if don't wanto use cache remove this if statement
  671.                     //     return query_cache[query];
  672.                     return {
  673.                         type: "GET",
  674.                         url: "{{ path('source_typeahead_ville_hotel') }}",
  675.                         path: "data",
  676.                         data: {
  677.                             Keywords: "{{ '{{query}}' }}",
  678.                             maxItem: 30,
  679.                             onlySearchCity: 1
  680.                         },
  681.                         callback: {
  682.                             done: function (data) {
  683.                                 data.data = data
  684.                                 // query_cache[query] = data;  // save result to cache, remove next line if you don't want to use cache
  685.                                 return data;
  686.                             }
  687.                         }
  688.                     }
  689.                 }
  690.                 {% else %}
  691.                 data:{{ villes_hotels|json_encode|raw }}
  692.                 {% endif %}
  693.             }
  694.         },
  695.         callback: {
  696.             onClickAfter: function (node, a, item, event) {
  697.                 jQuery(node).val(item.name);
  698.                 vjsAdvancedSearch{{ produit }}.pays = item.pays
  699.                 vjsAdvancedSearch{{ produit }}.ville = item.ville
  700.                 vjsAdvancedSearch{{ produit }}.hotel = (item.hotel === undefined ? 'tous' : item.hotel)
  701.                 vjsAdvancedSearch{{ produit }}.destination = `${item.type}-${item.id}`
  702.                 vjsAdvancedSearch{{ produit }}.lbl_destination = item.name
  703.             },
  704.             onSendRequest: function (node, query) {
  705.                 jQuery(node).parent().removeClass('input-marker').addClass('input-spinner');
  706.             },
  707.             onReceiveRequest: function (node, query) {
  708.                 jQuery(node).parent().addClass('input-marker').removeClass('input-spinner');
  709.             }
  710.         },
  711.         debug: true
  712.     });
  713.     {% endif %}
  714.     $(window).scroll(function () {
  715.         if ($(window).scrollTop() >= 300) {
  716.             $('#navbar').addClass('stikynavbar');
  717.         } else {
  718.             $('#navbar').removeClass('stikynavbar');
  719.         }
  720.     });
  721.     $(window).scroll(function () {
  722.         if ($(this).scrollTop() > 100) {
  723.             $('.advance-search-header').addClass('sticky-advanced-search')
  724.         } else {
  725.             $('.advance-search-header').removeClass('sticky-advanced-search')
  726.         }
  727.     });
  728. </script>