templates/inscription/inscription.html.twig line 1

Open in your IDE?
  1. {% extends 'base.html.twig' %}
  2. {% block title %}IMMY BEAUTY - Inscription{% endblock %}
  3. {% block stylesheets %}
  4.     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/css/intlTelInput.css"/>
  5.     <script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/intlTelInput.min.js"></script>
  6.     <style>
  7.         .form-group { margin-bottom: 0.8rem !important; }
  8.         .form-label { margin-bottom: 0.2rem; color: #555; font-size: 0.9rem; }
  9.         .form-control { padding: 0.5rem 0.75rem; }
  10.         .registration-form {
  11.             background: white;
  12.             padding: 2rem;
  13.             border-radius: 10px;
  14.             box-shadow: 0 0 20px rgba(0,0,0,0.05);
  15.         }
  16.         .promo-code-section {
  17.             margin: 1.5rem 0;
  18.             padding: 1rem;
  19.             background: #f8f9fa;
  20.             border-radius: 8px;
  21.             border: 1px dashed #dee2e6;
  22.         }
  23.         .promo-code-toggle {
  24.             color: #FF6B6B;
  25.             text-decoration: none;
  26.             cursor: pointer;
  27.             display: inline-flex;
  28.             align-items: center;
  29.             font-size: 0.9rem;
  30.         }
  31.         .promo-code-input {
  32.             background: white;
  33.             border: 2px solid #FF6B6B;
  34.             border-radius: 4px;
  35.             padding: 0.5rem;
  36.             font-size: 1rem;
  37.             text-transform: uppercase;
  38.             letter-spacing: 1px;
  39.             text-align: center;
  40.         }
  41.         .promo-code-info {
  42.             font-size: 0.8rem;
  43.             color: #666;
  44.             margin-top: 0.5rem;
  45.         }
  46.     </style>
  47. {% endblock %}
  48. {% block body %}
  49.     <div class="container mt-4">
  50.         <div class="row justify-content-center">
  51.             <div class="col-md-6">
  52.                 <form method="post" action="{{ path('api_register') }}" class="registration-form">
  53.                     <input type="hidden" name="_csrf_token" value="{{ csrf_token('register') }}">
  54.                     <h2 class="text-center mb-2">Rejoignez IMMY BEAUTY</h2>
  55.                     <p class="text-center text-muted mb-4 small">Créez votre compte et commencez à cumuler des avantages exclusifs</p>
  56.                     <div class="row">
  57.                         <div class="col-md-6">
  58.                             <div class="form-group">
  59.                                 <label class="form-label">Prénom</label>
  60.                                 <input type="text" id="prenom" name="prenom" class="form-control" required autofocus>
  61.                             </div>
  62.                         </div>
  63.                         <div class="col-md-6">
  64.                             <div class="form-group">
  65.                                 <label class="form-label">Nom</label>
  66.                                 <input type="text" id="nom" name="nom" class="form-control" required>
  67.                             </div>
  68.                         </div>
  69.                     </div>
  70.                     <div class="form-group">
  71.                         <label class="form-label">Date de naissance</label>
  72.                         <input type="date" id="birthdate" name="birthdate" class="form-control" required>
  73.                     </div>
  74.                     <div class="row">
  75.                         <div class="col-md-6">
  76.                             <div class="form-group">
  77.                                 <label class="form-label">Email</label>
  78.                                 <input type="email" id="email" name="email" class="form-control" required>
  79.                             </div>
  80.                         </div>
  81.                         <div class="col-md-6">
  82.                             <div class="form-group">
  83.                                 <label class="form-label">Téléphone</label>
  84.                                 <input type="tel" id="telephone" name="telephone" class="form-control" required maxlength="10">
  85.                             </div>
  86.                         </div>
  87.                     </div>
  88.                     <div class="form-group mb-3">
  89.                         <label class="form-label d-flex align-items-center">
  90.                             <span>Code cadeau</span>
  91.                             <span class="ms-2 badge bg-secondary" style="font-size: 0.7em;">Facultatif</span>
  92.                         </label>
  93.                         <div class="input-group">
  94.                             <input type="text"
  95.                                    id="promo_code"
  96.                                    name="promo_code"
  97.                                    class="form-control"
  98.                                    placeholder="Uniquement si vous avez reçu un code par email"
  99.                                    autocomplete="off">
  100.                             <button class="btn btn-outline-secondary verify-code"
  101.                                     type="button"
  102.                                     id="verify-code">
  103.                                 <i class="fas fa-check"></i>
  104.                             </button>
  105.                         </div>
  106.                         <small class="text-muted">Laissez vide si vous n'avez pas de code</small>
  107.                         <div id="promo-status" class="form-text mt-1"></div>
  108.                     </div>
  109.                     <div class="row">
  110.                         <div class="col-md-6">
  111.                             <div class="form-group">
  112.                                 <label class="form-label">Mot de passe</label>
  113.                                 <input type="password" id="password" name="password" class="form-control" required>
  114.                                 <small class="form-text text-muted">8 caractères minimum</small>
  115.                             </div>
  116.                         </div>
  117.                         <div class="col-md-6">
  118.                             <div class="form-group">
  119.                                 <label class="form-label">Confirmer</label>
  120.                                 <input type="password" id="confirm_password" name="confirm_password" class="form-control" required>
  121.                             </div>
  122.                         </div>
  123.                     </div>
  124.                     <div class="form-group mt-4">
  125.                         <button type="submit" class="btn btn-primary w-100">Créer mon compte</button>
  126.                     </div>
  127.                     <div class="text-center mt-3">
  128.                         <span class="small">Déjà membre ? <a href="{{ path('connexion') }}" class="text-decoration-none">Connectez-vous</a></span>
  129.                     </div>
  130.                 </form>
  131.             </div>
  132.         </div>
  133.     </div>
  134.     <section class="ftco-section">
  135.         <div class="container">
  136.             <div class="row">
  137.                 <div class="col-md-4 ftco-animate">
  138.                     <div class="media d-block text-center block-6 services">
  139.                         <div class="icon d-flex mb-3"><span class="fas fa-user-plus"></span></div>
  140.                         <div class="media-body">
  141.                             <h3 class="heading">INSCRIVEZ VOUS</h3>
  142.                             <p>Commencez votre voyage pour gagner des points et profiter d'avantages exclusifs.</p>
  143.                         </div>
  144.                     </div>
  145.                 </div>
  146.                 <div class="col-md-4 ftco-animate">
  147.                     <div class="media d-block text-center block-6 services">
  148.                         <div class="icon d-flex mb-3"><span class="fas fa-trophy"></span></div>
  149.                         <div class="media-body">
  150.                             <h3 class="heading">CUMULEZ DES POINTS</h3>
  151.                             <p>Plus vous collectez de points, plus vous débloquez de récompenses et de privilèges spéciaux.</p>
  152.                         </div>
  153.                     </div>
  154.                 </div>
  155.                 <div class="col-md-4 ftco-animate">
  156.                     <div class="media d-block text-center block-6 services">
  157.                         <div class="icon d-flex mb-3"><span class="fas fa-gift"></span></div>
  158.                         <div class="media-body">
  159.                             <h3 class="heading">PROFITEZ DES AVANTAGES</h3>
  160.                             <p>Échangez vos points contre des réductions, des produits gratuits ou des services spéciaux.</p>
  161.                         </div>
  162.                     </div>
  163.                 </div>
  164.             </div>
  165.         </div>
  166.     </section>
  167. {% endblock %}
  168. {% block btn_reserver %}
  169. {% endblock %}
  170. {% block javascripts %}
  171.     {{ parent() }}
  172. <script>
  173.     $(document).ready(function() {
  174.         const urlParams = new URLSearchParams(window.location.search);
  175.         const codeFromUrl = urlParams.get('code');
  176.         if (codeFromUrl) {
  177.             // Pré-rempli le champ
  178.             $('#promo_code').val(codeFromUrl);
  179.             // Attendre que l'email soit rempli pour vérifier automatiquement
  180.             $('#email').on('change', function() {
  181.                 const email = $(this).val().trim();
  182.                 if (email) {
  183.                     $('#verify-code').click(); // Déclenche la vérification
  184.                 }
  185.             });
  186.         }
  187.         $('form').submit(function(e) {
  188.             e.preventDefault();
  189.             // Récupération et nettoyage des données
  190.             const formData = {
  191.                 prenom: $('#prenom').val().trim(),
  192.                 nom: $('#nom').val().trim(),
  193.                 email: $('#email').val().trim().toLowerCase(),
  194.                 telephone: $('#telephone').val().trim().replace(/\D/g, ''),
  195.                 password: $('#password').val(),
  196.                 confirm_password: $('#confirm_password').val(),
  197.                 birthdate: $('#birthdate').val(),
  198.                 promo_code: $('#promo_code').val().trim(),
  199.                 _csrf_token: $('[name="_csrf_token"]').val()
  200.             };
  201.             if (formData.promo_code) {
  202.                 formData.promo_verified = Boolean($('#promo_code').prop('readonly'));
  203.             }
  204.             // Validation complète
  205.             const errors = [];
  206.             // Validation nom/prénom
  207.             if (!formData.prenom || formData.prenom.length < 2) {
  208.                 errors.push('Le prénom doit contenir au moins 2 caractères');
  209.             }
  210.             if (!formData.nom || formData.nom.length < 2) {
  211.                 errors.push('Le nom doit contenir au moins 2 caractères');
  212.             }
  213.             // Validation email
  214.             const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  215.             if (!emailRegex.test(formData.email)) {
  216.                 errors.push('Adresse email invalide');
  217.             }
  218.             // Validation téléphone
  219.             if (!/^0[1-9][0-9]{8}$/.test(formData.telephone)) {
  220.                 errors.push('Le numéro de téléphone doit commencer par 0 et contenir 10 chiffres');
  221.             }
  222.             // Validation date de naissance
  223.             const birthDate = new Date(formData.birthdate);
  224.             const today = new Date();
  225.             let age = today.getFullYear() - birthDate.getFullYear();
  226.             const m = today.getMonth() - birthDate.getMonth();
  227.             if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
  228.                 age--;
  229.             }
  230.             if (!formData.birthdate) {
  231.                 errors.push('La date de naissance est obligatoire');
  232.             } else if (age < 16) {
  233.                 errors.push('Vous devez avoir au moins 16 ans pour vous inscrire');
  234.             }
  235.             // Validation mot de passe
  236.             const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*#?&]{8,}$/;
  237.             if (!passwordRegex.test(formData.password)) {
  238.                 errors.push('Le mot de passe doit contenir au moins 8 caractères, une lettre et un chiffre');
  239.             }
  240.             if (formData.password !== formData.confirm_password) {
  241.                 errors.push('Les mots de passe ne correspondent pas');
  242.             }
  243.             // Affichage des erreurs
  244.             if (errors.length > 0) {
  245.                 errors.forEach(error => toastr.error(error));
  246.                 return;
  247.             }
  248.             // Envoi sécurisé
  249.             $.ajax({
  250.                 type: 'POST',
  251.                 url: '{{ path('api_register') }}',
  252.                 data: formData,
  253.                 dataType: 'json',
  254.                 headers: {
  255.                     'X-CSRF-Token': formData._csrf_token
  256.                 },
  257.                 success: function(response) {
  258.                     if (response.success) {
  259.                         localStorage.setItem('registerSuccess', 'Inscription réussie ! Vous êtes désormais connecté.');
  260.                         window.location.href = '{{ path('app_fidelite') }}';
  261.                     } else {
  262.                         toastr.error(response.message || 'Une erreur est survenue');
  263.                     }
  264.                 },
  265.                 error: function(xhr) {
  266.                     const errorMsg = xhr.responseJSON?.message || "Une erreur est survenue lors de l'inscription.";
  267.                     toastr.error(errorMsg);
  268.                 }
  269.             });
  270.         });
  271.         // Masquer les caractères spéciaux dans les champs texte
  272.         $('input[type="text"]').on('input', function() {
  273.             this.value = this.value.replace(/[<>]/g, '');
  274.         });
  275.         // Formatter le téléphone en temps réel
  276.         $('#telephone').on('input', function() {
  277.             this.value = this.value.replace(/\D/g, '').substring(0, 10);
  278.         });
  279.     });
  280.     $('#verify-code').click(function() {
  281.         const code = $('#promo_code').val().trim();
  282.         const email = $('#email').val().trim();
  283.         if (!code) {
  284.             toastr.error('Veuillez entrer un code');
  285.             return;
  286.         }
  287.         if (!email) {
  288.             toastr.error('Veuillez d\'abord remplir votre email');
  289.             return;
  290.         }
  291.         const $button = $(this);
  292.         const $status = $('#promo-status');
  293.         $button.prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i>');
  294.         $.ajax({
  295.             url: '{{ path('verify_promo_code') }}',
  296.             method: 'POST',
  297.             data: {
  298.                 code: code,
  299.                 email: email,
  300.                 _token: '{{ csrf_token('promo_verify') }}'
  301.             },
  302.             success: function(response) {
  303.                 if (response.valid) {
  304.                     $status.html(`<small class="text-success">
  305.                     <i class="fas fa-check-circle"></i> ${response.message}
  306.                 </small>`);
  307.                     $('#promo_code').prop('readonly', true);
  308.                     $button.html('<i class="fas fa-check"></i>').addClass('btn-success');
  309.                 } else {
  310.                     $status.html(`<small class="text-danger">
  311.                     <i class="fas fa-times-circle"></i> ${response.message}
  312.                 </small>`);
  313.                     $button.prop('disabled', false).html('<i class="fas fa-check"></i>');
  314.                 }
  315.             },
  316.             error: function(xhr) {
  317.                 let message = xhr.responseJSON?.message || 'Une erreur est survenue';
  318.                 $status.html(`<small class="text-danger">
  319.                 <i class="fas fa-times-circle"></i> ${message}
  320.             </small>`);
  321.                 $button.prop('disabled', false).html('<i class="fas fa-check"></i>');
  322.             }
  323.         });
  324.     });
  325. </script>
  326. {% endblock %}