templates/registration/register.html.twig line 32

Open in your IDE?
  1. {% extends 'base_home.html.twig' %}
  2. {% block title %}Inscription | MaketOu{% endblock %}
  3. {% block stylesheets %}
  4.     {{ parent() }}
  5.     <link rel="stylesheet" href="{{ asset('css/modern-password-field.css') }}">
  6. {% endblock %}
  7. {% block body %}
  8.     <!-- Start Banner Area -->
  9.     <section class="banner-area organic-breadcrumb">
  10.         <div class="container">
  11.             <div class="breadcrumb-banner d-flex flex-wrap align-items-center justify-content-end">
  12.                 <div class="col-first">
  13.                     <h1>Inscription</h1>
  14.                     <nav class="d-flex align-items-center">
  15.                         <a href="{{ path('ui_home') }}">Accueil<span class="lnr lnr-arrow-right"></span></a>
  16.                         <a href="javascript:void(0)">Inscription</a>
  17.                     </nav>
  18.                 </div>
  19.             </div>
  20.         </div>
  21.     </section>
  22.     <!-- End Banner Area -->
  23.     {% for flash_error in app.flashes('verify_email_error') %}
  24.         <div class="alert alert-danger" role="alert">{{ flash_error }}</div>
  25.     {% endfor %}
  26.     {{ form_errors(registrationForm) }}
  27.     <!--================Login Box Area =================-->
  28.     <section class="login_box_area section_gap">
  29.         <div class="container">
  30.             <div class="row">
  31.                 <div class="col-lg-6">
  32.                     <div class="login_box_img">
  33.                         <img class="img-fluid" src="{{ asset('ui/img/login.jpg') }}" alt="">
  34.                         <div class="hover">
  35.                             <h4>Vous avez un compte?</h4>
  36.                             <p>Connectez-vous à votre compte pour accéder à vos commandes, suivre vos livraisons et gérer vos préférences personnelles.</p>
  37.                             <a class="primary-btn" href="{{ path('ui_app_login') }}">Se connecter</a>
  38.                         </div>
  39.                     </div>
  40.                 </div>
  41.                 <div class="col-lg-6">
  42.                     <div class="login_form_inner">
  43.                         <h3>S'inscrire</h3>
  44.                         {{ form_start(registrationForm, {'attr': {'class': 'needs-validation row login_form'}}) }}
  45.                         {% if app.user %}
  46.                             <div class="mb-3">
  47.                                 Vous êtes connecté comme {{ app.user.userIdentifier }}, <a
  48.                                         href="{{ path('ui_app_logout') }}">Déconnexion</a>
  49.                             </div>
  50.                         {% endif %}
  51.                         <div class="col-md-12 form-group">
  52.                             {{ form_label(registrationForm.email, 'Email', {'label_attr': {'class': 'form-label'}}) }}
  53.                             {{ form_widget(registrationForm.email, {'attr': {'class': 'form-control', 'placeholder': 'email@example.com', 'onfocus':"this.placeholder = ''", 'onblur':"this.placeholder = 'email@example.com'", 'id': 'registration_email'}}) }}
  54.                             {{ form_errors(registrationForm.email) }}
  55.                             <small class="form-text text-muted email-validation-message"></small>
  56.                         </div>
  57.                         <div class="col-md-12 form-group">
  58.                             {{ form_label(registrationForm.plainPassword, 'Mot de passe', {'label_attr': {'class': 'form-label'}}) }}
  59.                             <div class="modern-password-group" style="position: relative;">
  60.                                 {{ form_widget(registrationForm.plainPassword, {'attr': {'class': 'form-control modern-password', 'placeholder': 'Votre mot de passe', 'onfocus':"this.placeholder = ''", 'onblur':"this.placeholder = 'Votre mot de passe'", 'id': 'registration_password', 'autocomplete': 'new-password', 'style': 'padding-right: 55px; background-color: white !important;'}}) }}
  61.                                 <button type="button" class="eye-toggle" title="Afficher le mot de passe" aria-pressed="false" style="position: absolute; right: 8px; top: 50%; transform: translateY(-50%); width: 40px; height: 40px; border: none; background: transparent; cursor: pointer; z-index: 100; display: flex; align-items: center; justify-content: center; padding: 0; color: #777;">
  62.                                     <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="width: 24px; height: 24px; display: block; color: inherit;">
  63.                                         <defs>
  64.                                             <mask id="eye-open">
  65.                                                 <path d="M1 12 C1 12 5 4 12 4 19 4 23 12 23 12 23 14.66 23 17.32 23 20 19.32 20 15.66 20 12 20 8.33 20 4.66 20 1 20 1 17.32 1 14.66 1 12 z" fill="#D9D9D9" stroke="black" stroke-width="1.5" stroke-linejoin="round"></path>
  66.                                             </mask>
  67.                                             <mask id="eye-closed">
  68.                                                 <path d="M1 12C1 12 5 20 12 20C19 20 23 12 23 12V20H12H1V12Z" fill="#D9D9D9"></path>
  69.                                             </mask>
  70.                                         </defs>
  71.                                         <path class="lid lid--upper" d="M1 12 C1 12 5 4 12 4 19 4 23 12 23 12 " stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
  72.                                         <path class="lid lid--lower" d="M1 12C1 12 5 20 12 20C19 20 23 12 23 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
  73.                                         <g mask="url(#eye-open)">
  74.                                             <g class="eye">
  75.                                                 <circle cy="12" cx="12" r="4" fill="currentColor"></circle>
  76.                                                 <circle cy="11" cx="13" r="1" fill="black"></circle>
  77.                                             </g>
  78.                                         </g>
  79.                                     </svg>
  80.                                     <span class="sr-only">Afficher</span>
  81.                                 </button>
  82.                             </div>
  83.                             {{ form_errors(registrationForm.plainPassword) }}
  84.                             <small class="form-text text-muted password-validation-message"></small>
  85.                             <div class="password-strength mt-2" style="display: none;">
  86.                                 <div class="progress" style="height: 5px;">
  87.                                     <div class="progress-bar" role="progressbar" style="width: 0%"></div>
  88.                                 </div>
  89.                                 <small class="strength-text"></small>
  90.                             </div>
  91.                         </div>
  92.                         <div class="col-md-12 form-group">
  93.                             <div class="creat_account">
  94.                                 {{ form_widget(registrationForm.agreeTerms) }}
  95.                                 {{ form_label(registrationForm.agreeTerms, 'Accepte les conditions') }}
  96.                                 {{ form_errors(registrationForm.agreeTerms) }}
  97.                             </div>
  98.                         </div>
  99.                         <div class="col-md-12 form-group">
  100.                             <button class="primary-btn" type="submit">
  101.                                 S'inscrire
  102.                             </button>
  103.                             <a href="{{ path('ui_app_login') }}">Déjà un compte? <b>Se connecter</b></a>
  104.                         </div>
  105.                         {{ form_end(registrationForm) }}
  106.                     </div>
  107.                 </div>
  108.             </div>
  109.         </div>
  110.     </section>
  111. {% endblock %}
  112. {% block javascripts %}
  113.     {{ parent() }}
  114.     <script>
  115.     // Load GSAP standard (now 100% free with all plugins included as of April 2025)
  116.     (function() {
  117.         const GSAP_TIMEOUT = 5000; // 5 seconds timeout
  118.         let gsapLoaded = false;
  119.         
  120.         // Load GSAP standard package (includes all plugins)
  121.         const gsapScript = document.createElement('script');
  122.         gsapScript.src = 'https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js';
  123.         gsapScript.async = true;
  124.         gsapScript.onload = function() {
  125.             gsapLoaded = true;
  126.             console.log('[GSAP] Standard package loaded successfully');
  127.             // Load password field script after GSAP is loaded
  128.             setTimeout(loadPasswordFieldScript, 100);
  129.         };
  130.         gsapScript.onerror = function() {
  131.             console.warn('[GSAP] Failed to load, using fallback');
  132.             loadPasswordFieldScript();
  133.         };
  134.         
  135.         // Timeout fallback
  136.         setTimeout(function() {
  137.             if (!gsapLoaded) {
  138.                 console.warn('[GSAP] Timeout loading GSAP, using fallback');
  139.                 loadPasswordFieldScript();
  140.             }
  141.         }, GSAP_TIMEOUT);
  142.         
  143.         document.head.appendChild(gsapScript);
  144.         
  145.         function loadPasswordFieldScript() {
  146.             const script = document.createElement('script');
  147.             script.src = '{{ asset('js/modern-password-field.js') }}';
  148.             script.async = true;
  149.             document.head.appendChild(script);
  150.         }
  151.     })();
  152.     </script>
  153. <script>
  154. document.addEventListener('DOMContentLoaded', function() {
  155.     const emailInput = document.getElementById('registration_email');
  156.     const passwordInput = document.getElementById('registration_password');
  157.     const emailMessage = document.querySelector('.email-validation-message');
  158.     const passwordMessage = document.querySelector('.password-validation-message');
  159.     const passwordStrength = document.querySelector('.password-strength');
  160.     const progressBar = passwordStrength.querySelector('.progress-bar');
  161.     const strengthText = passwordStrength.querySelector('.strength-text');
  162.     const registrationForm = document.querySelector('.needs-validation');
  163.     
  164.     // Validation email en temps réel
  165.     if (emailInput) {
  166.         emailInput.addEventListener('blur', function() {
  167.             validateEmail(this.value);
  168.         });
  169.         
  170.         emailInput.addEventListener('input', function() {
  171.             if (this.value.length > 0) {
  172.                 validateEmail(this.value);
  173.             } else {
  174.                 emailMessage.textContent = '';
  175.                 emailMessage.className = 'form-text text-muted email-validation-message';
  176.             }
  177.         });
  178.     }
  179.     
  180.     // Validation mot de passe en temps réel
  181.     if (passwordInput) {
  182.         passwordInput.addEventListener('input', function() {
  183.             validatePassword(this.value);
  184.         });
  185.         
  186.         passwordInput.addEventListener('blur', function() {
  187.             if (this.value.length > 0) {
  188.                 validatePassword(this.value);
  189.             }
  190.         });
  191.     }
  192.     
  193.     function validateEmail(email) {
  194.         const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
  195.         
  196.         if (!email) {
  197.             emailMessage.textContent = '';
  198.             emailMessage.className = 'form-text text-muted email-validation-message';
  199.             return false;
  200.         }
  201.         
  202.         if (!emailRegex.test(email)) {
  203.             emailMessage.textContent = 'Format d\'email invalide. Exemple: exemple@domaine.com';
  204.             emailMessage.className = 'form-text text-danger email-validation-message';
  205.             emailInput.classList.add('is-invalid');
  206.             emailInput.classList.remove('is-valid');
  207.             return false;
  208.         }
  209.         
  210.         // Vérifier les domaines invalides communs
  211.         const invalidDomains = ['test.com', 'example.com', 'invalid.com'];
  212.         const domain = email.split('@')[1];
  213.         if (invalidDomains.includes(domain)) {
  214.             emailMessage.textContent = 'Veuillez utiliser une adresse email valide.';
  215.             emailMessage.className = 'form-text text-danger email-validation-message';
  216.             emailInput.classList.add('is-invalid');
  217.             emailInput.classList.remove('is-valid');
  218.             return false;
  219.         }
  220.         
  221.         emailMessage.textContent = '✓ Adresse email valide';
  222.         emailMessage.className = 'form-text text-success email-validation-message';
  223.         emailInput.classList.remove('is-invalid');
  224.         emailInput.classList.add('is-valid');
  225.         return true;
  226.     }
  227.     
  228.     function validatePassword(password) {
  229.         const minLength = 8;
  230.         const hasUpperCase = /[A-Z]/.test(password);
  231.         const hasLowerCase = /[a-z]/.test(password);
  232.         const hasNumber = /\d/.test(password);
  233.         const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);
  234.         
  235.         if (!password) {
  236.             passwordMessage.textContent = '';
  237.             passwordMessage.className = 'form-text text-muted password-validation-message';
  238.             passwordStrength.style.display = 'none';
  239.             return false;
  240.         }
  241.         
  242.         let messages = [];
  243.         let strength = 0;
  244.         
  245.         if (password.length >= minLength) {
  246.             strength += 25;
  247.         } else {
  248.             messages.push(`Au moins ${minLength} caractères`);
  249.         }
  250.         
  251.         if (hasUpperCase) {
  252.             strength += 25;
  253.         } else {
  254.             messages.push('Une majuscule');
  255.         }
  256.         
  257.         if (hasLowerCase) {
  258.             strength += 25;
  259.         } else {
  260.             messages.push('Une minuscule');
  261.         }
  262.         
  263.         if (hasNumber) {
  264.             strength += 25;
  265.         } else {
  266.             messages.push('Un chiffre');
  267.         }
  268.         
  269.         // Bonus pour caractère spécial
  270.         if (hasSpecialChar) {
  271.             strength = Math.min(100, strength + 10);
  272.         }
  273.         
  274.         // Mettre à jour la barre de progression
  275.         progressBar.style.width = strength + '%';
  276.         
  277.         if (strength < 50) {
  278.             progressBar.className = 'progress-bar bg-danger';
  279.             strengthText.textContent = 'Faible';
  280.             strengthText.className = 'strength-text text-danger';
  281.         } else if (strength < 75) {
  282.             progressBar.className = 'progress-bar bg-warning';
  283.             strengthText.textContent = 'Moyen';
  284.             strengthText.className = 'strength-text text-warning';
  285.         } else {
  286.             progressBar.className = 'progress-bar bg-success';
  287.             strengthText.textContent = 'Fort';
  288.             strengthText.className = 'strength-text text-success';
  289.         }
  290.         
  291.         passwordStrength.style.display = 'block';
  292.         
  293.         if (messages.length > 0) {
  294.             passwordMessage.textContent = 'Le mot de passe doit contenir: ' + messages.join(', ');
  295.             passwordMessage.className = 'form-text text-danger password-validation-message';
  296.             passwordInput.classList.add('is-invalid');
  297.             passwordInput.classList.remove('is-valid');
  298.             return false;
  299.         } else {
  300.             passwordMessage.textContent = '✓ Mot de passe valide';
  301.             passwordMessage.className = 'form-text text-success password-validation-message';
  302.             passwordInput.classList.remove('is-invalid');
  303.             passwordInput.classList.add('is-valid');
  304.             return true;
  305.         }
  306.     }
  307.     
  308.     // Validation avant soumission
  309.     if (registrationForm) {
  310.         registrationForm.addEventListener('submit', function(e) {
  311.             const emailValid = validateEmail(emailInput.value);
  312.             const passwordValid = validatePassword(passwordInput.value);
  313.             
  314.             if (!emailValid || !passwordValid) {
  315.                 e.preventDefault();
  316.                 e.stopPropagation();
  317.                 
  318.                 if (!emailValid) {
  319.                     emailInput.focus();
  320.                 } else if (!passwordValid) {
  321.                     passwordInput.focus();
  322.                 }
  323.             }
  324.             
  325.             registrationForm.classList.add('was-validated');
  326.         });
  327.     }
  328. });
  329. </script>
  330. {% endblock %}