fix: replace deprecated HTML attributes and reduce JS nesting
- Replace email layout tables with CSS divs in base.html.twig - Replace deprecated width/align attributes with CSS styles in PDF templates - Add role="presentation" to email layout tables - Convert td to th[scope=row] in profil and attestation verify tables - Reduce function nesting in app.js by extracting renderHit/performSearch Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,27 +4,18 @@ import "./app.scss"
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const memberCheckbox = document.querySelector('input[value="gp_member"]');
|
||||
const adminCheckbox = document.querySelector('input[value="super_admin_asso"]');
|
||||
const otherGroupCheckboxes = () =>
|
||||
[...document.querySelectorAll('input[name="groups[]"]')].filter(cb => cb !== memberCheckbox);
|
||||
|
||||
if (memberCheckbox && adminCheckbox) {
|
||||
memberCheckbox.addEventListener('change', () => {
|
||||
if (memberCheckbox.checked) {
|
||||
document.querySelectorAll('input[name="groups[]"]').forEach(cb => {
|
||||
if (cb !== memberCheckbox) {
|
||||
cb.checked = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (memberCheckbox.checked) otherGroupCheckboxes().forEach(cb => { cb.checked = false; });
|
||||
});
|
||||
|
||||
adminCheckbox.addEventListener('change', () => {
|
||||
if (adminCheckbox.checked) {
|
||||
memberCheckbox.checked = false;
|
||||
document.querySelectorAll('input[name="groups[]"]').forEach(cb => {
|
||||
if (cb !== memberCheckbox) {
|
||||
cb.checked = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!adminCheckbox.checked) return;
|
||||
memberCheckbox.checked = false;
|
||||
otherGroupCheckboxes().forEach(cb => { cb.checked = true; });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -105,6 +96,22 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
|
||||
// Search (customers & revendeurs)
|
||||
const renderHit = (h, linkPrefix) =>
|
||||
`<a href="${linkPrefix}${h.id}" class="block px-4 py-2 hover:bg-gray-50 border-b border-gray-100 text-xs">
|
||||
<span class="font-bold">${h.fullName || h.raisonSociale || (h.firstName + ' ' + h.lastName)}</span>
|
||||
${h.email ? `<span class="text-gray-400 ml-2">${h.email}</span>` : ''}
|
||||
${h.codeRevendeur ? `<span class="ml-2 px-1 py-0.5 bg-gray-900 text-[#fabf04] text-[9px] font-bold">${h.codeRevendeur}</span>` : ''}
|
||||
</a>`;
|
||||
|
||||
const performSearch = async (searchUrl, linkPrefix, results, q) => {
|
||||
const resp = await fetch(`${searchUrl}?q=${encodeURIComponent(q)}`);
|
||||
const hits = await resp.json();
|
||||
results.innerHTML = hits.length === 0
|
||||
? '<div class="px-4 py-3 text-xs text-gray-400">Aucun resultat.</div>'
|
||||
: hits.map(h => renderHit(h, linkPrefix)).join('');
|
||||
results.classList.remove('hidden');
|
||||
};
|
||||
|
||||
const setupSearch = (inputId, resultsId, searchUrl, linkPrefix) => {
|
||||
const input = document.getElementById(inputId);
|
||||
const results = document.getElementById(resultsId);
|
||||
@@ -119,22 +126,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
results.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
debounce = setTimeout(async () => {
|
||||
const resp = await fetch(`${searchUrl}?q=${encodeURIComponent(q)}`);
|
||||
const hits = await resp.json();
|
||||
if (hits.length === 0) {
|
||||
results.innerHTML = '<div class="px-4 py-3 text-xs text-gray-400">Aucun resultat.</div>';
|
||||
} else {
|
||||
results.innerHTML = hits.map(h =>
|
||||
`<a href="${linkPrefix}${h.id}" class="block px-4 py-2 hover:bg-gray-50 border-b border-gray-100 text-xs">
|
||||
<span class="font-bold">${h.fullName || h.raisonSociale || (h.firstName + ' ' + h.lastName)}</span>
|
||||
${h.email ? `<span class="text-gray-400 ml-2">${h.email}</span>` : ''}
|
||||
${h.codeRevendeur ? `<span class="ml-2 px-1 py-0.5 bg-gray-900 text-[#fabf04] text-[9px] font-bold">${h.codeRevendeur}</span>` : ''}
|
||||
</a>`
|
||||
).join('');
|
||||
}
|
||||
results.classList.remove('hidden');
|
||||
}, 300);
|
||||
debounce = setTimeout(() => performSearch(searchUrl, linkPrefix, results, q), 300);
|
||||
});
|
||||
|
||||
document.addEventListener('click', (e) => {
|
||||
|
||||
@@ -42,19 +42,19 @@
|
||||
<div class="border-2 border-gray-200 bg-gray-50 p-4">
|
||||
<table class="w-full text-sm">
|
||||
<tr class="border-b border-gray-200">
|
||||
<td class="py-2 pr-4 font-black uppercase text-xs text-gray-400 w-1/3">Prenom</td>
|
||||
<th scope="row" class="py-2 pr-4 font-black uppercase text-xs text-gray-400 w-1/3 text-left">Prenom</th>
|
||||
<td class="py-2 font-bold">{{ app.user.firstName }}</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-200">
|
||||
<td class="py-2 pr-4 font-black uppercase text-xs text-gray-400">Nom</td>
|
||||
<th scope="row" class="py-2 pr-4 font-black uppercase text-xs text-gray-400 text-left">Nom</th>
|
||||
<td class="py-2 font-bold">{{ app.user.lastName }}</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-200">
|
||||
<td class="py-2 pr-4 font-black uppercase text-xs text-gray-400">Email</td>
|
||||
<th scope="row" class="py-2 pr-4 font-black uppercase text-xs text-gray-400 text-left">Email</th>
|
||||
<td class="py-2 font-bold font-mono text-xs">{{ app.user.email }}</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-200">
|
||||
<td class="py-2 pr-4 font-black uppercase text-xs text-gray-400">Connexion</td>
|
||||
<th scope="row" class="py-2 pr-4 font-black uppercase text-xs text-gray-400 text-left">Connexion</th>
|
||||
<td class="py-2">
|
||||
{% if app.user.keycloakId %}
|
||||
<span class="px-2 py-0.5 bg-green-100 text-green-800 font-black uppercase text-[10px]">Keycloak</span>
|
||||
@@ -64,7 +64,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="py-2 pr-4 font-black uppercase text-xs text-gray-400">Inscrit le</td>
|
||||
<th scope="row" class="py-2 pr-4 font-black uppercase text-xs text-gray-400 text-left">Inscrit le</th>
|
||||
<td class="py-2 text-xs text-gray-500">{{ app.user.createdAt|date('d/m/Y a H:i') }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -34,11 +34,11 @@
|
||||
<div class="p-6">
|
||||
<table class="w-full text-sm">
|
||||
<tr class="border-b border-gray-200">
|
||||
<td class="py-3 pr-4 font-black uppercase text-xs text-gray-500 w-1/3">Reference</td>
|
||||
<th scope="row" class="py-3 pr-4 font-black uppercase text-xs text-gray-500 w-1/3 text-left">Reference</th>
|
||||
<td class="py-3 font-bold">{{ attestation.reference }}</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-200">
|
||||
<td class="py-3 pr-4 font-black uppercase text-xs text-gray-500">Type</td>
|
||||
<th scope="row" class="py-3 pr-4 font-black uppercase text-xs text-gray-500 text-left">Type</th>
|
||||
<td class="py-3 font-bold">
|
||||
{% if attestation.type == 'access' %}
|
||||
<span class="px-2 py-1 bg-indigo-100 text-indigo-800 text-xs font-black uppercase">Droit d'acces</span>
|
||||
@@ -50,15 +50,15 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-200">
|
||||
<td class="py-3 pr-4 font-black uppercase text-xs text-gray-500">Date</td>
|
||||
<th scope="row" class="py-3 pr-4 font-black uppercase text-xs text-gray-500 text-left">Date</th>
|
||||
<td class="py-3 font-bold">{{ attestation.createdAt|date('d/m/Y a H:i:s') }}</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-200">
|
||||
<td class="py-3 pr-4 font-black uppercase text-xs text-gray-500">Adresse IP</td>
|
||||
<th scope="row" class="py-3 pr-4 font-black uppercase text-xs text-gray-500 text-left">Adresse IP</th>
|
||||
<td class="py-3 font-bold font-mono">{{ attestation.ip }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="py-3 pr-4 font-black uppercase text-xs text-gray-500">Email</td>
|
||||
<th scope="row" class="py-3 pr-4 font-black uppercase text-xs text-gray-500 text-left">Email</th>
|
||||
<td class="py-3 font-bold">{{ attestation.email }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -6,31 +6,21 @@
|
||||
<title>{% block title %}CRM Ecosplay{% endblock %}</title>
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; background-color: #fbfbfb; font-family: Arial, Helvetica, sans-serif; color: #111827;">
|
||||
<table role="presentation" width="100%" style="background-color: #fbfbfb; padding: 40px 0;">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<p style="font-size: 11px; color: #666; margin: 0 0 16px 0; text-align: center;">
|
||||
Cet email ne s'affiche pas correctement ? <a href="__VIEW_URL__" style="color: #4338ca; text-decoration: underline;">Voir en ligne</a>
|
||||
</p>
|
||||
<table role="presentation" width="600" style="background-color: #ffffff; border: 4px solid #111827;">
|
||||
<tr>
|
||||
<td style="background-color: #fabf04; border-bottom: 4px solid #111827; padding: 20px; text-align: center;">
|
||||
<img src="https://crm.e-cosplay.fr/logo.jpg" alt="CRM Ecosplay" width="120" style="display: block; margin: 0 auto;">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 32px;">
|
||||
{% block content %}{% endblock %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="background-color: #111827; color: #ffffff; padding: 16px; text-align: center; font-size: 11px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px;">
|
||||
© {{ "now"|date("Y") }} Association E-Cosplay
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div style="background-color: #fbfbfb; padding: 40px 0; text-align: center;">
|
||||
<p style="font-size: 11px; color: #666; margin: 0 0 16px 0; text-align: center;">
|
||||
Cet email ne s'affiche pas correctement ? <a href="__VIEW_URL__" style="color: #4338ca; text-decoration: underline;">Voir en ligne</a>
|
||||
</p>
|
||||
<div style="max-width: 600px; margin: 0 auto; background-color: #ffffff; border: 4px solid #111827; text-align: left;">
|
||||
<div style="background-color: #fabf04; border-bottom: 4px solid #111827; padding: 20px; text-align: center;">
|
||||
<img src="https://crm.e-cosplay.fr/logo.jpg" alt="CRM Ecosplay" style="display: block; margin: 0 auto; width: 120px;">
|
||||
</div>
|
||||
<div style="padding: 32px;">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
<div style="background-color: #111827; color: #ffffff; padding: 16px; text-align: center; font-size: 11px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px;">
|
||||
© {{ "now"|date("Y") }} Association E-Cosplay
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<div style="background: #111827; color: #fff; padding: 20px; margin: 20px 0;">
|
||||
<p style="font-size: 11px; text-transform: uppercase; letter-spacing: 1px; margin: 0 0 12px; opacity: 0.7;">Vos identifiants de connexion</p>
|
||||
<table style="width: 100%; font-size: 14px;">
|
||||
<table role="presentation" style="width: 100%; font-size: 14px;">
|
||||
<tr>
|
||||
<td style="color: #fabf04; font-weight: bold; padding: 4px 0; width: 120px;">Email</td>
|
||||
<td style="color: #fff; padding: 4px 0;">{{ email }}</td>
|
||||
@@ -45,7 +45,7 @@
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
<table style="margin: 24px 0;">
|
||||
<table role="presentation" style="margin: 24px 0;">
|
||||
<tr>
|
||||
<td style="background: #fabf04; border: 2px solid #111827; padding: 12px 24px;">
|
||||
<a href="{{ url('app_home') }}" style="color: #111827; font-weight: 900; text-transform: uppercase; font-size: 13px; text-decoration: none; letter-spacing: 1px;">Se connecter</a>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<p style="font-size: 14px; line-height: 1.6; margin: 0 0 8px; font-weight: bold;">Pour acceder a votre espace, suivez ces etapes :</p>
|
||||
|
||||
<table style="width: 100%; margin: 16px 0;">
|
||||
<table role="presentation" style="width: 100%; margin: 16px 0;">
|
||||
<tr>
|
||||
<td style="padding: 12px 16px; border-left: 4px solid #fabf04; background: #f9fafb;">
|
||||
<p style="font-size: 12px; font-weight: 900; text-transform: uppercase; color: #fabf04; margin: 0 0 4px;">Etape 1</p>
|
||||
@@ -36,7 +36,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table style="margin: 24px 0; width: 100%;">
|
||||
<table role="presentation" style="margin: 24px 0; width: 100%;">
|
||||
<tr>
|
||||
<td style="background: #fabf04; border: 2px solid #111827; padding: 14px 24px; text-align: center;">
|
||||
<a href="{{ setPasswordUrl }}" style="color: #111827; font-weight: 900; text-transform: uppercase; font-size: 14px; text-decoration: none; letter-spacing: 1px;">Definir mon mot de passe</a>
|
||||
@@ -44,7 +44,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table style="margin: 0 0 24px; width: 100%;">
|
||||
<table role="presentation" style="margin: 0 0 24px; width: 100%;">
|
||||
<tr>
|
||||
<td style="background: #fff; border: 2px solid #111827; padding: 12px 24px; text-align: center;">
|
||||
<a href="{{ url('app_home') }}" style="color: #111827; font-weight: 900; text-transform: uppercase; font-size: 12px; text-decoration: none; letter-spacing: 1px;">Acceder a la page de connexion</a>
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
<div style="background: #f9fafb; padding: 16px; border: 1px solid #e5e7eb; margin: 16px 0;">
|
||||
<p style="font-size: 12px; font-weight: bold; margin: 0 0 8px;">Informations de votre compte :</p>
|
||||
<table style="font-size: 12px; width: 100%;">
|
||||
<table role="presentation" style="font-size: 12px; width: 100%;">
|
||||
<tr>
|
||||
<td style="padding: 2px 0; color: #666; width: 120px;">Code revendeur</td>
|
||||
<td style="padding: 2px 0; font-weight: bold; font-family: monospace;">{{ codeRevendeur }}</td>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<h1 style="font-size: 20px; font-weight: bold; text-transform: uppercase; margin: 0 0 16px 0;">Attestation RGPD signee</h1>
|
||||
<p style="font-size: 14px; line-height: 1.6; margin: 0 0 16px 0;">Bonjour,</p>
|
||||
<p style="font-size: 14px; line-height: 1.6; margin: 0 0 16px 0;">Suite a votre demande, vous trouverez en piece jointe votre <strong>attestation d'{{ typeName }}</strong>, signee electroniquement par l'association E-Cosplay.</p>
|
||||
<table style="margin: 16px 0; font-size: 13px; width: 100%;">
|
||||
<table role="presentation" style="margin: 16px 0; font-size: 13px; width: 100%;">
|
||||
<tr>
|
||||
<td style="padding: 8px 12px; background: #f9fafb; border-left: 3px solid #fabf04; font-weight: bold;">Reference</td>
|
||||
<td style="padding: 8px 12px; background: #f9fafb;">{{ attestation.reference }}</td>
|
||||
|
||||
@@ -50,10 +50,10 @@
|
||||
<div class="subtitle">RGPD — Article 15</div>
|
||||
<table class="info-grid">
|
||||
<tr>
|
||||
<td class="info-cell" width="25%"><span class="info-label">Reference</span><span class="info-value">{{ attestation.reference }}</span></td>
|
||||
<td class="info-cell" width="25%"><span class="info-label">Date</span><span class="info-value">{{ date|date('d/m/Y a H:i') }}</span></td>
|
||||
<td class="info-cell" width="25%"><span class="info-label">Adresse IP</span><span class="info-value">{{ ip }}</span></td>
|
||||
<td class="info-cell" width="25%"><span class="info-label">Sessions</span><span class="info-value">{{ data|length }}</span></td>
|
||||
<td class="info-cell" style="width: 25%;"><span class="info-label">Reference</span><span class="info-value">{{ attestation.reference }}</span></td>
|
||||
<td class="info-cell" style="width: 25%;"><span class="info-label">Date</span><span class="info-value">{{ date|date('d/m/Y a H:i') }}</span></td>
|
||||
<td class="info-cell" style="width: 25%;"><span class="info-label">Adresse IP</span><span class="info-value">{{ ip }}</span></td>
|
||||
<td class="info-cell" style="width: 25%;"><span class="info-label">Sessions</span><span class="info-value">{{ data|length }}</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<div class="session-meta"><strong>ID :</strong> {{ entry.visitor.id }} — <strong>Visite :</strong> {{ entry.visitor.createdAt|date('d/m/Y H:i') }}</div>
|
||||
{% if entry.events|length > 0 %}
|
||||
<table class="data">
|
||||
<thead><tr><th width="25%">Date</th><th width="20%">Type</th><th width="55%">Page</th></tr></thead>
|
||||
<thead><tr><th style="width: 25%;">Date</th><th style="width: 20%;">Type</th><th style="width: 55%;">Page</th></tr></thead>
|
||||
<tbody>
|
||||
{% for event in entry.events %}
|
||||
<tr><td>{{ event.createdAt|date('d/m/Y H:i:s') }}</td><td>{{ event.type }}</td><td>{{ event.page }}</td></tr>
|
||||
|
||||
@@ -48,9 +48,9 @@
|
||||
<div class="subtitle">RGPD — Article 17</div>
|
||||
<table class="info-grid">
|
||||
<tr>
|
||||
<td class="info-cell" width="33%"><span class="info-label">Reference</span><span class="info-value">{{ attestation.reference }}</span></td>
|
||||
<td class="info-cell" width="33%"><span class="info-label">Date</span><span class="info-value">{{ date|date('d/m/Y a H:i') }}</span></td>
|
||||
<td class="info-cell" width="33%"><span class="info-label">Adresse IP</span><span class="info-value">{{ ip }}</span></td>
|
||||
<td class="info-cell" style="width: 33%;"><span class="info-label">Reference</span><span class="info-value">{{ attestation.reference }}</span></td>
|
||||
<td class="info-cell" style="width: 33%;"><span class="info-label">Date</span><span class="info-value">{{ date|date('d/m/Y a H:i') }}</span></td>
|
||||
<td class="info-cell" style="width: 33%;"><span class="info-label">Adresse IP</span><span class="info-value">{{ ip }}</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="attestation-box">
|
||||
|
||||
@@ -47,9 +47,9 @@
|
||||
<div class="subtitle">RGPD — Article 15</div>
|
||||
<table class="info-grid">
|
||||
<tr>
|
||||
<td class="info-cell" width="33%"><span class="info-label">Reference</span><span class="info-value">{{ attestation.reference }}</span></td>
|
||||
<td class="info-cell" width="33%"><span class="info-label">Date</span><span class="info-value">{{ date|date('d/m/Y a H:i') }}</span></td>
|
||||
<td class="info-cell" width="33%"><span class="info-label">Adresse IP</span><span class="info-value">{{ ip }}</span></td>
|
||||
<td class="info-cell" style="width: 33%;"><span class="info-label">Reference</span><span class="info-value">{{ attestation.reference }}</span></td>
|
||||
<td class="info-cell" style="width: 33%;"><span class="info-label">Date</span><span class="info-value">{{ date|date('d/m/Y a H:i') }}</span></td>
|
||||
<td class="info-cell" style="width: 33%;"><span class="info-label">Adresse IP</span><span class="info-value">{{ ip }}</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="attestation-box">
|
||||
|
||||
Reference in New Issue
Block a user