Milhas para quem é feito de viagens

Um erro ocorreu enquanto processava o modelo.
The following has evaluated to null or missing:
==> item.mobileBtnVarName  [in template "20101#20128#4389887" at line 508, column 25]

----
Tip: It's the step after the last dot that caused this error, not those before it.
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----

----
FTL stack trace ("~" means nesting-related):
	- Failed at: ${item.mobileBtnVarName.getData()}  [in template "20101#20128#4389887" at line 508, column 23]
----
1<#if getterUtil.getBoolean(showTabs.getData())> 
2<style> 
3  #time-input-dropdown-pickup { 
4     max-height: 17.5rem !important; 
5
6 #time-input-dropdown-dropoff { 
7     max-height: 17.5rem !important; 
8
9 .smls-searchers-container-tab-container { 
10     overflow: hidden; 
11     width: 1120px; 
12     margin: auto; 
13     background-color: #ffffff; 
14     padding: 0 30px; 
15     border-bottom: 1px solid rgba(0, 0, 0, 0.1); 
16     box-shadow: 0px -4px 16px rgba(0, 0, 0, 0.12); 
17     border-radius: 24px 24px 0 0; 
18
19 .smls-searchers-container-tab { 
20     float: left; 
21     border: none; 
22     outline: none; 
23     cursor: pointer; 
24     padding: 14px 16px; 
25     transition: 0.3s; 
26     color: #333; 
27     font-weight: 700; 
28     font-size: 14px; 
29     line-height: 21px; 
30
31 .smls-searchers-container-tab:hover { 
32     text-decoration: underline; 
33
34 .smls-searchers-container-tab.active { 
35     border-bottom: 2px solid #ff7020; 
36
37 .smls-flight-search-desktop .wrapper { 
38     box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.12); 
39     border-radius: 0 0 16px 16px; 
40
41 .car-search-container { 
42     box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.12); 
43     border-radius: 0 0 16px 16px; 
44     padding: 20px 32px; 
45
46 .hidden { 
47     display: none !important; 
48
49 
50 .smls-searchers-container { 
51     position: absolute; 
52     top: -662px; 
53     left: calc(50% - 562px); 
54
55 .car-search-container .car-search-content-wrapper{ 
56     display: -webkit-box; 
57     display: -ms-flexbox; 
58     display: flex; 
59     -webkit-box-orient: horizontal; 
60     -webkit-box-direction: normal; 
61     -ms-flex-flow: row wrap; 
62     flex-flow: row wrap; 
63     -webkit-box-align: start; 
64     -ms-flex-align: start; 
65     align-items: flex-end!important; 
66     width: 100%; 
67
68.smls-flight-search-desktop .wrapper .bottom-content .list-of-destinations .search-item .location-section .flight-icon-circle { 
69    min-width: 32px; 
70
71.search-panel-dropdown-wrapper{ 
72		display: flex !important; 
73
74#DesktopFlightSearch-form-click header { 
75    display: none; 
76
77.smiles-react-hotels-search-App .hotels-search-panel-cross-sell-tooltip-container { 
78    margin-right: 20px; 
79
80#hotels-auto-complete-search:focus  { 
81    box-shadow: none !important 
82
83@media (min-width: 992px) { 
84    .smiles-react-hotels-search-App .dropdown-menu.expansible { 
85        min-width: 550px; 
86
87
88@media (max-width: 992px) { 
89.smls-flight-search-mobile .autocomplete-search .dropdown-toggle input.form-control{ 
90        display: flex; 
91        justify-items: left; 
92
93
94@media (min-width: 769px) { 
95    .search-panel-fixed.visible { 
96        display: none !important 
97    }     
98}		 
99@media only screen and (max-width: 1239px) { 
100    .liferay-home-banner { 
101        margin-top: 25px; 
102
103     
104
105 @media (min-width: 840px) { 
106    .liferay-home-banner { 
107        margin-top: 30px; 
108
109     .smls-searchers-container-tabcontent { 
110         padding: 0; 
111         display: block; 
112         width: 1120px; 
113         margin: auto; 
114         text-align: center; 
115         position: relative; 
116         border: 0px; 
117         height: auto; 
118
119     #DesktopFlightSearch-form-click { 
120         margin: 0px; 
121         width: 100%; 
122
123     .smls-flight-search-desktop { 
124         margin: 0 !important; 
125         top: 0 !important; 
126
127     .smls-lf .smls-flight-search-mobile { 
128         top: 0 !important; 
129
130     .searcher-button-container { 
131         display: none; 
132
133
134 @media (max-width: 839px) { 
135    .car-search-mobile-header { 
136        display: flex !important; 
137
138    .smls-lf .autocomplete-search .dropdown:not(.show)>.dropdown-toggle { 
139        border: 1px solid #ccc !important; 
140
141    .smls-lf .smls-counter-input .dropdown-wrapper .hidden{ 
142        display: block !important 
143
144     .searcher-button-container { 
145         position: absolute; 
146         left: 0; 
147         display: flex; 
148         flex-wrap: wrap; 
149         gap: 8px; 
150         background-color: transparent; 
151         width: 100%; 
152         justify-content: center; 
153         max-height: 96px; 
154         top: 502px; 
155
156     .searcher-button { 
157         display: flex; 
158         align-items: center; 
159         justify-content: flex-start; 
160         padding: 12px; 
161         gap: 8px; 
162         border-radius: 8px; 
163         background-color: #ffffff; 
164         color: #000000; 
165         font-weight: 400; 
166         font-size: 14px; 
167         border: none; 
168         cursor: pointer; 
169
170     .searcher-button i { 
171         display: flex; 
172         align-items: center; 
173         font-size: 17px; 
174         width: 23px; 
175         height: 23px; 
176         color: #ff7020; 
177
178     .smls-searchers-container-tab-container { 
179         display: none; 
180
181     .car-search-modal { 
182         z-index: 2; 
183         min-height: 100%; 
184         width: 100%; 
185
186     .smls-searchers-container { 
187         top: -1010px; 
188         position: absolute; 
189         left: 0; 
190         width: 100%; 
191
192     .smls-searchers-container-tabcontent { 
193         display:block !important; 
194
195     .car-search-button { 
196         display: none !important; 
197
198     .smls-flight-search-mobile .wrapper { 
199         display: none !important; 
200
201     .car-search-modal .time-modal-list { 
202         height: calc(100% - 200px) !important; 
203
204     .smls-lf .list-group-item>button .smls-ignore-click .smls-list-main-content { 
205         width: 100%; 
206         -webkit-box-orient: vertical; 
207         -webkit-box-direction: normal; 
208         -ms-flex-direction: column; 
209         flex-direction: column; 
210         -webkit-box-pack: center; 
211         -ms-flex-pack: center; 
212         justify-content: center; 
213         color: black; 
214
215     .smls-lf .dropdown-mobile { 
216         height: 100vh; 
217         width: 100%; 
218         background-color: #fff; 
219         z-index: 1050; 
220         position: fixed; 
221         left: 0; 
222
223
224 .smls-searchers-container-skeleton { 
225     width: 1120px; 
226     height: 270px; 
227     margin: auto; 
228     position: absolute; 
229     top: -667px; 
230     left: calc(50% - 562px); 
231
232 .searcher-button-container-skeleton { 
233     display: none; 
234     position: absolute; 
235     z-index: 1; 
236     top: -408px; 
237     left: calc(50% - -12px); 
238
239 .skeleton-tabs { 
240     overflow: hidden; 
241     width: 1120px; 
242     margin: auto; 
243     padding: 0 30px; 
244     border-bottom: 1px solid rgba(0, 0, 0, 0.1); 
245     box-shadow: 0px -4px 16px rgba(0, 0, 0, 0.12); 
246     border-radius: 24px 24px 0 0; 
247     background: #ffffff; 
248     display: flex; 
249     gap: 16px; 
250
251 .skeleton-tab { 
252     height: 21px; 
253     width: 120px; 
254     margin: 14px 0; 
255     background: #e2e5e7; 
256     background: linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%); 
257     background-size: 200% 100%; 
258     animation: 1.5s shine linear infinite; 
259     border-radius: 4px; 
260
261 .skeleton-content { 
262     height: 176px; 
263     width: 1120px; 
264     background: #e2e5e7; 
265     background: linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%); 
266     background-size: 200% 100%; 
267     animation: 1.5s shine linear infinite; 
268     border-radius: 0 0 24px 24px; 
269     box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.12); 
270
271 @media (max-width: 839px) { 
272     
273     #search-panel-mobile { 
274         display: none; 
275
276    .search-panel-container-mobile{ 
277      width: auto !important; 
278
279     .smls-searchers-container-skeleton { 
280         display: none; 
281
282     .searcher-button-container-skeleton { 
283         position: absolute; 
284         left: 0; 
285         top: -508px; 
286         display: flex; 
287         flex-direction: row; 
288         gap: 8px; 
289         width: 100%; 
290         max-height: 96px; 
291         justify-content: center; 
292         z-index: 2; 
293
294     .searcher-button-mobile-skeleton { 
295         height: 47px; 
296         width: 90px; 
297         display: flex; 
298         align-items: center; 
299         font-size: 17px; 
300         color: #ff7020; 
301         background: #e2e5e7; 
302         background: linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%); 
303         background-size: 200% 100%; 
304         animation: 1.5s shine linear infinite; 
305         border-radius: 8px; 
306
307
308 @keyframes shine { 
309     to { 
310         background-position-x: -200%; 
311
312
313 
314</style> 
315 
316<div class="smls-searchers-container-skeleton"> 
317  <div class="skeleton-tabs"> 
318      <#list tab.getSiblings() as item> 
319         <#if getterUtil.getBoolean(item.show.getData())> 
320         <div class="skeleton-tab"></div> 
321         </#if>    
322      </#list> 
323  </div> 
324  <div class="skeleton-content"></div> 
325</div> 
326<div class="searcher-button-container-skeleton"> 
327   <#list tab.getSiblings() as item> 
328      <#if getterUtil.getBoolean(item.show.getData())> 
329         <div class="searcher-button-mobile-skeleton"></div> 
330      </#if>    
331   </#list> 
332</div> 
333<div class="smls-searchers-container hidden"> 
334  <div class="smls-searchers-container-tab-container"> 
335     <#list tab.getSiblings() as item> 
336      <#if getterUtil.getBoolean(item.show.getData())> 
337        <div class="smls-searchers-container-tab" onclick="openTabSearchers(event, '${item.library.getData()}-tab')"> 
338            ${item.label.getData()} 
339        </div> 
340      </#if>    
341     </#list>				 
342  </div> 
343  <#list tab.getSiblings() as item> 
344    <#if getterUtil.getBoolean(item.show.getData())> 
345      <div id="${item.library.getData()}-tab" class="smls-searchers-container-tabcontent smls-lf"> 
346        <div id="${item.library.getData()}-id-tab"></div> 
347      </div> 
348    </#if>     
349  </#list> 
350  <div class="searcher-button-container hidden"> 
351     <#list tab.getSiblings() as item> 
352      <#if getterUtil.getBoolean(item.show.getData())> 
353        <button class="searcher-button" id="${item.library.getData()}-search-btn"> 
354        <i class="material-icons" id="${item.library.getData()}-icon">${item.icon.getData()}</i> ${item.labelMobile.getData()} 
355        </button> 
356      </#if> 
357     </#list> 
358  </div> 
359</div> 
360 
361<script type="text/javascript"> 
362    let isInitializedDynamicSearch = false; 
363 
364    Liferay.Portlet.ready(function() { 
365        if (isInitializedDynamicSearch) { 
366            return; 
367
368        console.log("Inicializado Buscadores."); 
369        isInitializedDynamicSearch = true; 
370 
371        if (window.React && window.ReactDOM && window.remoteComponent && window.Liferay) { 
372        //Definição de constantes 
373        const mdhDynamicSearchUrl         = new URL(window.location.href); 
374        const mdhDynamicSearchUrlEditMode = mdhDynamicSearchUrl.searchParams.get("p_l_mode") === "edit"; 
375        const mdhDynamicSearchUrlIsStage  = mdhDynamicSearchUrl.href.includes("stg-svc"); 
376        const mdhDynamicSearchUrlIsPub    = mdhDynamicSearchUrl.href.includes("pub-svc"); 
377        const mdhDynamicSearchHostname    = window.location.hostname; 
378         
379        //Definição de ambientes 
380        const mdhDynamicSearchBaseUrlMap  = { 
381            'dev1'  : { baseUrl: 'portal.dev1.smiles.com.br', staticBaseUrl: 'portal-static.dev1.smiler.com.br' }, 
382            'dev2'  : { baseUrl: 'portal.dev2.smiles.com.br', staticBaseUrl: 'portal-static.dev2.smiler.com.br' }, 
383            'dev3'  : { baseUrl: 'portal.dev3.smiles.com.br', staticBaseUrl: 'portal-static.dev3.smiler.com.br' }, 
384            'uat1'  : { baseUrl: 'portal-uat1.smiles.com.br', staticBaseUrl: 'portal-uat1-static.smiler.com.br' }, 
385            'uat5'  : { baseUrl: 'portal-uat5.smiles.com.br', staticBaseUrl: 'portal-uat5-static.smiler.com.br' }, 
386            'green' : { baseUrl: 'www.smiles.com.br', staticBaseUrl: 'static.smiler.com.br' }, 
387            'blue'  : { baseUrl: 'www.smiles.com.br', staticBaseUrl: 'static.smiler.com.br' }, 
388            'www'   : { baseUrl: 'www.smiles.com.br', staticBaseUrl: 'static.smiler.com.br' }, 
389            'smiles': { baseUrl: 'smiles.com.br', staticBaseUrl: 'static.smiler.com.br' } 
390        }; 
391 
392        // Expressão regular melhorada para lidar com variações no hostname 
393        const mdhDynamicSearchEnvironment = mdhDynamicSearchHostname.match(/(?:portal(-svc)?\.)?(dev[1-3]|uat[15]|green|blue|www|smiles)(?=\.)/)?.[1] || mdhDynamicSearchHostname.match(/(dev[1-3]|uat[15]|green|blue|www|smiles)/)?.[0]; 
394        const mdhDynamicSearchBaseUrls    = mdhDynamicSearchBaseUrlMap[mdhDynamicSearchEnvironment] || { baseUrl: mdhDynamicSearchHostname, staticBaseUrl: 'static.smiler.com.br' }; 
395 
396        //Definição de urls 
397        const mdhDynamicSearchUrls = { 
398            jsonURL :   'https://' + mdhDynamicSearchBaseUrls.baseUrl + '/mfe-apps/components/react-components.json', 
399            cssOrigin : 'https://' + mdhDynamicSearchBaseUrls.staticBaseUrl, 
400            jsOrigin :  'https://' + mdhDynamicSearchBaseUrls.baseUrl 
401        }; 
402 
403        let initProps = []; 
404        <#list tab.getSiblings() as item> 
405            <#if getterUtil.getBoolean(item.show.getData())> 
406            var componentData = { 
407                documentId: '${item.library.getData()}-id-tab',  
408                config: {  
409                    componentConfig: { 
410                        library: '${item.library.getData()}', 
411                        component: '${item.component.getData()}', 
412                        configuration: {${item.configuration.getData()}} 
413                    }, 
414                    jsonURL: mdhDynamicSearchUrls.jsonURL, 
415                    cssOrigin: mdhDynamicSearchUrls.cssOrigin, 
416                    jsOrigin: mdhDynamicSearchUrls.jsOrigin 
417
418            }; 
419            initProps.push(componentData); 
420            </#if> 
421        </#list> 
422 
423 
424        async function renderComponentsWithDelay(initProps) { 
425            for (const item of initProps) { 
426                const config = item.config; 
427                const targetElement = document.getElementById(item.documentId); 
428                 
429                if (targetElement) { 
430                    ReactDOM.render( 
431                        React.createElement(window.remoteComponent.RcConfigLoader, config), 
432                        targetElement 
433                    ); 
434                    console.log("Componente renderizado com sucesso:", item.documentId); 
435                } else { 
436                    console.error("Elemento com ID " + item.documentId + " não encontrado."); 
437
438                await delay(500); 
439
440            const firstItemId = initProps[0]?.documentId; // Verifica se há componentes 
441            if (firstItemId) { 
442                const firstTargetElement = document.getElementById(firstItemId); 
443                 
444                // Inicializa o intervalo para verificar a presença de elementos <input> 
445                const checkInterval = setInterval(() => { 
446                    if (firstTargetElement) { 
447                        // Verifica se existem inputs dentro do primeiro elemento 
448                        const inputElements = firstTargetElement.querySelectorAll('input'); 
449                        if (inputElements.length > 0) { 
450                            clearSkelleton(); // Limpa apenas se houver inputs 
451                            console.log("Inputs encontrados, clearSkelleton chamado."); 
452                            clearInterval(checkInterval); // Limpa o intervalo após encontrar inputs 
453                        } else { 
454                            console.log("Verificando se há inputs no primeiro componente..."); 
455
456                    } else { 
457                        console.error("Elemento com ID " + firstItemId + " não encontrado."); 
458                        clearInterval(checkInterval); // Para o intervalo se o alvo não existir 
459
460                }, 100); // Verifica a cada 100 milissegundos 
461
462
463 
464        function delay(ms) { 
465            return new Promise(resolve => setTimeout(resolve, ms)); 
466
467 
468        setTimeout(() => renderComponentsWithDelay(initProps),800); 
469 
470        } else { 
471            console.error("Algumas bibliotecas não foram carregadas corretamente."); 
472
473    }); 
474 
475    window.addEventListener("load", (event) => { 
476        mapMobileButtons() 
477    }); 
478 
479    function openTabSearchers(evt, tabName) { 
480        const tabcontents = document.querySelectorAll(".smls-searchers-container-tabcontent"); 
481        tabcontents.forEach(content => content.style.display = "none"); 
482        const tablinks = document.querySelectorAll(".smls-searchers-container-tab"); 
483        tablinks.forEach(link => link.classList.remove("active")); 
484        document.getElementById(tabName).style.display = "block"; 
485        evt.currentTarget.classList.add("active"); 
486
487 
488    function clearSkelleton() { 
489        const skeleton = document.querySelector('.smls-searchers-container-skeleton'); 
490        const buttonSkeleton = document.querySelector('.searcher-button-container-skeleton'); 
491        const container = document.querySelector('.smls-searchers-container'); 
492        const buttonContainer = document.querySelector('.searcher-button-container'); 
493        if (skeleton && skeleton.style.display !== 'none') { 
494            skeleton.style.display = 'none'; 
495            buttonSkeleton.style.display = 'none'; 
496            container.classList.remove('hidden'); 
497            buttonContainer.classList.remove('hidden'); 
498            document.getElementsByClassName("smls-searchers-container-tab")[0].click(); 
499            mapMobileButtons();             
500        } else { 
501            console.log("Searchers already loaded"); 
502
503
504 
505    function mapMobileButtons() { 
506        <#list tab.getSiblings() as item> 
507            <#if getterUtil.getBoolean(item.show.getData())> 
508                const ${item.mobileBtnVarName.getData()}DisplayBtn = document.getElementById('${item.library.getData()}-search-btn'); 
509                const ${item.mobileBtnVarName.getData()} = document.querySelector('${item.mobileButtonId.getData()}'); 
510                ${item.mobileBtnVarName.getData()}DisplayBtn.addEventListener('click', (e) => { 
511                    e.preventDefault(); 
512                    ${item.mobileBtnVarName.getData()}.click(); 
513                }); 
514            </#if> 
515        </#list> 
516             
517        document.getElementById('smiles-react-car-search-ut-search-btn').addEventListener('click', (e) => { 
518            e.preventDefault(); 
519            document.querySelector('#smiles-car-search-panel > section > button').click(); 
520        }); 
521 
522        const calendarDiv = document.getElementById("1"); 
523        if (calendarDiv) { 
524            const callback = function(mutationsList) { 
525            for (const mutation of mutationsList) { 
526                if (mutation.type === 'attributes' && mutation.attributeName === 'placeholder') { 
527                const placeholder = mutation.target.placeholder; 
528                const showPanel = placeholder === 'Buscar acomodações' || (placeholder === 'Digite um local ou hotel' && calendarDiv.classList.contains("close")); 
529                document.getElementById("search-panel-mobile").style.display = showPanel ? 'block' : 'none'; 
530
531
532            }; 
533            const defaultHotelsButton = document.getElementById('hotels-auto-complete-search'); 
534            const observerForHotelsButton = new MutationObserver(callback); 
535            const config = { attributes: true }; 
536            observerForHotelsButton.observe(defaultHotelsButton, config); 
537
538
539 
540    const observer = new MutationObserver((mutationsList, observer) => { 
541        let mobileButtonsLoaded = true; 
542        <#list tab.getSiblings() as item> 
543            <#if getterUtil.getBoolean(item.show.getData())> 
544                const ${item.mobileBtnVarName.getData()} = document.querySelector('${item.mobileButtonId.getData()}'); 
545                if (!${item.mobileBtnVarName.getData()}) mobileButtonsLoaded = false; 
546            </#if> 
547        </#list> 
548        if (mobileButtonsLoaded) { 
549            mapMobileButtons(); 
550            observer.disconnect(); 
551
552    }); 
553 
554    if (document.body) { // Verifica se document.body existe 
555        observer.observe(document.body, { childList: true, subtree: true }); 
556
557 
558</script> 
559</#if> 

Turbine seus sonhos

Conheça mais sobre nosso programa de fidelidade e descubra algumas formas de acumular milhas mais rápido!

Mais experiências para você

Junte milhas mais rápido com o Clube Smiles.

Receba milhas todo mês e aproveite benefícios exclusivos, como descontos e promoções que te deixam mais perto da sua próxima sua viagem!

Cartão de Crédito GOL Smiles

Faz sua viagem
acontecer
naturalmente.