templates/questionnaires/frontOffice/quiz.html.twig line 1

Open in your IDE?
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
  7.     <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css">
  8.     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
  9.     <link rel="stylesheet" href="{{ asset('assets/css/quiz-front.css') }}">
  10.     <title>Quiz Front Page</title>
  11. </head>
  12. <style id="dynamic-css"></style>
  13. <style>
  14. </style>
  15. <body style="background: {% if questionnaire.getCodeCouleur() is not empty %}{{ 'background-color: ' ~ questionnaire.getCodeCouleur() ~ ' !important;' }}{% else %}url('/images/FOND-QUIZZ.png') center center fixed no-repeat; background-size: cover;{% endif %}"> 
  16.     <header class="d-none"> <span id="quizHeader">{{questionnaire.header}} </span> - <span id="headerGeneral">{{HeaderGeneral}}</span></header>
  17.         <script type="text/javascript">
  18.                document.addEventListener("DOMContentLoaded", function() {
  19.                     const elem = document.getElementById("headerGeneral").innerText;
  20.                     const quizheader = document.getElementById("quizHeader").innerText;
  21.                     const formattedCode = `
  22.                     ${elem}
  23.                     ${quizheader}
  24.                     `;
  25.                     if (elem.trim().startsWith("<style")) {
  26.                         const dynamicCss = elem;
  27.                         const cssContent = elem.replace(/<style[^>]*>/, '').replace(/<\/style>/, '');
  28.                         document.getElementById("dynamic-css").innerHTML = cssContent;
  29.                     } else {
  30.                         eval(formattedCode);
  31.                 }
  32.         });
  33.         </script>
  34.         <div class="quiz-container">
  35.             <div class="image-container">
  36.                 <img src="https://akoyaconfig.services-unifies.fr/uploads/logo/logo.png" alt="Akoya Logo" class="brand-image elevation-3 mb-3 " style="opacity: .8; width: 33%;">
  37.                 <img src="{{ asset('/uploads/quiz/' ~ questionnaire.getImgPrincipale()) }}" alt="Questionnaire Image" class="questionnaire-image mainimg image_quiz">
  38.             </div>
  39.             <div class="congrats-container texte_done m-5 d-none">
  40.                     <h2>Félicitations ! Voici votre résultat basé sur vos réponses :</h2>
  41.             </div>
  42.             <input type="hidden" id="quizId" name="quizId" value="{{ questionnaire.id }}">
  43.             <div class="content-container">
  44.                 <div class="title-stepper">
  45.                 <div class="progress-container">
  46.                         <div class="progress-bar"></div>
  47.                         <div class="stepper">
  48.                             {% for question in questionnaire.questions %}
  49.                                 <div style="background-color: {{ questionnaire.getCouleurContraste() }};" class="step">{{ loop.index }}</div>
  50.                             {% endfor %}
  51.                         </div>
  52.                     </div>
  53.                    
  54.                 </div>
  55.                  <img src="https://akoyaconfig.services-unifies.fr/uploads/logo/logo.png" alt="Akoya Logo" class="after d-none" style="opacity: .8; width: 33%;">
  56.                 <div id="loader" class="loader"></div>
  57.                 <div class="question-container" style="display: none;">
  58.                     <h2 class="question"></h2>
  59.                     <div class="body">
  60.                         <ul class="sortable-list list-group" data-questionnaire-id="{{ questionnaire.id }}">
  61.                             {% for question in questionnaire.questions %}
  62.                                 <li class="list-group-item mb-4 p-4 border border-secondary question-item" data-num-responses="{{ question.numResponses }}">
  63.                                     <div class="mb-3">
  64.                                         <p class="font-weight-bold">{{ question.question }}</p>
  65.                                         <span    style="color: {{ questionnaire.getCouleurContraste() }};" >{% if question.numResponses > 1 %}
  66.                                             Choisir <b>{{ question.numResponses }}</b> options
  67.                                             {% else %}
  68.                                                 Choisir <b>{{ question.numResponses }}</b> option
  69.                                             {% endif %}
  70.                                         </span>
  71.                                     </div>
  72.                                     <input type="hidden" id="{{ question.id }}" value="{{ question.numResponses }}" />
  73.                                     <ul class="pl-4">
  74.                                         {% for questionReponse in question.reponses %}
  75.                                             <li style="list-style: none !important;">
  76.                                                 <div class="mb-2">
  77.                                                     <div class="form-check">
  78.                                                         <input type="checkbox" class="form-check-input edit-response-checkbox" id="editResponse-{{ question.id }}-{{ questionReponse.id }}" data-rep-number="{{ question.numResponses }}" data-response-id="{{ questionReponse.id }}" required>
  79.                                                         <label class="form-check-label" for="editResponse-{{ question.id }}-{{ questionReponse.id }}">{{ questionReponse.content }}</label>
  80.                                                     </div>
  81.                                                 </div>
  82.                                             </li>
  83.                                         {% endfor %}
  84.                                     </ul>
  85.                                 </li>
  86.                             {% endfor %}
  87.                         </ul>
  88.                         <button class="next-btn" style="background-color: {{ questionnaire.getCouleurContraste() }} !important;">Valider</button>
  89.                     </div>
  90.                 </div>
  91.                 
  92.                 <button class="cta" id="start-button"   style="--background-color: {{ questionnaire.getCouleurContraste() }};">
  93.                 <input type="hidden" value="{{ questionnaire.getCouleurContraste() }}" id="buttons-color">
  94.                 <span>Commencer</span>
  95.                 <svg viewBox="0 0 13 10" height="10px" width="15px">
  96.                     <path d="M1,5 L11,5"></path>
  97.                     <polyline points="8 1 12 5 8 9"></polyline>
  98.                 </svg>
  99.                 </button>
  100.             
  101.             </div>
  102.         </div>
  103.         <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  104.         <script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
  105.     <script>
  106.         $(document).ready(function () {
  107.            $("#start-button").click(function () {
  108.                 console.log("click");
  109.                 $("#loader").show();
  110.                 $(this).hide(); 
  111.                 setTimeout(function () {
  112.                     $("#loader").hide();
  113.                     $(".question-container").show();
  114.                 }, 2000);
  115.             });
  116.         });
  117.     </script>
  118.     <script>
  119.     let currentNumReponses = 0;
  120.         $(document).ready(function() {
  121.             $(document).on('submit', '.userDataForm', function(event) {
  122.                 event.preventDefault();
  123.                 if (!$('#acceptData').is(':checked')) {
  124.                     toastr.error("Vous devez accepter les conditions pour pouvoir envoyer par mail.");
  125.                     return false;
  126.                 }
  127.                 var allInputsValid = true;
  128.                 
  129.                 var formData = {};
  130.                 $(this).find('input').each(function() {
  131.                     var input = $(this);
  132.                     var inputName = input.attr('name');
  133.                     var inputSociete = input.attr('societe');
  134.                     var inputPrenom = input.attr('prenom');
  135.                     var inputTelephone = input.attr('telephone');
  136.                     var inputEmail= input.attr('email');
  137.                     var inputValue = input.val().trim();
  138.                     
  139.                     if (inputName === 'prenom' && inputValue === '') {
  140.                         allInputsValid = false;
  141.                         toastr.error("Le prénom est obligatoire.");
  142.                         return false;
  143.                     }
  144.                     if (inputName === 'societe' && inputValue === '') {
  145.                         // Societe field is optional, so no validation required
  146.                         return true;
  147.                     }
  148.                     if (inputName === 'telephone' && inputValue === '') {
  149.                         allInputsValid = false;
  150.                         toastr.error("Le numéro de téléphone est obligatoire.");
  151.                         return false;
  152.                     }
  153.                     if (inputName === 'email' && inputValue === '') {
  154.                         allInputsValid = false;
  155.                         toastr.error("L'adresse e-mail est obligatoire.");
  156.                         return false;
  157.                     }
  158.                     if (inputName === 'nom' && inputValue === '') {
  159.                         allInputsValid = false;
  160.                         toastr.error("Le nom est obligatoire.");
  161.                         return false;
  162.                     }
  163.                 });
  164.                 var profilesData = $('#profilesDataContainer').text();
  165.                const pointsData = {};
  166.                 $.each(JSON.parse(profilesData), function (profileId, points) {
  167.                     // Convert the profileId to a string before using it as a key
  168.                     pointsData[profileId.toString()] = points;
  169.                 });
  170.                 formData['profiles'] = JSON.stringify(pointsData);
  171.                 formData['prenom'] = $('#prenom').val().trim();
  172.                 formData['societe'] = $('#societe').val().trim();
  173.                 formData['telephone'] = $('#telephone').val().trim();
  174.                 formData['email'] = $('#email').val().trim();
  175.                 formData['nom'] = $('#nom').val().trim();
  176.                 formData['quizId'] = $('#quizId').val();
  177.                 if (!allInputsValid) {
  178.                     return false;
  179.                 }
  180.                 $.ajax({
  181.                     method: 'POST',
  182.                     url: '/candidat/save', 
  183.                     data: formData,
  184.                     dataType: 'json', 
  185.                     success: function(response) {
  186.                         toastr.success(response.success); 
  187.                         location.reload();
  188.                     },
  189.                     error: function(xhr, status, error) {
  190.                         const errorMessage = xhr.responseJSON ? xhr.responseJSON.error : 'An error occurred while saving your data.';
  191.                         toastr.error(errorMessage); 
  192.                     }
  193.                 });
  194.                 
  195.             });
  196.             const $questions = $('.question-item');
  197.             let currentQuestionIndex = 0;
  198.             let questionResponses = new Array($questions.length).fill(null).map(() => []); 
  199.             function showQuestion(index) {
  200.                 $questions.hide();
  201.                  var currentNumReponses = parseInt($($questions[index]).find('input[type="hidden"]').val());
  202.                 updateActiveStep(index);
  203.                 //console.log(currentNumReponses);
  204.                 $($questions[index]).show();
  205.                 
  206.             }
  207.             function checkNextButton() {
  208.                 $('.next-btn').prop('disabled', $('.edit-response-checkbox:checked').length === 0);
  209.             }
  210.             function calculateScore() {
  211.                 let scoreDetails = '';
  212.                 const url = '/findProfile';
  213.                 const requestData = JSON.stringify(questionResponses);
  214.                 for (let i = 0; i < questionResponses.length; i++) {
  215.                     const question = $questions.eq(i).find('.font-weight-bold').text();
  216.                     const selectedResponseIds = questionResponses[i];
  217.                     if (selectedResponseIds.length > 0) {
  218.                         let questionScoreDetails = `<p><strong>${question}</strong><br>`;
  219.                         for (const responseId of selectedResponseIds) {
  220.                             const responseText = $(`#editResponse${responseId}`).siblings('.form-check-label').text();
  221.                             questionScoreDetails += `- ${responseText}<br>`;
  222.                         }
  223.                         questionScoreDetails += '</p>';
  224.                         scoreDetails += questionScoreDetails;
  225.                     }
  226.                 }
  227.                     var buttonColor = $("#buttons-color").val();
  228.                   $.ajax({
  229.                     url: url,
  230.                     method: 'POST',
  231.                     data: requestData,
  232.                     contentType: 'application/json',
  233.                     success: function(response) {
  234.                         
  235.                         let scoreDetails = `
  236.                             
  237.                             <div class="justify-content-center mb-1 resultat1">
  238.                         `;
  239.                         var profileIds = [];
  240.                         var mostPointsProfile;
  241.                         let pointsData = {};
  242.                         for (let i = 0; i < response.length; i++) {
  243.                             const responseDetails = response[i];
  244.                             const profile = responseDetails.profile;
  245.                             const profileId = response[i].profile.id;
  246.                             profileIds.push(profileId);
  247.                             
  248.                             const points = responseDetails.points;
  249.                             pointsData[profileId] = points;
  250.                             if (profile) {
  251.                                 const responseNumber = i + 1;
  252.                                 const profileNumber = responseDetails.points === 0 ? 'aucun' : responseDetails.points;
  253.                                 let profileCardClass = 'winnerprofile';
  254.                                 if (i === 0) {
  255.                                     profileCardClass += ' winner'; 
  256.                                 }
  257.                                  const showPoints = responseDetails.testModeEnabled; 
  258.                                 console.log(showPoints);
  259.                                 let pointsHtml = '';
  260.                                 if (showPoints) {
  261.                                     pointsHtml = `<p class="profile-points">Points: ${responseDetails.points}</p>`;
  262.                                 }
  263.                                 //mostPointsProfile = responseProfiles[0];
  264.                              
  265.                                scoreDetails += `
  266.                                     <div class="mb-4">
  267.                                         <div class="${profileCardClass}">
  268.                                             <h3>${ i === 0 ? "Votre profil dominant" : "Mais aussi..."}</h3>
  269.                                             <div class="profile-details winner-profile}">
  270.                                                 <div class="profile-picture">
  271.                                                     <img class="winner-picture ${i === 0 ? ' resultat1_image' : 'resultat_secondaire_image'}" style="width: 280px ; height: 280px"' src="{{ asset('uploads/profils/${profile.imageProfil}') }}" alt="${profile.nomProfil}">
  272.                                                 </div>
  273.                                                 <div class="${i === 0 ? 'profile-info resultat1_texte' : 'profile-info resultat_secondaire_texte'}">
  274.                                                     <h5 class="profile-name">${profile.nomProfil}</h5>
  275.                                                     <p class="profile-description">${profile.textCourt}</p>
  276.                                                     ${pointsHtml}
  277.                                                 </div>
  278.                                                 ${i === 0 ? '<div class="winner-icon"><i class="fas fa-trophy"></i></div>' : ''}
  279.                                             </div>
  280.                                         </div>
  281.                                     </div>
  282.                                 `;
  283.                                 if (i === 0) {
  284.                                     scoreDetails += `
  285.                                         </div>
  286.                                         <div class="justify-content-around">
  287.                                     `;
  288.                                 }
  289.                             }
  290.                         }
  291.                         console.log(pointsData)
  292.                         scoreDetails += `
  293.                             </div> <br>
  294.                             <p class="text-muted">Vous voulez en savoir plus? Souhaitez vous avoir un rapport complet et des conseils liés a votre résultat? Rien de plus facile !
  295.                             renseigner vos coordonnées ci desous, un conseillé Akoya va vous recontacter trés vite !</p>
  296.                         `;
  297.                          var profilesData = JSON.stringify(pointsData);
  298.                         //$('#profilesDataContainer').text(profilesData);
  299.                         // Add the user data form here
  300.                         scoreDetails += `
  301.                         <form class="userDataForm ml-1 mt-5">
  302.                             <h3>Informations personnelles :</h3>
  303.                            <div id="profilesDataContainer" style="display: none;">${profilesData}</div>
  304.                             <div class="form-row">
  305.                                 <div class="form-group col-3">
  306.                                     <label for="nom">Nom* :</label>
  307.                                     <input type="text" class="form-control" id="nom" name="nom">
  308.                                 </div>
  309.                                 <div class="form-group col-3">
  310.                                     <label for="prenom">Prénom* :</label>
  311.                                     <input type="text" class="form-control" id="prenom" name="prenom">
  312.                                 </div>
  313.                                 <div class="form-group col-3">
  314.                                     <label for="societe">Société :</label>
  315.                                     <input type="text" class="form-control" id="societe" name="societe">
  316.                                 </div>
  317.                                 <div class="form-group col-3">
  318.                                     <label for="telephone">Téléphone* :</label>
  319.                                     <input type="tel" class="form-control" id="telephone" name="telephone">
  320.                                 </div>
  321.                             </div>
  322.                             <div class="form-group">
  323.                                 <label for="email">Adresse e-mail* :</label>
  324.                                 <input type="email" class="form-control" id="email" name="email">
  325.                             </div>
  326.                             <div class="form-check">
  327.                                 <input type="checkbox" class="form-check-input" id="acceptData" name="acceptData">
  328.                                 <label class="form-check-label" for="acceptData">J'accepte que mes données ci-dessus soient enregistrées et conservées pour une durée de 12 mois par AKOYA. 
  329.                                 Je peux à tout moment contacter AKOYA par email contact@akoya-academie.fr pour demander la suppresison de mes données</label>
  330.                             </div><br>
  331.                             <div class="form-check">
  332.                                 <input type="checkbox" class="form-check-input" id="contactMe" name="contactMe">
  333.                                 <label class="form-check-label" for="contactMe">Je souhaite être contacté(e) par Akoya pour approfondir mon résultat</label>
  334.                             </div><br>
  335.                             <button type="submit" style="background: ${buttonColor} !important;" class="btn text-white">Valider</button>
  336.                         </form>
  337.                     `;
  338.                     
  339.                         $('.body').html(scoreDetails);
  340.                         $('.progress-container').hide();
  341.                         $('.image-container').hide();
  342.                         $('.after').removeClass('d-none');
  343.                     },
  344.                     error: function(xhr, textStatus, errorThrown) {
  345.                         // Handle error if the AJAX request fails
  346.                         console.log('Error:', errorThrown);
  347.                     }
  348.                 });
  349.             }
  350.            function nextQuestion() {
  351.                 const selectedResponses = $('.edit-response-checkbox:checked').map(function() {
  352.                     const responseId = $(this).data('response-id');
  353.                     const repNumber = $(this).data('rep-number');
  354.                     console.log(responseId, repNumber);
  355.                     return { responseId, repNumber };
  356.                 }).get();
  357.                 //const currentNumReponses = parseInt($('.question-item.active').data('num-responses'));
  358.                 if (selectedResponses.length === 0) {
  359.                     toastr.error("Vous devez sélectionner au moins une réponse avant de passer à la question suivante.");
  360.                     return;
  361.                 }
  362.                 const totalSelectedReps = selectedResponses.map(response => response.repNumber);
  363.                 const hasUnexpectedRepNumber = selectedResponses.some(response => response.repNumber);
  364.                 console.log(totalSelectedReps.length, );
  365.                 if (totalSelectedReps.length !== totalSelectedReps[0]) {
  366.                     toastr.error("Vous devez sélectionner exactement " + totalSelectedReps[0] + " réponse(s) pour cette question.");
  367.                     return;
  368.                 }
  369.                 questionResponses[currentQuestionIndex] = selectedResponses.map(response => response.responseId);
  370.                 // Uncheck all checkboxes before moving to the next question
  371.                 $('.edit-response-checkbox').prop('checked', false);
  372.                 if (currentQuestionIndex < $questions.length - 1) {
  373.                     showQuestion(currentQuestionIndex + 1); 
  374.                     currentQuestionIndex++;
  375.                     $('.next-btn').prop('disabled', true);
  376.                     checkNextButton();
  377.                     updateActiveStep(currentQuestionIndex);
  378.                 } else {
  379.                     calculateScore();
  380.                 }
  381.             }
  382.             // Show the first question initially
  383.             showQuestion(currentQuestionIndex);
  384.             $('.edit-response-checkbox').on('change', function() {
  385.                 checkNextButton();
  386.             });
  387.             $('.next-btn').on('click', function() {
  388.                 nextQuestion();
  389.             });
  390.            function updateActiveStep(index) {
  391.                 $('.step').removeClass('active');
  392.                 $('.step:nth-child(' + (index + 1) + ')').addClass('active');
  393.             }
  394.     
  395.         });
  396.     </script>
  397. </body>
  398. </html>