1(function( $ ) { 2 3 if (jQuery(window).scrollTop() >= 50) { 4 5 jQuery('.navigation-top').removeClass("transparent"); 6 7 } else { 8 jQuery('.navigation-top').addClass("transparent"); 9 } 10 11 $(window).scroll(function () { 12 13 if (jQuery(window).scrollTop() >= 50) { 14 15 jQuery('.navigation-top').removeClass("transparent"); 16 17 } else { 18 jQuery('.navigation-top').addClass("transparent"); 19 } 20 }); 21 22 23 $('.wpmm-mobile-menu li a').on('click', function(){ 24 setTimeout(function(){ 25 $('.wpmm_mobile_menu_btn').click(); 26 }, 500); 27 }); 28 29 30 // Activate select2 on element 31 function activate_select2_element( select_element ) { 32 let select_options = {}; 33 34 // Caso não deva haver search 35 if( $(select_element).attr('data-searchable') != 'true' ) { 36 select_options.minimumResultsForSearch = Infinity; 37 } 38 39 // Caso deva permitir escolher opção vazia 40 if( $(select_element).data('allow-empty-value') === 'true' ) { 41 select_options.allowClear = true; 42 } 43 44 $(select_element).select2( select_options ); 45 } 46 47 48 // Activate all select2 elements with selector 49 function activate_all_select2_elements_by_selector( selector ) { 50 // Obter todos os elementos select2 51 var select2_elements = $( selector ); 52 53 select2_elements.each( function() { 54 activate_select2_element( this ); 55 }); 56 } 57 58 59 // Select2 60 if( $('.select2').length > 0 ) { 61 // Ativar todos os elementos select2 62 activate_all_select2_elements_by_selector( '.select2' ); 63 } 64 65 66 67 var max_file_text = $('.max-file-size').text(); 68 69 $('input[type=file]').on('change', function(){ 70 var filename = $(this).val().split('\\').pop(); 71 $('.max-file-size').html(filename); 72 $('.formulario-mais-detalhes .cross-html').css('display','inline-block'); 73 }); 74 75 $('.cross-html').on('click', function(){ 76 $('input[type=file]').replaceWith($('input[type=file]').val('').clone(true)); 77 $('.max-file-size').text( max_file_text ); 78 $('.formulario-mais-detalhes .cross-html').css('display','none'); 79 }); 80 81 var file_anexed = $('.info-anexarCV').text(); 82 83 $('input[name="AnexarCV"]').on('change', function(){ 84 var filename = $(this).val().split('\\').pop(); 85 86 if(filename == '') { 87 $('.info-anexarCV').html(file_anexed); 88 }else { 89 $('.info-anexarCV').html(filename); 90 } 91 }); 92 93 $(".update-current-year").text(new Date().getFullYear()); 94 95 // Função que traduz a janela hovercard do plugin de chat 96 function wplc_translate_hovercard() { 97 var path = window.location.pathname; 98 99 if(path.includes("/en/") || path.includes("/es/")) { 100 // Tradução Inglês 101 if(path.includes("/en/")) { 102 // Textos 103 var hovercard_content = "What can we help you with?"; 104 var speeching_button = "Submit"; 105 106 // Modificar textos 107 $("#wplc_hovercard_content").text(hovercard_content); 108 $("#speeching_button").text(speeching_button); 109 } 110 111 // Tradução Espanhol 112 else if(path.includes("/es/")) { 113 // Textos 114 var hovercard_content = "¿Como podemos ayudar?"; 115 var speeching_button = "Someter"; 116 117 // Modificar textos 118 $("#wplc_hovercard_content").text(hovercard_content); 119 $("#speeching_button").text(speeching_button); 120 } 121 } 122 } 123 124 125 // Função que traduz a janela de live chat do plugin de chat 126 function wplc_translate_live_chat() { 127 var path = window.location.pathname; 128 129 $("#wplc_name").val(""); 130 131 if(path.includes("/en/") || path.includes("/es/")) { 132 // Tradução Inglês 133 if(path.includes("/en/")) { 134 // Textos 135 var wplc_first_message_offline = "Chat offline. Leave a message."; 136 var wp_live_chat_2_info = "We will contact you as soon as possible."; 137 var send_message_button = "Send Message"; 138 139 // Modificar textos 140 $("#wplc_first_message .wplc_offline").text(wplc_first_message_offline); 141 $("#wp-live-chat-2-info").text(wp_live_chat_2_info); 142 $("#wplc_na_msg_btn").val(send_message_button); 143 } 144 145 // Tradução Espanhol 146 else if(path.includes("/es/")) { 147 // Textos 148 var wplc_first_message_offline = "Chat sin conexión. Deja un mensaje."; 149 var wp_live_chat_2_info = "Nos pondremos en contacto con usted tan pronto como sea posible."; 150 var send_message_button = "Enviar Mensaje"; 151 152 // Modificar textos
153 $("#wplc_first_message .wplc_offline").text(wplc_first_message_offline); 154 $("#wp-live-chat-2-info").text(wp_live_chat_2_info); 155 $("#wplc_na_msg_btn").val(send_message_button); 156 } 157 } 158 } 159 setTimeout(function() { 160 wplc_translate_hovercard(); 161 wplc_translate_live_chat() 162 }, 3000); 163 164 165 166 // ########## NotÃcias ########## 167 168 // Pagination 169 $('#noticias-wrapper').on('click', '#noticias-pagination .page-link', function() { 170 // Get current page 171 let page = parseInt( $('#noticias-page-filter').val() ); 172 173 // Previous page 174 if( $(this).hasClass('page-link-prev') ) { 175 page = page - 1; 176 } 177 // Next page 178 else if( $(this).hasClass('page-link-next') ) { 179 page = page + 1; 180 } 181 // Specific page 182 else { 183 page = $(this).data('page'); 184 } 185 186 // Update page 187 $('#noticias-page-filter').val( page ); 188 $(this).trigger('noticias-update-list'); 189 }); 190 191 192 // Update noticias list 193 var search_noticias_queue = 0; 194 $('#noticias-wrapper').on('noticias-update-list', '.update-noticias-list', function() { 195 search_noticias_queue += 1; 196 197 let noticias_container = $('#noticias-wrapper'); 198 199 // Get filter values 200 let page = $('#noticias-page-filter').val(); 201 202 // Show loader 203 let loader_container = $('#noticias-wrapper'); 204// loader_container.block( default_loader ); 205 206 // AJAX request 207 $.ajax({ 208 type: 'POST', 209 dataType: 'html', 210 url: ajax_var.url, 211 data: { 212 action: 'get_noticias_paginated', 213 nonce: ajax_var.nonce, 214 page: page, 215 search_noticias_queue: search_noticias_queue 216 }, 217 success:function( data ) { 218 let queue_number_response = ''; 219 220 $(data).each(function(){ 221 if( $(this).find("[name='search_noticias_queue']").length > 0 ) { 222 queue_number_response = $(this).find("[name='search_noticias_queue']").val(); 223 } 224 }); 225 226 227 if( parseInt(queue_number_response) === search_noticias_queue ) { 228 $(noticias_container).html( data ); 229 230 // Hide loader 231 // loader_container.unblock(); 232 233 // Reset number queue 234 search_noticias_queue = 0; 235 } 236 }, 237 error: function( errorThrown ) { 238 console.log( "Error: ", errorThrown ); 239 240 // Hide loader 241 // loader_container.unblock(); 242 } 243 }); 244 }); 245 246 jQuery(document).ready(function($) { 247 $(document).on('click', '.update-artigos-list', function(e) { 248 e.preventDefault(); 249 250 var page = $(this).data('page'); 251 if (!page) return; // Proteção para botões disabled 252 253 var data = { 254 'action': 'get_artigos_paginated', 255 'page': page 256 }; 257 258 // Adiciona um efeito visual de loading (opcional) 259 $('#artigos-wrapper').css('opacity', '0.5'); 260 261 $.post(ajaxurl, data, function(response) { 262 $('#artigos-wrapper').html(response); 263 $('#artigos-wrapper').css('opacity', '1'); 264 265 // Faz scroll suave de volta para o topo da grelha 266 $('html, body').animate({ 267 scrollTop: $("#artigos-wrapper").offset().top - 100 268 }, 500); 269 }); 270 }); 271 }); 272 273 274 275 276 277 278 279 280 // ########## Form AI validation ########## 281 282 $('#form-ai-validate').on('blur', 'input[type="number"][min], input[type="number"][max]', function() { 283 let min = $(this).attr('min'); 284 let max = $(this).attr('max'); 285 let value = $(this).val(); 286 287 // Adiciona uma verificação para campos vazios 288 if (value === '') { 289 // Se o campo for deixado vazio, força-o a ter o valor mÃnimo 290 if (min !== undefined) { 291 $(this).val(min); 292 } 293 return; 294 } 295 296 value = parseInt(value); // Converte o valor para número para comparações seguras 297 298 if ( min !== undefined ) { 299 min = parseInt( min ); 300 if ( value < min ) { 301 value = min; 302 } 303 } 304 305 if ( max !== undefined ) { 306 max = parseInt( max ); 307 if ( value > max ) { 308 value = max; 309 } 310 } 311 312 $(this).val(value); 313 }); 314 315 316 var tooltip_options = { 317 container: 'body', 318 boundary: 'window', 319 html: true 320 }; 321 322 $('#form-ai-content').on('click', 'a.tooltip-icon', function(e) { 323 e.preventDefault(); 324 }); 325 326 $('#form-ai-content [data-toggle="tooltip"]').tooltip(tooltip_options); 327 328 // Mostra/esconde o campo de texto "Outro" para a Tipologia de Evento 329 $('#form-ai-tipologia-evento').on('change', function() { 330 if ($(this).val() === 'Outro') { 331 $('#form-ai-tipologia-evento-outro').slideDown(); 332 } else {
333 $('#form-ai-tipologia-evento-outro').slideUp(); 334 } 335 }); 336 337 // ########## Limitar dÃgitos de campos numéricos ########## 338 $('#coffee-breaks').on('input', function() { 339 if (this.value.length > 2) this.value = this.value.slice(0, 2); 340 }); 341 $('#qts_noites, #qts_single, #qts_twin').on('input', function() { 342 if (this.value.length > 4) this.value = this.value.slice(0, 4); 343 }); 344 345 // Sincroniza o número de participantes principal com os campos dos espaços de evento 346 $('#form-ai-participants').on('input', function() { 347 let mainParticipants = $(this).val(); 348 $('input[id^="nr_participantes_sala"]').val(mainParticipants); 349 }); 350 351 // ########## Adicionar salas secundarias ########## 352 const layoutOptionsHtml = $('#sala-principal-disposicao').html(); 353 354 // $('#qts-salas-adicionais').on('input', function() { 355 // const numSalas = parseInt($(this).val()) || 0; 356 // const container = $('#dynamic-salas-adicionais-container'); 357 358 // container.html(''); 359 360 // if (numSalas > 0) { 361 // const headerHtml = ` 362 // <div class="row dynamic-salas-header mb-2"> 363 // <div class="col-6"><label class="form-question-small">Nº de participantes em cada sala</label></div> 364 // <div class="col-6"><label class="form-question-small">Disposição das salas</label></div> 365 // </div>`; 366 // container.append(headerHtml); 367 // } 368 369 // for (let i = 1; i <= numSalas; i++) { 370 // const salaHtml = `
371 // <div class="row dynamic-sala-row align-items-center mb-2"> 372 // <div class="col-2"><label class="sala-number">${i}º</label></div> 373 // <div class="col-4"><input type="number" name="sala_adicional_participantes[]" class="form-control form-control-sm" min="1" placeholder="Nº"></div> 374 // <div class="col-6"><select name="sala_adicional_disposicao[]" class="form-control form-control-sm">${layoutOptionsHtml}</select></div> 375 // </div>`; 376 // container.append(salaHtml); 377 // } 378 // }); 379 380 381 var dynamic_salas_adicionais_num_participants_str = $('#salas-adicionais-num-participants-string').val(); 382 var dynamic_salas_adicionais_layout_str = $('#salas-adicionais-layout-string').val(); 383 var dynamic_salas_adicionais_number_abrev_str = $('#salas-adicionais-number-abrev-string').val(); 384 385 $('#dynamic-event-space-days-container').on('input', 'input[id^="qts-salas-adicionais"]', function() { 386 const numSalas = parseInt($(this).val()) || 0; 387 const container = $(this).closest('.event-space-day').find('[id^="dynamic-salas-adicionais-container"]'); 388 const layoutOptionsHtml = $('#sala-principal-disposicao').html(); 389 390 container.html(''); 391 392 if (numSalas > 0) { 393 const headerHtml = ` 394 <div class="row dynamic-salas-header mb-2"> 395 <div class="col-6"><label class="form-question-small">${dynamic_salas_adicionais_num_participants_str}</label></div> 396 <div class="col-6"><label class="form-question-small">${dynamic_salas_adicionais_layout_str}</label></div> 397 </div>`; 398 container.append(headerHtml); 399 } 400 401 for (let i = 1; i <= numSalas; i++) { 402 const salaHtml = `
403 <div class="row dynamic-sala-row align-items-center mb-2"> 404 <div class="col-2"><label class="sala-number">${i}º</label></div> 405 <div class="col-4"><input type="number" name="sala_adicional_participantes[]" class="form-control form-control-sm" min="1" placeholder="${dynamic_salas_adicionais_number_abrev_str}"></div> 406 <div class="col-6"><select name="sala_adicional_disposicao[]" class="form-control form-control-sm">${layoutOptionsHtml}</select></div> 407 </div>`; 408 container.append(salaHtml); 409 } 410 }); 411 412 // ########## Adicionar dias de Espaços de Evento ########## 413 function updateEventSpaceDays() { 414 const container = $('#dynamic-event-space-days-container'); 415 const template = $('#event-space-day-template'); 416 const desired_days = parseInt($('#form-ai-duration').val()) || 0; 417 const current_days = container.find('.dynamic-event-space-day').length; 418 const mainParticipantsValue = $('#form-ai-participants').val(); 419 420 if (desired_days > current_days) { 421 for (let d = current_days + 1; d <= desired_days; d++) { 422 const new_day = template.clone(); 423 new_day.addClass('dynamic-event-space-day').removeAttr('id').show(); 424 new_day.find('.event-space-day-text').text(d); 425 new_day.find('[id^="nr_participantes_sala"]').val(mainParticipantsValue); 426 427 new_day.find('input, select').each(function() { 428 const old_id = $(this).attr('id'); 429 if (old_id) { 430 $(this).attr('id', old_id + '_' + d); 431 new_day.find(`label[for="${old_id}"]`).attr('for', old_id + '_' + d); 432 } 433 const old_name = $(this).attr('name'); 434 if(old_name) $(this).attr('name', old_name + '_day[' + d + ']'); 435 }); 436 new_day.find('[id^="dynamic-salas-adicionais-container"]').attr('id', 'dynamic-salas-adicionais-container_' + d); 437 container.append(new_day); 438 new_day.find('[id^="sala-principal-tipo_"]').prop('required', true); 439 new_day.find('[id^="nr_participantes_sala_"]').prop('required', true); 440 new_day.find('[id^="sala-principal-disposicao_"]').prop('required', true); 441 } 442 } else if (desired_days < current_days) { 443 container.find('.dynamic-event-space-day:gt(' + (desired_days - 1) + ')').remove(); 444 } 445 } 446 447 // ########## Adicionar dias de catering ########## 448 449 function updateCateringDays() { 450 const container = $('#dynamic-catering-days-container'); 451 const template = $('#catering-day-template'); 452 const desired_days = parseInt($('#form-ai-duration').val()) || 0; 453 const current_days = container.find('.dynamic-catering-day').length; 454 455 // Cenário 1: ADICIONAR DIAS 456 if (desired_days > current_days) { 457 for (let d = current_days + 1; d <= desired_days; d++) { 458 const new_day = template.clone(); 459 new_day.addClass('dynamic-catering-day').removeAttr('id').show(); 460 new_day.find('.catering-day-text').text(d); 461 462 new_day.find('input').each(function() { 463 const old_id = $(this).attr('id'); 464 if (old_id) { 465 const new_id = old_id + '_' + d; 466 $(this).attr('id', new_id); 467 new_day.find(`label[for="${old_id}"]`).attr('for', new_id); 468 } 469 470 const old_name = $(this).attr('name'); 471 if (old_name) { 472 // Lógica de renomear para garantir unicidade 473 const new_name_base = old_name.replace(/_day\[\d+\]/g, '').replace('[]', ''); 474 const new_name = new_name_base + '_day[' + d + ']' + (old_name.endsWith('[]') ? '[]' : ''); 475 $(this).attr('name', new_name); 476 } 477 }); 478 container.append(new_day); 479 new_day.find('[data-toggle="tooltip"]').tooltip(tooltip_options); 480 } 481 } 482 // Cenário 2: REMOVER DIAS 483 else if (desired_days < current_days) { 484 container.find('.dynamic-catering-day:gt(' + (desired_days - 1) + ')').remove(); 485 } 486 487 } 488 489 $('#dynamic-catering-days-container').on('change', 'input[id^="coffee_breaks_toggle"]', function() { 490 const dropdown = $(this).closest('.coffee-break-group').find('.coffee-breaks-input'); 491 492 if ($(this).is(':checked')) { 493 dropdown.show(); 494 dropdown.val('1'); 495 } 496 else { 497 dropdown.hide(); 498 } 499 }); 500 $('#catering-day-template .coffee-breaks-input').hide(); 501 502 $('#form-ai-duration').on('input', function() { 503 updateCateringDays(); 504 updateEventSpaceDays(); 505 }); 506 507 $('#form-ai-duration').on('blur', function() { 508 if (!$(this).val() || parseInt($(this).val()) < 1) { 509 $(this).val(1); 510 $(this).trigger('input'); 511 } 512 }); 513 updateCateringDays(); 514 updateEventSpaceDays(); 515 516 // ########## Lógica de Submissão do Formulário ########## 517 $('#form-ai-validate').on('submit', function(e) { 518 e.preventDefault(); 519 520 let url_params = new URLSearchParams( window.location.search ); 521 522 let debug_mode = false;
523 if( url_params.has( 'debug' ) && url_params.get( 'debug' ) === 'true' ) { 524 debug_mode = true; 525 } 526 527 $('.is-invalid').removeClass('is-invalid'); 528 $('.invalid-feedback').removeClass('d-block').text(''); 529 $('#form-ai-feedback-container').empty(); 530 $('#label-inclui-catering').removeClass('has-error'); 531 532 if (this.checkValidity() === false) { 533 $(this).addClass('was-validated'); 534 $(this).find(':invalid').first().focus(); 535 536 $(this).find('input:invalid, select:invalid').each(function() { 537 const field = $(this); 538 const message = field.prop('validationMessage') || 'Este campo é obrigatório'; // Mensagem do browser ou genérica 539 540 if (field.closest('.custom-number-input').length > 0) { 541 field.closest('.custom-number-input').addClass('is-invalid'); 542 } else { 543 field.addClass('is-invalid'); 544 if (field.hasClass('select2-hidden-accessible')) { 545 field.next('.select2-container').find('.select2-selection').addClass('is-invalid'); 546 } 547 } 548 field.closest('.form-group, .custom-number-input').next('.invalid-feedback').text(message).addClass('d-block'); 549 }); 550 551 return; 552 } 553 554 let submit_button = $('#form-ai-submit'); 555 let button_text = submit_button.children('span'); 556 let button_loader = submit_button.children('.button-loader-container'); 557 558 submit_button.attr('disabled', true); 559 button_text.hide(); 560 button_loader.show(); 561 562 // Obter dados do form 563 let form_data = new FormData( $(this)[0] ); 564 565 // Obter salas adicionais por dia 566 let event_spaces_additional_rooms_days = {}; 567 $('#dynamic-event-space-days-container .dynamic-event-space-day').each(function(index) { 568 let day_index = index + 1; 569 let daily_rooms = []; 570 571 $(this).find('.dynamic-sala-row').each(function() { 572 let room_info = { 573 "num_participants": $(this).find('input[name="sala_adicional_participantes[]"]').val() || 0, 574 "layout": $(this).find('select[name="sala_adicional_disposicao[]"]').val() 575 }; 576 daily_rooms.push(room_info); 577 }); 578 579 if (daily_rooms.length > 0) { 580 event_spaces_additional_rooms_days[day_index] = daily_rooms; 581 } 582 }); 583 584 if (Object.keys(event_spaces_additional_rooms_days).length > 0) { 585 form_data.append('event_spaces_additional_rooms_days', JSON.stringify(event_spaces_additional_rooms_days)); 586 } 587 588 589 // Get catering 590 if( $('#inclui_catering').is(':checked') ) { 591 let catering_details = []; 592 $('#dynamic-catering-days-container .dynamic-catering-day').each( function( index, day_element ) { 593 let day_info = { 594 "day": (index + 1), 595 "welcome_coffee": $(day_element).find('input[id^="welcome_coffee"]').is(':checked'), 596 "coffee_breaks": $(day_element).find('input[id^="coffee_breaks_toggle"]').is(':checked') ? (parseInt($(day_element).find('[id^="coffee_breaks_count"]').val()) || false) : false, 597 "welcome_drink": $(day_element).find('input[id^="welcome_drink"]').is(':checked'), 598 "lunch": $(day_element).find('input[id^="inclui_almoco"]').is(':checked'), 599 "canapes": $(day_element).find('input[id^="canapes"]').is(':checked'), 600 "dinner": $(day_element).find('input[id^="inclui_jantar"]').is(':checked'), 601 "open_bar": $(day_element).find('input[id^="bar_aberto"]').is(':checked'), 602 "supper": $(day_element).find('input[id^="ceia"]').is(':checked') 603 }; 604 605 catering_details.push(day_info); 606 }); 607 608 form_data.append( 'catering_details', JSON.stringify(catering_details) ); 609 } 610 611 612 // Check URL params 613 // let total_visible = true; 614 let total_visible = false; 615 if( url_params.has( 'ver-hv' ) ) { 616 total_visible = false; 617 618 console.log( 'total_visible', total_visible ); 619 } 620 621 form_data.append( 'total_visible', total_visible ); 622 623 624 $('#form-ai-validate .error_msg').html(""); 625 626 $.ajax({ 627 type: 'POST', 628 dataType: 'json', 629 contentType: false, 630 processData: false, 631 url: ajax_var.url, 632 data: form_data, 633 success: function( data ) { 634 console.log(data); 635 636 if( data.success === 'true' ) { 637 // --- Preenchimento do Cabeçalho e TÃtulo --- 638 let dataEvento = $('#form-ai-data-evento').val(); 639 let location = $('#form-ai-location').val(); 640 let tipologiasVenue = $('#form-ai-tipo-venue').val(); 641 642 let tipologiaEvento = $('#form-ai-tipologia-evento').val(); 643 let tipologiaEventoTexto = $('#form-ai-tipologia-evento option:selected').map(function() { 644 return $(this).text(); 645 }).get().join(', '); 646 647 if (tipologiaEvento === 'Outro') { 648 tipologiaEventoTexto = $('#form-ai-tipologia-evento-outro').val(); 649 } 650 651 let participants = $('#form-ai-participants').val(); 652 let duration = $('#form-ai-duration').val(); 653 654 const localizacoesTexto = $('#form-ai-location option:selected').map(function() { 655 return $(this).text(); 656 }).get().join(', '); 657 658 const tipologiasVenueTexto = $('#form-ai-tipo-venue option:selected').map(function() { 659 return $(this).text(); 660 }).get().join(', '); 661 662 const participantsLabel = $('label[for="form-ai-participants"]').data('value'); 663 const durationLabel = $('label[for="form-ai-duration"]').data('value'); 664 665 // Get current language 666 let language_formatted = document.getElementsByTagName('html')[0].getAttribute('lang'); 667 language_formatted = language_formatted ?? 'pt-PT'; 668 669 const dateObj = new Date(dataEvento + 'T00:00:00'); 670 const formattedDate = dateObj.toLocaleDateString(language_formatted, { day: 'numeric', month: 'long', year: 'numeric' }); 671 672 // --- PREENCHIMENTO DO CABEÃALHO DO RESULTADO COM OS TEXTOS VISÃVEIS --- 673 $('#form-ai-result .result-data').text(formattedDate); 674 $('#form-ai-result .result-location').text(localizacoesTexto); 675 $('#form-ai-result .result-venue-type').text(tipologiasVenueTexto); 676 $('#form-ai-result .result-event-type').text(tipologiaEventoTexto); 677 $('#form-ai-result .result-participants').text(participants + " " + participantsLabel); 678 $('#form-ai-result .result-duration').text(duration + " " + durationLabel); 679 680
681 // // --- LÃGICA PARA ESPAÃOS E SALAS ADICIONAIS --- 682 // const paxSalaPrincipal = $('#nr_participantes_sala').val() || 'N/A'; 683 // const layoutSalaPrincipal = $('#sala-principal-disposicao option:selected').text(); 684 // let salasDetailText = `Sala Principal - ${layoutSalaPrincipal} - ${paxSalaPrincipal} participantes`; 685 686 // $('.dynamic-sala-row').each(function(index) { 687 // const paxAdicional = $(this).find('input[name="sala_adicional_participantes[]"]').val() || 'N/A'; 688 // const layoutAdicional = $(this).find('select[name="sala_adicional_disposicao[]"] option:selected').text(); 689 // salasDetailText += ` + Sala Adicional - ${layoutAdicional} - ${paxAdicional} participantes`; 690 // }); 691 692 // let salasPeriodoMontagem = $('#montagem_dia').val(); 693 // salasDetailText += ` + Montagem - ${salasPeriodoMontagem}`; 694 695 // $('#form-ai-result .salas-line .detail').text(salasDetailText); 696 // $('#form-ai-result .salas-line').show(); 697 698 699 // //----- LOGICA PARA CATERING ------ 700 // if ($('#inclui_catering').is(':checked')) { 701 // const all_days_summary = []; 702 703 // // Itera sobre cada dia de catering que foi gerado 704 // $('#dynamic-catering-days-container .dynamic-catering-day').each(function(index) { 705 // const day_summary_parts = []; 706 707 // // Para cada input marcado, adiciona o texto da sua label ao resumo do dia 708 // $(this).find('input[type="checkbox"]:checked').each(function() { 709 // const label_text = $(`label[for="${$(this).attr('id')}"]`).text().trim(); 710 // day_summary_parts.push(label_text); 711 // }); 712 713 // // Adiciona a contagem de coffee breaks, se for maior que zero 714 // const coffeeBreaks = parseInt($(this).find('input[name^="coffee_breaks"]').val()) || 0; 715 // if (coffeeBreaks > 0) { 716 // day_summary_parts.push(`${coffeeBreaks} Coffee Break(s)`); 717 // } 718 719 // // Se houver algum item para este dia, formata a string 720 // if (day_summary_parts.length > 0) { 721 // all_days_summary.push(`Dia ${index + 1}: ${day_summary_parts.join(' + ')}`); 722 // } 723 // }); 724 725 // // Junta os resumos de todos os dias e mostra no ecrã de resultados 726 // $('#form-ai-result .catering-line .detail').text(all_days_summary.join(' | ')); 727 // $('#form-ai-result .catering-line').show(); 728 729 // } else { 730 // $('#form-ai-result .catering-line').hide(); 731 // } 732 733 // // --- LÃGICA PARA ALOJAMENTO --- 734 // if ($('#inclui_alojamento').is(':checked')) { 735 // const noites = $('#qts_noites').val(); 736 // const single = $('#qts_single').val(); 737 // const twin = $('#qts_twin').val(); 738 739 // const noitesLabel = $('label[for="qts_noites"]').data('value'); 740 // const singleLabel = $('label[for="qts_single"]').data('value'); 741 // const twinLabel = $('label[for="qts_twin"]').data('value'); 742 743 // const detailText = `${noites} ${noitesLabel}: ${single} ${singleLabel} e ${twin} ${twinLabel}`; 744 745 // $('#form-ai-result .accomodation-line .detail').text(detailText); 746 // $('#form-ai-result .accomodation-line').show(); 747 // } else { 748 // $('#form-ai-result .accomodation-line').hide(); 749 // } 750 751 752 // // --- LÃGICA PARA AUDIOVISUAIS --- 753 // if ($('#inclui_audiovisuais').is(':checked')) { 754 // const pacoteSelecionado = $('input[name="audio_option"]:checked').val(); 755 // let detalhesDoPacote = []; 756 757 // $('input[name="audio_option"]:checked').closest('.package-radio').find('.package-item').each(function() { 758 // const detalheTexto = $(this).clone().children().remove().end().text().trim(); 759 // detalhesDoPacote.push(detalheTexto); 760 // }); 761 762 // let resultadoFinal = `${pacoteSelecionado}`; 763 // if (detalhesDoPacote.length > 0) { 764 // resultadoFinal += ` (${detalhesDoPacote.join(' + ')})`; 765 // } 766 767 // $('#form-ai-result .audiovisuals-line .detail').text(resultadoFinal); 768 // $('#form-ai-result .audiovisuals-line').show(); 769 // } else { 770 // $('#form-ai-result .audiovisuals-line').hide(); 771 // } 772 773 774 // If response is returned 775 if( 'response_endpoint' in data && data.response_endpoint ) { 776 // Simulation saved 777 if( 'save_simulation_result' in data && data.save_simulation_result ) { 778 let save_simulation_result = data.save_simulation_result; 779 780 $('#pid').val( save_simulation_result.id ); 781 $('#gid').val( save_simulation_result.guid ); 782 783 $('#form-ai-simulation-ref-text').text( save_simulation_result.id ); 784 785 786 // Check if there are charts to create 787 if( 'charts_info' in data.response_endpoint && data.response_endpoint.charts_info ) { 788 // Generate and save simulation charts 789 generate_and_save_simulation_charts( save_simulation_result.id, save_simulation_result.guid, data.response_endpoint.charts_info ); 790 } 791 } 792 793 794 // Mostrar debug 795 let show_debug = debug_mode; 796 if( show_debug ) { 797 let debug_html = `<h4 class="mb-4">Debug</h4>`; 798 799 if( 'calculated_event_prices' in data.response_endpoint && data.response_endpoint.calculated_event_prices ) {
800 let calculated_event_prices = data.response_endpoint.calculated_event_prices; 801 802 debug_html += `<h6 class="mb-4 p-0">Total evento: ${ calculated_event_prices.event_total }</h4>`; 803 804 // Event spaces 805 if ('event_spaces_prices' in calculated_event_prices && calculated_event_prices.event_spaces_prices.daily_setup_prices) { 806 let event_spaces_prices = calculated_event_prices.event_spaces_prices; 807 let event_space_services = ``; 808 809 // Percorre cada dia no array de preços 810 event_spaces_prices.daily_setup_prices.forEach((day_price, index) => { 811 event_space_services += `<li><b>Dia ${index + 1}</b></li>`; 812 813 // Adiciona uma lista dentro da lista para organizar 814 event_space_services += `<ul>`; 815 816 // Main event space para este dia 817 if (day_price.main_event_space) { 818 event_space_services += `<li>Sala principal - unit: ${day_price.main_event_space.price_unit} | total: ${day_price.main_event_space.price_total}</li>`; 819 } 820 821 // Additional rooms para este dia 822 if (day_price.additional_rooms && day_price.additional_rooms.length > 0) { 823 day_price.additional_rooms.forEach((room) => { 824 event_space_services += `<li>Sala adicional - unit: ${room.price_unit} | total: ${room.price_total}</li>`; 825 }); 826 } 827 828 event_space_services += `</ul>`; 829 }); 830 831 debug_html += ` 832 <div class="mb-4"> 833 <h5 class="m-0">Espaços de Evento</h5> 834 <p>Total: ${event_spaces_prices.event_spaces_total}</p> 835 <ul>${event_space_services}</ul> 836 </div> 837 `; 838 } 839 840 // Catering 841 if( 'catering_prices' in calculated_event_prices ) { 842 let catering_prices = calculated_event_prices.catering_prices; 843 844 let catering_services = ``; 845 catering_prices.catering_days.forEach( (catering_day, index) => { 846 let catering_day_services = ``; 847 848 if( 'welcome_coffee' in catering_day ) { 849 catering_day_services += `<li>Welcome coffee - unit: ${ catering_day.welcome_coffee.price_unit } | total: ${ catering_day.welcome_coffee.price_total }</li>`; 850 } 851 852 if( 'coffee_breaks' in catering_day ) { 853 catering_day_services += `<li>Coffee break - unit: ${ catering_day.coffee_breaks.price_unit } | total: ${ catering_day.coffee_breaks.price_total }</li>`; 854 } 855 856 if( 'welcome_drink' in catering_day ) { 857 catering_day_services += `<li>Welcome drink - unit: ${ catering_day.welcome_drink.price_unit } | total: ${ catering_day.welcome_drink.price_total }</li>`; 858 } 859 860 if( 'lunch' in catering_day ) { 861 catering_day_services += `<li>Almoço - unit: ${ catering_day.lunch.price_unit } | total: ${ catering_day.lunch.price_total }</li>`; 862 } 863 864 if( 'canapes' in catering_day ) { 865 catering_day_services += `<li>Canapés - unit: ${ catering_day.canapes.price_unit } | total: ${ catering_day.canapes.price_total }</li>`; 866 } 867 868 if( 'dinner' in catering_day ) { 869 catering_day_services += `<li>Jantar - unit: ${ catering_day.dinner.price_unit } | total: ${ catering_day.dinner.price_total }</li>`; 870 } 871 872 if( 'open_bar' in catering_day ) { 873 catering_day_services += `<li>Bar aberto - unit: ${ catering_day.open_bar.price_unit } | total: ${ catering_day.open_bar.price_total }</li>`; 874 } 875 876 if( 'supper' in catering_day ) { 877 catering_day_services += `<li>Ceia - unit: ${ catering_day.supper.price_unit } | total: ${ catering_day.supper.price_total }</li>`; 878 } 879 880 881 if( catering_day_services.length > 0 ) { 882 catering_services += ` 883<p>Dia ${ (index + 1) }</p> 884<ul>${ catering_day_services }</ul> 885`; 886 } 887 }); 888 889 890 debug_html += ` 891<div class="mb-4"> 892<h5 class="m-0">Catering</h5> 893<p>Total: ${ catering_prices.catering_total }</p> 894 895<div>${ catering_services }</div> 896</div> 897`; 898 } 899 900 // Accommodation 901 if( 'accommodation_prices' in calculated_event_prices ) { 902 let accommodation_prices = calculated_event_prices.accommodation_prices; 903 let number_of_nights = accommodation_prices.number_of_nights; 904 905 let accommodation_services = ``; 906 if( 'single_rooms' in accommodation_prices ) { 907 accommodation_services += `<li>Quartos single - unit: ${ accommodation_prices.single_rooms.price_unit } | total: ${ accommodation_prices.single_rooms.price_total }</li>`; 908 } 909 910 if( 'twin_rooms' in accommodation_prices ) { 911 accommodation_services += `<li>Quartos twin - unit: ${ accommodation_prices.twin_rooms.price_unit } | total: ${ accommodation_prices.twin_rooms.price_total }</li>`; 912 } 913 914 915 debug_html += ` 916<div class="mb-4"> 917<h5 class="m-0">Alojamento</h5> 918<p>Total: ${ accommodation_prices.accommodation_total }</p> 919<p>Noites: ${ number_of_nights }</p> 920 921<ul>${ accommodation_services }</ul> 922</div> 923`; 924 } 925 926 // Audiovisuals 927 if( 'audiovisuals_prices' in calculated_event_prices ) { 928 let audiovisuals_prices = calculated_event_prices.audiovisuals_prices; 929 930 let audiovisual_service = `<li>Serviço - unit: ${ audiovisuals_prices.audiovisual_service.price_unit } | total: ${ audiovisuals_prices.audiovisual_service.price_total }</li>`; 931 932 933 debug_html += ` 934<div class="mb-4"> 935<h5 class="m-0">Audiovisuais</h5> 936<p>Total: ${ audiovisuals_prices.audiovisuals_total }</p> 937 938<ul>${ audiovisual_service }</ul> 939</div> 940`; 941 } 942 } 943 else { 944 debug_html += `<p>Sem informação</p>`; 945 } 946 947 $('#debug-result-container').html( debug_html ); 948 } 949 950 951 } 952 953 954 955 // --- Mostrar o resultado --- 956 // $('#form-ai-result .para-testes').html(JSON.stringify(data, null, 2)); 957 958 let eventTotal = 0; 959 if( ( 'response_endpoint' in data && data.response_endpoint ) && ( 'calculated_event_prices' in data.response_endpoint && data.response_endpoint.calculated_event_prices ) && ( 'event_total' in data.response_endpoint.calculated_event_prices && data.response_endpoint.calculated_event_prices.event_total ) ) { 960 eventTotal = data.response_endpoint.calculated_event_prices.event_total; 961 } 962 963 964 965 // Check URL params 966 if( total_visible ) {
967 eventTotal = parseFloat( eventTotal ).toLocaleString( 'pt-PT', { minimumFractionDigits: 2, maximumFractionDigits: 2 } ); 968 $('#form-ai-result .price-value').html( eventTotal ); 969 } 970 else { 971 $('#form-ai-result .price').html(''); 972 $('#form-ai-result .price').addClass('blured-total-value'); 973 } 974 975 976 if( ! debug_mode ) { 977 $('#form-ai-content').css("display", "none"); 978 $('#form-ai-content').hide(); 979 } 980 981 $('#form-ai-result').css("display", "block"); 982 $('#form-ai-result').show(); 983 984 // Scroll to show the simulation values 985 let scroll_to_form_ai_offset = $('#masthead > nav').outerHeight() + 50; 986 if( $('#wpadminbar').length > 0 ) { 987 scroll_to_form_ai_offset += $('#wpadminbar').outerHeight(); 988 } 989 990 $(document).scrollTop( $("#form-ai-result").offset().top - scroll_to_form_ai_offset ); 991 } 992 // Mostrar erros do registo 993 else { 994 // --- 2. Mostrar novos erros --- 995 if (data.errors && data.errors.input_errors) { 996 const errors = data.errors.input_errors; 997 998 for (const fieldKey in errors) { 999 const message = errors[fieldKey]; 1000 1001 if (fieldKey === 'catering') { 1002 $('#label-inclui-catering').addClass('has-error'); 1003 $('#form-ai-feedback-container').html(`<div class="alert alert-danger" style="color: #dc3545; border: 1px solid #dc3545; padding: 10px; margin-bottom: 15px;">${message}</div>`); 1004 continue; 1005 } 1006 1007 const elementId = fieldKey.replace('_day_', '_'); 1008 const field = $('#' + elementId); 1009 1010 if (field.length > 0) { 1011 field.addClass('is-invalid'); 1012 1013 if (field.hasClass('select2-hidden-accessible')) { 1014 field.next('.select2-container').find('.select2-selection').addClass('is-invalid'); 1015 } 1016 1017 field.next('.invalid-feedback').text(message).addClass('d-block'); 1018 } 1019 } 1020 1021 const firstErrorKey = Object.keys(errors)[0]; 1022 if (firstErrorKey) { 1023 const firstElementId = firstErrorKey.replace('_day_', '_'); 1024 } 1025 } else { 1026 $('#form-ai-feedback-container').html('<div class="alert alert-danger">Ocorreu um erro. Por favor, tente novamente.</div>'); 1027 } 1028 } 1029 }, 1030 error: function( errorThrown ) { 1031 console.log( "Error: ", errorThrown ); 1032 $('#form-ai-validate .error_msg').html("Erro ao processar pedido. Tente novamente"); 1033 }, 1034 complete: function() { 1035 // Reativar o botão, mostrar o texto e esconder o loader 1036 if ($('#form-ai-content').is(':visible')) { 1037 button_text.show(); 1038 button_loader.hide(); 1039 submit_button.attr('disabled', false); 1040 } 1041 } 1042 }); 1043 }); 1044 1045 // ########## Validação de E-mail para o Formulário AI ########## 1046 // 1047 const emailFieldAI = $('#form-ai-result .submit-form input[name="your-email"]'); 1048 1049 // Executa apenas se o campo de email existir na página 1050 if (emailFieldAI.length) { 1051 emailFieldAI.after('<span class="wpcf7-not-valid-tip email-provider-error" style="display:none;"></span>'); 1052 const errorContainer = emailFieldAI.next('.email-provider-error'); 1053 1054 // Função para validar o email 1055 function validateEmailProvider() { 1056 const blocked_providers = $('#form-ai-blocked-email-providers').val().split(','); 1057 const emailValue = emailFieldAI.val(); 1058 1059 if (emailValue) { 1060 let email_parts = emailValue.split('@'); 1061 if (email_parts.length > 1) { 1062 let domain = email_parts[1].toLowerCase(); 1063 1064 if (blocked_providers.includes(domain)) { 1065 errorContainer.text( $('#form-ai-blocked-email-providers-str').val() ); 1066 errorContainer.show(); 1067 return false; 1068 } 1069 } 1070 } 1071 1072 errorContainer.hide(); 1073 return true; 1074 } 1075 1076 emailFieldAI.on('blur', validateEmailProvider); 1077 } 1078 1079 // Substituir resultado por mensagem de sucesso 1080 document.addEventListener( 'wpcf7mailsent', function( event ) { 1081 var targetFormIds = [ 12507, 13537, 13538 ]; 1082 1083 if ( targetFormIds.includes( event.detail.contactFormId ) ) { 1084 setTimeout(function() { 1085 var resultContainer = jQuery('#form-ai-result'); 1086 if (resultContainer.length) { 1087 jQuery('#form-ai-content').hide(); 1088 1089 1090 let msg_title_str = $('#form-ai-client-details-success-title-str').val(); 1091 let msg_text1_str = $('#form-ai-client-details-success-text1-str').val(); 1092 let msg_text2_str = $('#form-ai-client-details-success-text2-str').val(); 1093 1094 let msg_btn_new_simulation_str = $('#form-ai-client-details-success-btn-new-simulation-str').val(); 1095 let msg_btn_back_str = $('#form-ai-client-details-success-btn-back-str').val(); 1096 1097 var successMessageHtml = ` 1098 <div class="form-ai-success-message"> 1099 <h2>${msg_title_str}</h2> 1100 <p>${msg_text1_str}</p> 1101 <p>${msg_text2_str}</p> 1102 1103 <div class="success-buttons-container"> 1104 <a href="${window.location.pathname}" class="btn-success-action primary">${msg_btn_new_simulation_str}</a> 1105 <a href="https://venuesin.pt/" class="btn-success-action secondary">${msg_btn_back_str}</a> 1106 </div> 1107 </div> 1108 `; 1109 resultContainer.html(successMessageHtml).show(); 1110 jQuery('html, body').animate({ 1111 scrollTop: resultContainer.offset().top - 60 1112 }, 500); 1113 } 1114 }, 10); 1115 } 1116 }, false ); 1117
1118 var chart_api_endpoint_url = 'https://quickchart.io/chart'; 1119 1120 var chart_strings; 1121 if( $('#chart-strings').length > 0 ) { 1122 chart_strings = JSON.parse( $('#chart-strings').val() ); 1123 } 1124 1125 var charts_colors = [ 1126 '#9DC5FB', 1127 '#523ABD', 1128 '#7A99EB', 1129 '#5B72DE', 1130 '#575BD0', 1131 '#3E31B2', 1132 '#121D9A', 1133 '#0B1366' 1134 ]; 1135 1136 async function venuesin_generate_and_save_events_price_benchmark_chart( pdata, gdata, chart_data, test=false ) { 1137 let chart_type = 'events_price_benchmark'; 1138 1139 let event_price_per_person = chart_data.event_price_per_person; 1140 let event_min_price_per_person = chart_data.event_min_price_per_person; 1141 let event_max_price_per_person = chart_data.event_max_price_per_person; 1142 1143 let event_price_per_person_label = event_price_per_person.toLocaleString( 'pt-PT', { minimumFractionDigits: 2, maximumFractionDigits: 2 } ) + 'â¬'; 1144 let event_min_price_per_person_label = event_min_price_per_person.toLocaleString( 'pt-PT', { minimumFractionDigits: 2, maximumFractionDigits: 2 } ) + 'â¬'; 1145 let event_max_price_per_person_label = event_max_price_per_person.toLocaleString( 'pt-PT', { minimumFractionDigits: 2, maximumFractionDigits: 2 } ) + 'â¬'; 1146 1147 let min_max_dist = event_max_price_per_person - event_min_price_per_person; 1148 let event_dist = event_price_per_person - event_min_price_per_person; 1149 let event_price_per_person_label_pos_x = Math.round( (event_dist * 100) / min_max_dist ); 1150 1151 let chart_str_price_min = 'Preço MÃnimo'; 1152 let chart_str_price_max = 'Preço Máximo'; 1153 if( chart_strings ) { 1154 chart_str_price_min = 'price_min' in chart_strings && chart_strings.price_min ? chart_strings.price_min : chart_str_price_min; 1155 chart_str_price_max = 'price_max' in chart_strings && chart_strings.price_max ? chart_strings.price_max : chart_str_price_max; 1156 } 1157 1158 1159 let chart_config = { 1160 type: 'bar', 1161 data: { 1162 labels: [''], 1163 datasets: [{ 1164 data: [ 100 ], 1165 backgroundColor: '#9DC5FB', 1166 borderColor: '#000000' 1167 }] 1168 }, 1169 options: { 1170 indexAxis: 'y', 1171 scales: { 1172 x: { 1173 display: false 1174 }, 1175 y: { 1176 display: false 1177 } 1178 }, 1179 plugins: { 1180 legend: { 1181 display: false 1182 }, 1183 annotation: { 1184 clip: false, 1185 common: { 1186 drawTime: 'afterDraw' 1187 }, 1188 annotations: { 1189 low: { 1190 type: 'label', 1191 xValue: 0, 1192 yAdjust: 35, 1193 content: [ event_min_price_per_person_label, chart_str_price_min ], 1194 font: { 1195 family: '"Poppins", Sans-serif', 1196 size: 14, 1197 weight: '500' 1198 }, 1199 color: '#A0A3BD' 1200 }, 1201 high: { 1202 type: 'label', 1203 xValue: 100, 1204 yAdjust: 35, 1205 content: [ event_max_price_per_person_label, chart_str_price_max ], 1206 font: { 1207 family: '"Poppins", Sans-serif', 1208 size: 14, 1209 weight: '500', 1210 }, 1211 color: '#A0A3BD' 1212 }, 1213 arrow: { 1214 type: 'point', 1215 pointStyle: 'circle', 1216 xValue: event_price_per_person_label_pos_x, 1217 yAdjust: 0, 1218 backgroundColor: '#523ABD', 1219 borderColor: '#000000', 1220 borderWidth: 0, 1221 radius: 15 1222 }, 1223 label1: { 1224 type: 'label', 1225 content: [ event_price_per_person_label ], 1226 xValue: event_price_per_person_label_pos_x, 1227 yAdjust: -30, 1228 font: { 1229 family: '"Poppins", Sans-serif', 1230 size: 14, 1231 weight: '500' 1232 }, 1233 color: '#170F49' 1234 } 1235 } 1236 } 1237 }, 1238 layout: { 1239 padding: { 1240 top: 30, 1241 bottom: 40, 1242 left: 50, 1243 right: 50 1244 } 1245 }, 1246 borderWidth: 0, 1247 borderRadius: 20, 1248 borderSkipped: false 1249 } 1250 }; 1251 1252 // Generate chart URL params and final URL 1253 let url_params = encodeURIComponent( JSON.stringify( chart_config ) ); 1254 let chart_url = chart_api_endpoint_url + '?v=4&h=100&c=' + url_params; 1255 1256 if( test === false ) { 1257 let chart_base64_img = await venuesin_get_chart_base64_img( chart_url ); 1258 1259 if( chart_base64_img ) { 1260 venuesin_save_simulation_chart( pdata, gdata, chart_type, chart_data, chart_base64_img ); 1261 } 1262 } 1263 else { 1264 console.log( 'chart_url', chart_url ); 1265 } 1266 } 1267 1268 1269 async function venuesin_generate_and_save_events_price_evolution_by_service_category_chart( pdata, gdata, chart_data, test=false ) { 1270 let chart_type = 'events_price_evolution_by_service_category'; 1271 1272 let labels = [ '2022', '2023', '2024', '2025' ]; 1273
1274 let line_fill = false; 1275 let line_width = 4; 1276 let line_tension = 0; 1277 let point_radius = 6; 1278 1279 let chart_str_audiovisuals = 'Audiovisuais'; 1280 let chart_str_event_spaces = 'Espaços de Evento'; 1281 let chart_str_catering = 'Catering'; 1282 let chart_str_accommodation = 'Alojamento'; 1283 let chart_str_year = 'Ano'; 1284 let chart_str_euros_per_participant = '⬠por Participante'; 1285 if( chart_strings ) { 1286 chart_str_audiovisuals = 'audiovisuals' in chart_strings && chart_strings.audiovisuals ? chart_strings.audiovisuals : chart_str_audiovisuals; 1287 chart_str_event_spaces = 'event_spaces' in chart_strings && chart_strings.event_spaces ? chart_strings.event_spaces : chart_str_event_spaces; 1288 chart_str_catering = 'catering' in chart_strings && chart_strings.catering ? chart_strings.catering : chart_str_catering; 1289 chart_str_accommodation = 'accommodation' in chart_strings && chart_strings.accommodation ? chart_strings.accommodation : chart_str_accommodation; 1290 1291 chart_str_year = 'year' in chart_strings && chart_strings.year ? chart_strings.year : chart_str_year; 1292 chart_str_euros_per_participant = 'euros_per_participant' in chart_strings && chart_strings.euros_per_participant ? chart_strings.euros_per_participant : chart_str_euros_per_participant; 1293 } 1294 1295 1296 let values = []; 1297 if( 'audiovisuals' in chart_data && chart_data.audiovisuals ) { 1298 values.push({ 1299 label: chart_str_audiovisuals, 1300 data: chart_data.audiovisuals, 1301 borderColor: '#9DC5FB', 1302 backgroundColor: '#9DC5FB', 1303 fill: line_fill, 1304 borderWidth: line_width, 1305 lineTension: line_tension, 1306 pointRadius: point_radius 1307 }); 1308 } 1309 1310 if( 'event_spaces' in chart_data && chart_data.event_spaces ) { 1311 values.push({ 1312 label: chart_str_event_spaces, 1313 data: chart_data.event_spaces, 1314 borderColor: '#523ABD', 1315 backgroundColor: '#523ABD', 1316 fill: line_fill, 1317 borderWidth: line_width, 1318 lineTension: line_tension, 1319 pointRadius: point_radius 1320 }); 1321 } 1322 1323 if( 'catering' in chart_data && chart_data.catering ) { 1324 values.push({ 1325 label: chart_str_catering, 1326 data: chart_data.catering, 1327 borderColor: '#5B72DE', 1328 backgroundColor: '#5B72DE', 1329 fill: line_fill, 1330 borderWidth: line_width, 1331 lineTension: line_tension, 1332 pointRadius: point_radius 1333 }); 1334 } 1335 1336 if( 'accommodation' in chart_data && chart_data.accommodation ) { 1337 values.push({ 1338 label: chart_str_accommodation, 1339 data: chart_data.accommodation, 1340 borderColor: '#121D9A', 1341 backgroundColor: '#121D9A', 1342 fill: line_fill, 1343 borderWidth: line_width, 1344 lineTension: line_tension, 1345 pointRadius: point_radius 1346 }); 1347 } 1348 1349 1350 let chart_config = { 1351 type: 'line', 1352 data: { 1353 labels: labels, 1354 datasets: values 1355 }, 1356 options: { 1357 scales: { 1358 x: { 1359 display: true, 1360 title: { 1361 display: true, 1362 text: chart_str_year, 1363 font: { 1364 family: '"Poppins", Sans-serif', 1365 size: 14, 1366 weight: 500 1367 }, 1368 color: '#A0A3BD' 1369 }, 1370 ticks: { 1371 font: { 1372 family: '"Poppins", Sans-serif', 1373 size: 14, 1374 weight: 500 1375 }, 1376 color: '#A0A3BD' 1377 }, 1378 grid: { 1379 display: false, 1380 }, 1381 border: { 1382 display: false 1383 } 1384 }, 1385 y: { 1386 display: true, 1387 beginAtZero: false, 1388 suggestedMin: 70, 1389 title: { 1390 display: true, 1391 text: chart_str_euros_per_participant, 1392 font: { 1393 family: '"Poppins", Sans-serif', 1394 size: 14, 1395 weight: 500 1396 }, 1397 color: '#A0A3BD' 1398 }, 1399 ticks: { 1400 maxTicksLimit: 10, 1401 font: { 1402 family: '"Poppins", Sans-serif', 1403 size: 14, 1404 weight: 500 1405 }, 1406 color: '#A0A3BD' 1407 }, 1408 grid: { 1409 display: false, 1410 }, 1411 border: { 1412 display: false 1413 } 1414 } 1415 }, 1416 plugins: { 1417 legend: { 1418 display: true, 1419 position: 'bottom', 1420 labels: { 1421 usePointStyle: true, 1422 pointStyle: 'rectRounded', 1423 padding: 20, 1424 boxWidth: 6, 1425 boxHeight: 6, 1426 font: { 1427 family: '"Poppins", Sans-serif', 1428 size: 14, 1429 weight: 500 1430 }, 1431 color: '#A0A3BD' 1432 } 1433 } 1434 } 1435 } 1436 }; 1437 1438 // Generate chart URL params and final URL 1439 let url_params = encodeURIComponent( JSON.stringify( chart_config ) ); 1440 let chart_url = chart_api_endpoint_url + '?v=4&c=' + url_params; 1441 1442 if( test === false ) { 1443 let chart_base64_img = await venuesin_get_chart_base64_img( chart_url ); 1444 1445 if( chart_base64_img ) { 1446 venuesin_save_simulation_chart( pdata, gdata, chart_type, chart_data, chart_base64_img ); 1447 } 1448 } 1449 else { 1450 console.log( 'chart_url', chart_url ); 1451 } 1452 } 1453 1454 1455 function stringifyWithFunctions(obj) { 1456 const json = JSON.stringify(obj, (key, value) => { 1457 if (typeof value === 'function') return value.toString(); 1458 return value; 1459 }, 0); 1460 1461 // Remove as aspas que envolviam as funções (ficaram como strings) 1462 return json.replace(/"function\s*\([^)]*\)\s*\{[\s\S]*?\}"/g, match =>
1463 match.slice(1, -1) // tira as aspas do inÃcio e do fim 1464 ); 1465 } 1466 1467 1468 async function venuesin_generate_and_save_events_by_venue_typology_chart( pdata, gdata, chart_data, test=false ) { 1469 let chart_type = 'events_by_venue_typology'; 1470 1471 let labels = Object.keys( chart_data ); 1472 let values = Object.values( chart_data ); 1473 1474 // Translate labels 1475 if( chart_strings ) { 1476 let translated_labels = []; 1477 1478 labels.forEach( ( label, index ) => { 1479 if( label in chart_strings ) { 1480 labels[index] = chart_strings[label]; 1481 } 1482 }); 1483 } 1484 1485 1486 let chart_config = { 1487 type: 'doughnut', 1488 data: { 1489 labels: labels, 1490 datasets: [ 1491 { 1492 label: 'Dataset 1', 1493 data: values, 1494 backgroundColor: charts_colors 1495 } 1496 ] 1497 }, 1498 options: { 1499 cutout: '80%', 1500 elements: { 1501 arc: { 1502 borderWidth: 0 1503 } 1504 }, 1505 plugins: { 1506 legend: { 1507 display: true, 1508 position: 'bottom', 1509 labels: { 1510 usePointStyle: true, 1511 pointStyle: 'rectRounded', 1512 padding: 20, 1513 boxWidth: 8, 1514 boxHeight: 8, 1515 font: { 1516 family: '"Poppins", Sans-serif', 1517 size: 14, 1518 weight: 500 1519 }, 1520 color: '#A0A3BD' 1521 } 1522 }, 1523 datalabels: { 1524 font: { 1525 family: '"Poppins", Sans-serif', 1526 size: 14, 1527 weight: 'bold' 1528 }, 1529 color: '#ffffff', 1530 formatter: function(value) { return value + '%'; } 1531 } 1532 } 1533 } 1534 }; 1535 1536 // Generate chart URL params and final URL 1537 let url_params = encodeURIComponent( stringifyWithFunctions( chart_config ) ); 1538 let chart_url = chart_api_endpoint_url + '?v=4&c=' + url_params; 1539 1540 if( test === false ) { 1541 let chart_base64_img = await venuesin_get_chart_base64_img( chart_url ); 1542 1543 if( chart_base64_img ) { 1544 venuesin_save_simulation_chart( pdata, gdata, chart_type, chart_data, chart_base64_img ); 1545 } 1546 } 1547 else { 1548 console.log( 'chart_url', chart_url ); 1549 } 1550 } 1551 1552 1553 async function venuesin_generate_and_save_events_by_venue_region_chart_bar( pdata, gdata, chart_data, test=false ) { 1554 let chart_type = 'events_by_venue_region'; 1555 1556 let labels = Object.keys( chart_data ); 1557 let values = Object.values( chart_data ); 1558 1559 // Translate labels 1560 if( chart_strings ) { 1561 let translated_labels = []; 1562 1563 labels.forEach( ( label, index ) => { 1564 if( label in chart_strings ) { 1565 labels[index] = chart_strings[label]; 1566 } 1567 }); 1568 } 1569 1570 1571 let chart_str_event_percentage = '% de Eventos'; 1572 if( chart_strings ) { 1573 chart_str_event_percentage = 'event_percentage' in chart_strings && chart_strings.event_percentage ? chart_strings.event_percentage : chart_str_event_percentage; 1574 } 1575 1576 1577 let chart_config = { 1578 type: 'bar', 1579 data: { 1580 labels: labels, 1581 datasets: [ 1582 { 1583 label: 'Dataset 1', 1584 data: values, 1585 backgroundColor: '#501EA6' 1586 } 1587 ] 1588 }, 1589 options: { 1590 scales: { 1591 x: { 1592 display: true, 1593 border: { 1594 display: false 1595 }, 1596 grid: { 1597 display: false, 1598 } 1599 }, 1600 y: { 1601 display: true, 1602 border: { 1603 display: false 1604 }, 1605 grid: { 1606 display: false, 1607 }, 1608 title: { 1609 display: true, 1610 text: chart_str_event_percentage 1611 }, 1612 suggestedMin: 0, 1613 ticks: { 1614 maxTicksLimit: 10 1615 } 1616 } 1617 }, 1618 plugins: { 1619 legend: { 1620 display: false 1621 } 1622 }, 1623 font: { 1624 family: '"Poppins", Sans-serif' 1625 }, 1626 borderRadius: 14 1627 } 1628 }; 1629 1630 // Generate chart URL params and final URL 1631 let url_params = encodeURIComponent( JSON.stringify( chart_config ) ); 1632 let chart_url = chart_api_endpoint_url + '?v=4&c=' + url_params; 1633 1634 if( test === false ) { 1635 let chart_base64_img = await venuesin_get_chart_base64_img( chart_url ); 1636 1637 if( chart_base64_img ) { 1638 venuesin_save_simulation_chart( pdata, gdata, chart_type, chart_data, chart_base64_img ); 1639 } 1640 } 1641 else { 1642 console.log( 'chart_url', chart_url ); 1643 } 1644 } 1645 1646 1647 async function venuesin_generate_and_save_events_by_venue_region_chart_polar( pdata, gdata, chart_data, test=false ) { 1648 let chart_type = 'events_by_venue_region'; 1649 1650 let labels = Object.keys( chart_data ); 1651 let values = Object.values( chart_data ); 1652 1653 // Translate labels 1654 if( chart_strings ) { 1655 let translated_labels = []; 1656
1657 labels.forEach( ( label, index ) => { 1658 if( label in chart_strings ) { 1659 labels[index] = chart_strings[label]; 1660 } 1661 }); 1662 } 1663 1664 1665 // Opacity - see https://stackoverflow.com/questions/69683716/transparent-css-hex-value 1666 let hex_opacity = '80'; 1667 1668 let background_colors = []; 1669 charts_colors.forEach( (color) => { 1670 background_colors.push( color + hex_opacity ); 1671 }); 1672 1673 1674 let chart_config = { 1675 type: 'polarArea', 1676 data: { 1677 labels: labels, 1678 datasets: [ 1679 { 1680 label: 'Dataset 1', 1681 data: values, 1682 backgroundColor: background_colors 1683 } 1684 ] 1685 }, 1686 options: { 1687 plugins: { 1688 legend: { 1689 display: true, 1690 position: 'bottom', 1691 labels: { 1692 usePointStyle: true, 1693 pointStyle: 'rectRounded', 1694 padding: 20, 1695 boxWidth: 8, 1696 boxHeight: 8, 1697 font: { 1698 family: '"Poppins", Sans-serif', 1699 size: 14, 1700 weight: 500 1701 }, 1702 color: '#A0A3BD' 1703 } 1704 }, 1705 datalabels: { 1706 font: { 1707 family: '"Poppins", Sans-serif', 1708 size: 14, 1709 weight: 'bold', 1710 }, 1711 color: '#ffffff', 1712 borderWidth: 0, 1713 formatter: function(value) { return value + '%'; } 1714 } 1715 }, 1716 borderWidth: 2, 1717 borderRadius: 0 1718 } 1719 }; 1720 1721 // Generate chart URL params and final URL 1722 let url_params = encodeURIComponent( stringifyWithFunctions( chart_config ) ); 1723 let chart_url = chart_api_endpoint_url + '?v=4&c=' + url_params; 1724 1725 if( test === false ) { 1726 let chart_base64_img = await venuesin_get_chart_base64_img( chart_url ); 1727 1728 if( chart_base64_img ) { 1729 venuesin_save_simulation_chart( pdata, gdata, chart_type, chart_data, chart_base64_img ); 1730 } 1731 } 1732 else { 1733 console.log( 'chart_url', chart_url ); 1734 } 1735 } 1736 1737 1738 function generate_and_save_simulation_charts( pdata, gdata, charts_info, test=false ) { 1739 /* Create charts */ 1740 1741 // Events price benchmark 1742 if( 'events_price_benchmark' in charts_info && charts_info.events_price_benchmark ) { 1743 venuesin_generate_and_save_events_price_benchmark_chart( pdata, gdata, charts_info.events_price_benchmark, test ); 1744 } 1745 1746 // Events price evolution by service category 1747 if( 'events_price_evolution_by_category' in charts_info && charts_info.events_price_evolution_by_category ) { 1748 venuesin_generate_and_save_events_price_evolution_by_service_category_chart( pdata, gdata, charts_info.events_price_evolution_by_category, test ); 1749 } 1750 1751 // Events by Venue Typology 1752 if( 'events_by_venue_typology' in charts_info && charts_info.events_by_venue_typology ) { 1753 venuesin_generate_and_save_events_by_venue_typology_chart( pdata, gdata, charts_info.events_by_venue_typology, test ); 1754 } 1755 1756 // Events by Venue Region 1757 if( 'events_by_venue_region' in charts_info && charts_info.events_by_venue_region ) { 1758// venuesin_generate_and_save_events_by_venue_region_chart_bar( pdata, gdata, charts_info.events_by_venue_region, test ); 1759 venuesin_generate_and_save_events_by_venue_region_chart_polar( pdata, gdata, charts_info.events_by_venue_region, test ); 1760 } 1761 } 1762 1763 1764 async function venuesin_get_chart_base64_img( chart_url ) { 1765 let chart_request_result = await fetch( chart_url ); 1766 1767 if( chart_request_result.ok ) { 1768 let data_blob = await chart_request_result.blob(); 1769 1770 // Convert blob to base64 1771 if( data_blob.size > 0 ) { 1772 return new Promise( (resolve, reject) => { 1773 let file_reader = new FileReader(); 1774 file_reader.onloadend = function() { 1775 resolve( file_reader.result ); 1776 } 1777 file_reader.readAsDataURL( data_blob ); 1778 }); 1779 } 1780 } 1781 1782 return false; 1783 } 1784 1785 1786 function venuesin_save_simulation_chart( pdata, gdata, chart_type, chart_data, chart_base64_img ) { 1787 let form_data = new FormData(); 1788 form_data.append( 'action', 'update_v_ai_simulation_chart' ); 1789 form_data.append( 'nonce', ajax_var.nonce ); 1790 form_data.append( 'pdata', pdata ); 1791 form_data.append( 'gdata', gdata ); 1792 form_data.append( 'chart_type', chart_type ); 1793 form_data.append( 'chart_data', JSON.stringify(chart_data) ); 1794 form_data.append( 'chart_base64_img', chart_base64_img ); 1795 1796 $.ajax({ 1797 type: 'POST', 1798 dataType: 'json', 1799 contentType: false, 1800 processData: false, 1801 url: ajax_var.url, 1802 data: form_data, 1803 success: function( data ) { 1804 console.log( 'venuesin_save_simulation_chart_AJAX', data ); 1805 }, 1806 error: function( errorThrown ) { 1807 console.log( "Error: ", errorThrown ); 1808 } 1809 }); 1810 } 1811 1812 1813 $('#test-ai-charts').on( 'click', function() { 1814 let test = true; 1815 1816 let pdata = '12972'; 1817 let gdata = 'A92B3098-AA97-4F3B-A181-5E2E3D1B4794'; 1818 1819 let test_events_price_benchmark_chart = true; 1820 let test_events_price_evolution_by_category_chart = false;
1821 let test_events_by_venue_typology_chart = false; 1822 let test_events_by_venue_region_chart = false; 1823 1824 let charts_info = {}; 1825 1826 if( test_events_price_benchmark_chart ) { 1827 // charts_info.events_price_benchmark = { 1828 // 'event_price_per_person': 347.6, 1829 // 'event_min_price_per_person': 275.4, 1830 // 'event_max_price_per_person': 495.8 1831 // }; 1832 1833 charts_info.events_price_benchmark = { 1834 'event_price_per_person': 489.3, 1835 'event_min_price_per_person': 165, 1836 'event_max_price_per_person': 552.91 1837 }; 1838 } 1839 1840 if( test_events_price_evolution_by_category_chart ) { 1841 charts_info.events_price_evolution_by_category = { 1842 'event_spaces': [ 102, 112, 122, 133 ], 1843 'catering': [ 120, 130, 137, 143 ], 1844 'accommodation': [ 145, 159, 163, 171 ], 1845 'audiovisuals': [ 80, 97, 100, 103 ] 1846 }; 1847 } 1848 1849 if( test_events_by_venue_typology_chart ) { 1850 charts_info.events_by_venue_typology = { 1851 'Hotel': 98, 1852 'Congress Centre': 2 1853 }; 1854 } 1855 1856 if( test_events_by_venue_region_chart ) { 1857 charts_info.events_by_venue_region = { 1858 'Centre': 48, 1859 'Greater Lisbon': 42, 1860 'West': 10 1861 }; 1862 } 1863 1864 1865 generate_and_save_simulation_charts( pdata, gdata, charts_info, test ); 1866 }); 1867 1868 1869 1870 // ########## Chefs validation ########## 1871 1872 $('#form-chefs-validate').on('submit', function(e) { 1873 e.preventDefault(); 1874 1875 // Obter dados do form 1876 let form_data = new FormData( $(this)[0] ); 1877 form_data.append( 'nonce', ajax_var.nonce ); 1878 1879 let submit_button = $('#form-chefs-validate input[type="submit"]'); 1880 $(submit_button).attr('disabled', true); 1881 1882 $('#form-chefs-validate .error_msg').html(""); 1883 1884 1885 $.ajax({ 1886 type: 'POST', 1887 dataType: 'json', 1888 contentType: false, 1889 processData: false, 1890 url: ajax_var.url, 1891 data: form_data, 1892 success: function( data ) { 1893 1894 // Caso o registo seja bem sucedido 1895 if( data.success === 'true' ) { 1896 $('#chefs-form-content').html(data.content); 1897 $('.chefs-grow-bg').hide(); 1898 wpcf7.init($('#chefs-form-content form')[0]); 1899 1900 } 1901 // Mostrar erros do registo 1902 else { 1903 if ("message" in data) { 1904 $('#form-chefs-validate .error_msg').html(data.message); 1905 } 1906 } 1907 1908 $(submit_button).attr('disabled', false); 1909 }, 1910 error: function( errorThrown ) { 1911 1912 $(submit_button).attr('disabled', false); 1913 1914 console.log( "Error: ", errorThrown ); 1915 $('#form-chefs-validate .error_msg').html("Erro ao processar pedido. Tente novamente"); 1916 1917 } 1918 }); 1919 }); 1920 1921 1922 // ########## Premio Exclusivo ########## 1923 1924 function get_success_form_alert_html( message ) { 1925 let alert_html = '<div class="alert alert-success">'; 1926 alert_html += feather.icons['check'].toSvg({ class: 'mr-2' }) + '<span>' + message + '</span>'; 1927 alert_html += '</div>'; 1928 1929 return alert_html; 1930 } 1931 1932 1933 function get_error_form_alert_html( message ) { 1934 let alert_html = '<div class="alert alert-danger">'; 1935 alert_html += feather.icons['alert-circle'].toSvg({ class: 'mr-2' }) + '<span>' + message + '</span>'; 1936 alert_html += '</div>'; 1937 1938 return alert_html; 1939 } 1940 1941 1942 // Capture the wheel spin animation end 1943 $('.ruleta').on("animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd", function( e ) { 1944 // Check if it's the spinning animation 1945 if( 'originalEvent' in e && 'animationName' in e.originalEvent && e.originalEvent.animationName === 'animacion' ) { 1946 // $('#roleta-container').fadeTo( 1000, 0, function() { 1947 // $('#oferta').fadeIn(1000); 1948 // }); 1949 1950 $('#premio-exclusivo-title').fadeOut(1000); 1951 $('#roleta-container').fadeOut( 1000, function() { 1952 $('#oferta').fadeIn(1000); 1953 }); 1954 } 1955 }); 1956 1957 1958 // Validar participação no Prémio Exclusivo 1959 if( $('#form-premio-exclusivo').length ) { 1960 var blocked_email_providers = $('#form-premio-exclusivo-blocked-email-providers').val().split(','); 1961 var blocked_email_providers_aux = blocked_email_providers.slice(); 1962 1963 var last_blocked_email_provider = ''; 1964 if( blocked_email_providers_aux.length > 1 ) { 1965 last_blocked_email_provider = blocked_email_providers_aux.pop(); 1966 last_blocked_email_provider = last_blocked_email_provider ? ' e ' + last_blocked_email_provider : last_blocked_email_provider; 1967 } 1968 var blocked_email_providers_string = blocked_email_providers_aux.join(', ') + last_blocked_email_provider; 1969 1970 // Add custom email validation rule
1971 $.validator.addMethod('valid_email', function( value, element ) { 1972 let user_email_provider = value.split('@'); 1973 user_email_provider = user_email_provider[1].split('.'); 1974 user_email_provider = user_email_provider[0]; 1975 1976 if( blocked_email_providers.includes( user_email_provider ) ) { 1977 return false; 1978 } 1979 else { 1980 return true; 1981 } 1982 }); 1983 1984 1985 // Validate form submition 1986 $('#form-premio-exclusivo').validate( { 1987 rules: { 1988 'nome': { 1989 required: true 1990 }, 1991 'empresa': { 1992 required: true 1993 }, 1994 'email': { 1995 required: true, 1996 email: true, 1997 valid_email: true 1998 }, 1999 'telefone': { 2000 required: true 2001 }, 2002 'aceito-contato-venuesin': { 2003 required: true 2004 }, 2005 'aceito-termos-condicoes': { 2006 required: true 2007 } 2008 }, 2009 messages: { 2010 'nome': { 2011 required: 'Este campo é obrigatório' 2012 }, 2013 'empresa': { 2014 required: 'Este campo é obrigatório' 2015 }, 2016 'email': { 2017 required: 'Este campo é obrigatório', 2018 email: 'Por favor introduza um email válido', 2019 valid_email: 'Não são permitidos emails ' + blocked_email_providers_string 2020 }, 2021 'telefone': { 2022 required: 'Este campo é obrigatório' 2023 }, 2024 'aceito-contato-venuesin': { 2025 required: 'Este campo é obrigatório' 2026 }, 2027 'aceito-termos-condicoes': { 2028 required: 'Este campo é obrigatório' 2029 } 2030 }, 2031 errorPlacement: function( error, element ) { 2032 // Telephone input with the International Telephone Input JS library 2033 if( element.hasClass('show-phone-country-code') ) { 2034 $(element).parents('.form-group').get(0).append( error.get(0) ); 2035 } 2036 // Checkboxes 2037 else if( element.attr('type') === 'checkbox' ) { 2038 $(element).parents('.form-check').get(0).append( error.get(0) ); 2039 } 2040 // Other inputs 2041 else { 2042 error.insertAfter( element ); 2043 } 2044 }, 2045 submitHandler: function( form, event ) { 2046 // Impedir submit default (caso haja um erro, o "return false" não previne o submit) 2047 event.preventDefault(); 2048 2049 // 2050 let container_form = $('#formulario'); 2051 let container_roleta = $('#roleta-container'); 2052 2053 // Prevent additional submits 2054 let submit_button = $('#form-premio-exclusivo-submit'); 2055 $(submit_button).attr('disabled', true); 2056 $(submit_button).addClass('loading'); 2057 2058 let validator = this; 2059 let feedback_container = $('#form-premio-exclusivo-feedback-container'); 2060 2061 let form_data = new FormData( $(form)[0] ); 2062 2063 $.ajax({ 2064 type: 'POST', 2065 dataType: 'json', 2066 contentType: false, 2067 processData: false, 2068 url: ajax_var.url, 2069 data: form_data, 2070 success:function( data ) { 2071 console.log( 'form submit: ', data ); 2072 2073 // Submition succeeded 2074 if( data.result === 'success' ) { 2075 // feedback_container.html( get_success_form_alert_html( data.success_message.message ) ); 2076 2077 // Trigger wheel spin 2078 // rotateRolate(); 2079 2080 // Hide form 2081 container_form.fadeOut( 1000, function() { 2082 container_roleta.fadeIn( 1000, function() { 2083 // rotateRolate(); 2084 }).css( 'display', 'flex' ); 2085 }); 2086 } 2087 // Show errors 2088 else { 2089 // General error 2090 if( data.errors.general_error.message ) { 2091 feedback_container.html( get_error_form_alert_html( data.errors.general_error.message ) ); 2092 } 2093 2094 // Input errors 2095 if( data.errors.input_errors ) { 2096 validator.showErrors( data.errors.input_errors ); 2097 } 2098 2099 // Permit new submitions 2100 $(submit_button).removeClass('loading'); 2101 $(submit_button).attr('disabled', false); 2102 } 2103 }, 2104 error: function( errorThrown ) { 2105 feedback_container.html( get_error_form_alert_html( 'Ocorreu um erro ao validar a sua participação. Por favor tente novamente' ) ); 2106 2107 // Permit new submitions 2108 $(submit_button).removeClass('loading'); 2109 $(submit_button).attr('disabled', false); 2110 2111 // console.log( "Error: ", errorThrown ); 2112 } 2113 }); 2114 2115 // Retornar false uma vez que o submit default foi alterado 2116 return false; 2117 } 2118 } ); 2119 } 2120 2121 2122 // 2123 $('#btn-premio-exclusivo-view-gift').on( 'click', function(e) { 2124 e.preventDefault(); 2125 2126 rotateRolate(); 2127 }); 2128 2129 2130 // Initialize phone country codes 2131 function initialize_phone_country_codes( country_code_phone_inputs ) { 2132 // For each input
2133 country_code_phone_inputs.forEach( (country_code_phone_input) => { 2134 let disabled = $(country_code_phone_input).is(":disabled"); 2135 let preferred_countries = ['pt', 'es', 'us', 'uk']; 2136 2137 let intl_tel_input = window.intlTelInput(country_code_phone_input, { 2138 utilsScript: 'https://cdn.jsdelivr.net/npm/[email protected]/build/js/utils.js', 2139 containerClass: 'show-phone-country-code-container', 2140 allowDropdown: disabled === false ? true : false, 2141 countrySearch: false, 2142 initialCountry: 'pt', 2143 preferredCountries: preferred_countries, 2144 showSelectedDialCode: true, 2145 nationalMode: false 2146 }); 2147 2148 // Register events 2149 if( disabled === false ) { 2150 $(country_code_phone_input).on('countrychange input', function() { 2151 let full_phone_number = intl_tel_input.getNumber(); 2152 $( '#' + $(this).attr('id') + '-full' ).val( full_phone_number ); 2153 }); 2154 } 2155 }); 2156 } 2157 2158 // Initialize phone country codes 2159 if( $('.show-phone-country-code').length > 0 ) { 2160 let country_code_phone_inputs = document.querySelectorAll('.show-phone-country-code'); 2161 initialize_phone_country_codes( country_code_phone_inputs ); 2162 } 2163 2164 2165 var multiplicador = 7; 2166 2167 /*$('.ruleta').click(function(){ 2168 rotateRolate(); 2169 })*/ 2170 2171 2172 function rotateRolate() { 2173 //$('body').css('background-color', 'var(--bg-cont-b'); 2174 $('.ruleta').css('pointer-events', 'none'); 2175 $('.colores').removeClass('animacion'); 2176 var color = colorAleatorio(1, 360); 2177 2178 $('#animacion').empty().append( 2179 '@keyframes animacion{'+ 2180 '0%{transform: rotate(0deg)}'+ 2181 '100%{transform: rotate('+color+'deg)}'+ 2182 '}' 2183 ); 2184 2185 2186 2187 setTimeout(function(){ 2188 $('.colores').addClass('animacion') 2189 //$('.colores').css('animation', 'animacion 4s ease-out forwards'); 2190 },1) 2191 2192 setTimeout(function(){ 2193 if(color > 0 && color <= (90 + (360 * multiplicador))){ 2194 $('#nha-body').css('background-color', 'var(--bg-b)') 2195 2196 }else if(color > (90 + (360 * multiplicador)) && color <= (180 + (360 * multiplicador))){ 2197 $('#nha-body').css('background-color', 'var(--bg-y)') 2198 2199 }else if(color > (180 + (360 * multiplicador)) && color <= (270 + (360 * multiplicador))){ 2200 $('#nha-body').css('background-color', 'var(--bg-g)') 2201 2202 }else if(color > (270 + (360 * multiplicador))){ 2203 $('#nha-body').css('background-color', 'var(--bg-r)') 2204 } 2205 2206 $('.ruleta').css('pointer-events', 'initial'); 2207 },4000); 2208 } 2209 2210 2211 function colorAleatorio(min, max) { 2212 var colorAleatorio = ((Math.random() * (max - min) + min).toFixed(0))*1; 2213 colorAleatorio = colorAleatorio + (360 * multiplicador); 2214 return colorAleatorio; 2215 } 2216 2217 2218 /* Envelope */ 2219 2220 openEnvelope(); 2221 2222 function openEnvelope() { 2223 $('#envelope').addClass("open").removeClass("close"); 2224 } 2225 2226 2227 // Show Feather Icons 2228 feather.replace(); 2229 2230 // 2231 const swiper = new Swiper('.swiper', { 2232 loop: true, 2233 slidesPerView: 1, 2234 spaceBetween: 10, 2235 pagination: { 2236 el: '.swiper-pagination', 2237 }, 2238 navigation: { 2239 nextEl: '.swiper-button-next', 2240 prevEl: '.swiper-button-prev', 2241 } 2242 }); 2243 2244})( jQuery ); 2245 2246// Anexar Ficheiros 2247document.addEventListener('DOMContentLoaded', function() { 2248 2249 // Seleção de elementos 2250 var fileInput = document.getElementById('anexar-ficheiro'); 2251 var customBtn = document.querySelector('.add-file-btn'); 2252 var fileListDisplay = document.getElementById('lista-anexos'); 2253 var clearBtn = document.getElementById('limpar-anexos'); 2254 var maxSizeMsg = document.querySelector('.max-file-size'); 2255 2256 if(fileInput && customBtn && fileListDisplay) { 2257 2258 // Forçar multiple 2259 fileInput.setAttribute('multiple', 'multiple'); 2260 2261 customBtn.addEventListener('click', function() { 2262 fileInput.click(); 2263 }); 2264 2265 fileInput.addEventListener('change', function() { 2266 fileListDisplay.innerHTML = ''; 2267 2268 if (this.files.length > 0) { 2269 if(maxSizeMsg) maxSizeMsg.style.display = 'none'; 2270 2271 var ul = document.createElement('ul'); 2272 ul.style.listStyle = 'none'; 2273 ul.style.padding = '0'; 2274 ul.style.fontSize = '12px'; 2275 ul.style.marginTop = '10px'; 2276
2277 // Contador de ficheiros 2278 var info = document.createElement('p'); 2279 info.style.fontWeight = 'bold'; 2280 info.textContent = this.files.length + ' ficheiros selecionados:'; 2281 fileListDisplay.appendChild(info); 2282 2283 // Listar nomes 2284 for (var i = 0; i < this.files.length; i++) { 2285 var li = document.createElement('li'); 2286 li.innerHTML = '<span style="margin-right:5px">ð</span>' + this.files[i].name; 2287 li.style.marginBottom = '3px'; 2288 ul.appendChild(li); 2289 } 2290 2291 fileListDisplay.appendChild(ul); 2292 if(clearBtn) clearBtn.style.display = 'block'; 2293 } else { 2294 // Se o utilizador cancelar a seleção na janela 2295 if(clearBtn) clearBtn.style.display = 'none'; 2296 if(maxSizeMsg) maxSizeMsg.style.display = 'block'; 2297 } 2298 }); 2299 2300 // Botão de limpar tudo 2301 if(clearBtn) { 2302 clearBtn.addEventListener('click', function() { 2303 fileInput.value = ''; 2304 fileListDisplay.innerHTML = ''; 2305 clearBtn.style.display = 'none'; 2306 2307 if(maxSizeMsg) maxSizeMsg.style.display = 'block'; 2308 }); 2309 } 2310 } 2311});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.