Milhas
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!
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.
Como comprar passagens aéreas com Milhas
Viajar com a Smiles ficou muito mais fácil! Se você já tem férias planejadas, mas ainda faltam milhas para completar a compra das passagens aéreas, você está no lugar certo! Na Smiles você pode combinar milhas e dinheiro na emissão dos seus bilhetes para garantir a viagem dos sonhos. Acumule pontos usando seu cartão de crédito nas compras do dia a dia e troque por milhas para a sua próxima aventura!