{% extends 'base_home.html.twig' %}
{% block title %}Inscription | MaketOu{% endblock %}
{% block stylesheets %}
{{ parent() }}
<link rel="stylesheet" href="{{ asset('css/modern-password-field.css') }}">
{% endblock %}
{% block body %}
<!-- Start Banner Area -->
<section class="banner-area organic-breadcrumb">
<div class="container">
<div class="breadcrumb-banner d-flex flex-wrap align-items-center justify-content-end">
<div class="col-first">
<h1>Inscription</h1>
<nav class="d-flex align-items-center">
<a href="{{ path('ui_home') }}">Accueil<span class="lnr lnr-arrow-right"></span></a>
<a href="javascript:void(0)">Inscription</a>
</nav>
</div>
</div>
</div>
</section>
<!-- End Banner Area -->
{% for flash_error in app.flashes('verify_email_error') %}
<div class="alert alert-danger" role="alert">{{ flash_error }}</div>
{% endfor %}
{{ form_errors(registrationForm) }}
<!--================Login Box Area =================-->
<section class="login_box_area section_gap">
<div class="container">
<div class="row">
<div class="col-lg-6">
<div class="login_box_img">
<img class="img-fluid" src="{{ asset('ui/img/login.jpg') }}" alt="">
<div class="hover">
<h4>Vous avez un compte?</h4>
<p>Connectez-vous à votre compte pour accéder à vos commandes, suivre vos livraisons et gérer vos préférences personnelles.</p>
<a class="primary-btn" href="{{ path('ui_app_login') }}">Se connecter</a>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="login_form_inner">
<h3>S'inscrire</h3>
{{ form_start(registrationForm, {'attr': {'class': 'needs-validation row login_form'}}) }}
{% if app.user %}
<div class="mb-3">
Vous êtes connecté comme {{ app.user.userIdentifier }}, <a
href="{{ path('ui_app_logout') }}">Déconnexion</a>
</div>
{% endif %}
<div class="col-md-12 form-group">
{{ form_label(registrationForm.email, 'Email', {'label_attr': {'class': 'form-label'}}) }}
{{ form_widget(registrationForm.email, {'attr': {'class': 'form-control', 'placeholder': 'email@example.com', 'onfocus':"this.placeholder = ''", 'onblur':"this.placeholder = 'email@example.com'", 'id': 'registration_email'}}) }}
{{ form_errors(registrationForm.email) }}
<small class="form-text text-muted email-validation-message"></small>
</div>
<div class="col-md-12 form-group">
{{ form_label(registrationForm.plainPassword, 'Mot de passe', {'label_attr': {'class': 'form-label'}}) }}
<div class="modern-password-group" style="position: relative;">
{{ 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;'}}) }}
<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;">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="width: 24px; height: 24px; display: block; color: inherit;">
<defs>
<mask id="eye-open">
<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>
</mask>
<mask id="eye-closed">
<path d="M1 12C1 12 5 20 12 20C19 20 23 12 23 12V20H12H1V12Z" fill="#D9D9D9"></path>
</mask>
</defs>
<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>
<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>
<g mask="url(#eye-open)">
<g class="eye">
<circle cy="12" cx="12" r="4" fill="currentColor"></circle>
<circle cy="11" cx="13" r="1" fill="black"></circle>
</g>
</g>
</svg>
<span class="sr-only">Afficher</span>
</button>
</div>
{{ form_errors(registrationForm.plainPassword) }}
<small class="form-text text-muted password-validation-message"></small>
<div class="password-strength mt-2" style="display: none;">
<div class="progress" style="height: 5px;">
<div class="progress-bar" role="progressbar" style="width: 0%"></div>
</div>
<small class="strength-text"></small>
</div>
</div>
<div class="col-md-12 form-group">
<div class="creat_account">
{{ form_widget(registrationForm.agreeTerms) }}
{{ form_label(registrationForm.agreeTerms, 'Accepte les conditions') }}
{{ form_errors(registrationForm.agreeTerms) }}
</div>
</div>
<div class="col-md-12 form-group">
<button class="primary-btn" type="submit">
S'inscrire
</button>
<a href="{{ path('ui_app_login') }}">Déjà un compte? <b>Se connecter</b></a>
</div>
{{ form_end(registrationForm) }}
</div>
</div>
</div>
</div>
</section>
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script>
// Load GSAP standard (now 100% free with all plugins included as of April 2025)
(function() {
const GSAP_TIMEOUT = 5000; // 5 seconds timeout
let gsapLoaded = false;
// Load GSAP standard package (includes all plugins)
const gsapScript = document.createElement('script');
gsapScript.src = 'https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js';
gsapScript.async = true;
gsapScript.onload = function() {
gsapLoaded = true;
console.log('[GSAP] Standard package loaded successfully');
// Load password field script after GSAP is loaded
setTimeout(loadPasswordFieldScript, 100);
};
gsapScript.onerror = function() {
console.warn('[GSAP] Failed to load, using fallback');
loadPasswordFieldScript();
};
// Timeout fallback
setTimeout(function() {
if (!gsapLoaded) {
console.warn('[GSAP] Timeout loading GSAP, using fallback');
loadPasswordFieldScript();
}
}, GSAP_TIMEOUT);
document.head.appendChild(gsapScript);
function loadPasswordFieldScript() {
const script = document.createElement('script');
script.src = '{{ asset('js/modern-password-field.js') }}';
script.async = true;
document.head.appendChild(script);
}
})();
</script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const emailInput = document.getElementById('registration_email');
const passwordInput = document.getElementById('registration_password');
const emailMessage = document.querySelector('.email-validation-message');
const passwordMessage = document.querySelector('.password-validation-message');
const passwordStrength = document.querySelector('.password-strength');
const progressBar = passwordStrength.querySelector('.progress-bar');
const strengthText = passwordStrength.querySelector('.strength-text');
const registrationForm = document.querySelector('.needs-validation');
// Validation email en temps réel
if (emailInput) {
emailInput.addEventListener('blur', function() {
validateEmail(this.value);
});
emailInput.addEventListener('input', function() {
if (this.value.length > 0) {
validateEmail(this.value);
} else {
emailMessage.textContent = '';
emailMessage.className = 'form-text text-muted email-validation-message';
}
});
}
// Validation mot de passe en temps réel
if (passwordInput) {
passwordInput.addEventListener('input', function() {
validatePassword(this.value);
});
passwordInput.addEventListener('blur', function() {
if (this.value.length > 0) {
validatePassword(this.value);
}
});
}
function validateEmail(email) {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (!email) {
emailMessage.textContent = '';
emailMessage.className = 'form-text text-muted email-validation-message';
return false;
}
if (!emailRegex.test(email)) {
emailMessage.textContent = 'Format d\'email invalide. Exemple: exemple@domaine.com';
emailMessage.className = 'form-text text-danger email-validation-message';
emailInput.classList.add('is-invalid');
emailInput.classList.remove('is-valid');
return false;
}
// Vérifier les domaines invalides communs
const invalidDomains = ['test.com', 'example.com', 'invalid.com'];
const domain = email.split('@')[1];
if (invalidDomains.includes(domain)) {
emailMessage.textContent = 'Veuillez utiliser une adresse email valide.';
emailMessage.className = 'form-text text-danger email-validation-message';
emailInput.classList.add('is-invalid');
emailInput.classList.remove('is-valid');
return false;
}
emailMessage.textContent = '✓ Adresse email valide';
emailMessage.className = 'form-text text-success email-validation-message';
emailInput.classList.remove('is-invalid');
emailInput.classList.add('is-valid');
return true;
}
function validatePassword(password) {
const minLength = 8;
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasNumber = /\d/.test(password);
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);
if (!password) {
passwordMessage.textContent = '';
passwordMessage.className = 'form-text text-muted password-validation-message';
passwordStrength.style.display = 'none';
return false;
}
let messages = [];
let strength = 0;
if (password.length >= minLength) {
strength += 25;
} else {
messages.push(`Au moins ${minLength} caractères`);
}
if (hasUpperCase) {
strength += 25;
} else {
messages.push('Une majuscule');
}
if (hasLowerCase) {
strength += 25;
} else {
messages.push('Une minuscule');
}
if (hasNumber) {
strength += 25;
} else {
messages.push('Un chiffre');
}
// Bonus pour caractère spécial
if (hasSpecialChar) {
strength = Math.min(100, strength + 10);
}
// Mettre à jour la barre de progression
progressBar.style.width = strength + '%';
if (strength < 50) {
progressBar.className = 'progress-bar bg-danger';
strengthText.textContent = 'Faible';
strengthText.className = 'strength-text text-danger';
} else if (strength < 75) {
progressBar.className = 'progress-bar bg-warning';
strengthText.textContent = 'Moyen';
strengthText.className = 'strength-text text-warning';
} else {
progressBar.className = 'progress-bar bg-success';
strengthText.textContent = 'Fort';
strengthText.className = 'strength-text text-success';
}
passwordStrength.style.display = 'block';
if (messages.length > 0) {
passwordMessage.textContent = 'Le mot de passe doit contenir: ' + messages.join(', ');
passwordMessage.className = 'form-text text-danger password-validation-message';
passwordInput.classList.add('is-invalid');
passwordInput.classList.remove('is-valid');
return false;
} else {
passwordMessage.textContent = '✓ Mot de passe valide';
passwordMessage.className = 'form-text text-success password-validation-message';
passwordInput.classList.remove('is-invalid');
passwordInput.classList.add('is-valid');
return true;
}
}
// Validation avant soumission
if (registrationForm) {
registrationForm.addEventListener('submit', function(e) {
const emailValid = validateEmail(emailInput.value);
const passwordValid = validatePassword(passwordInput.value);
if (!emailValid || !passwordValid) {
e.preventDefault();
e.stopPropagation();
if (!emailValid) {
emailInput.focus();
} else if (!passwordValid) {
passwordInput.focus();
}
}
registrationForm.classList.add('was-validated');
});
}
});
</script>
{% endblock %}