templates/partials/_etablissements_cards.html.twig line 1
{% for etablissement in etablissements %}{# ============================================================CARTE ÉTABLISSEMENT UNIQUE — Design premium centréAncien code de la grille multiple conservé ci-dessous en commentaire.ANCIEN CODE (carte petite pour grille 3 colonnes) :<div class="group bg-white rounded-xl border border-slate-200 p-5 ...">... (voir git history ou RESUME_MODIFICATIONS.txt)</div>============================================================ #}<div class="w-full h-full flex flex-col etablissement-card">{# --- En-tête blanc --- #}<div class="bg-white border border-indigo-100 rounded-t-2xl px-4 py-4 text-center shadow-sm"><div class="w-14 h-14 bg-indigo-100 rounded-full flex items-center justify-center mx-auto mb-3"><i class="fas fa-school text-2xl text-indigo-600"></i></div><h3 class="text-xl font-bold text-slate-900 leading-tight">{{ etablissement.nom }}</h3>{% if etablissement.localite %}<p class="text-xs text-slate-500 mt-2"><i class="fas fa-map-marker-alt mr-1 text-indigo-400"></i>{{ etablissement.localite.nom }}{% if etablissement.localite.directionRegionale %}— {{ etablissement.localite.directionRegionale.nom }}{% endif %}</p>{% endif %}</div>{# --- Corps principal --- #}<div class="bg-white rounded-b-2xl border border-t-0 border-indigo-100 shadow-lg px-4 py-4 flex-grow flex flex-col">{# --- Stats résumées --- #}{% set totalPlaces = 0 %}{% for em in etablissement.etablissementMetiers %}{% set totalPlaces = totalPlaces + (em.nbrplace ?? 0) %}{% endfor %}<div class="flex justify-center gap-4 mb-4 py-2 bg-indigo-50 rounded-xl"><div class="text-center"><div class="text-2xl font-bold text-indigo-600">{{ etablissement.etablissementMetiers|length }}</div><div class="text-[10px] text-slate-500 mt-0.5 uppercase font-semibold">Métier(s)</div></div><div class="w-px bg-indigo-200"></div><div class="text-center"><div class="text-2xl font-bold text-green-600">{{ totalPlaces }}</div><div class="text-[10px] text-slate-500 mt-0.5 uppercase font-semibold">Place(s)</div></div></div>{# --- Liste des métiers avec bouton "Voir les options" --- #}{% if etablissement.etablissementMetiers|length > 0 %}<div class="mb-5 flex-grow"><h4 class="text-xs font-semibold text-slate-500 uppercase tracking-wider mb-3"><i class="fas fa-briefcase mr-2 text-indigo-400"></i>Métiers disponibles</h4><div class="space-y-2 h-32 overflow-y-auto pr-1 custom-scrollbar">{% for em in etablissement.etablissementMetiers %}{% if em.metier %}<div class="flex flex-col sm:flex-row sm:items-center justify-between w-full px-3 py-2.5 bg-slate-50 border border-slate-200 rounded-xl gap-2"><div class="flex items-center gap-3"><div class="w-7 h-7 bg-indigo-100 rounded-lg flex items-center justify-center flex-shrink-0"><i class="fas fa-hard-hat text-indigo-600 text-[10px]"></i></div><div class="text-left leading-tight"><span class="text-sm font-semibold text-slate-800 block">{{ em.metier.nom }}</span>{% if em.nbrplace is defined and em.nbrplace %}<span class="text-[10px] text-slate-500">{{ em.nbrplace }} place(s)</span>{% endif %}</div></div>{# Bouton "Voir les options" — ouvre le modal #}<button type="button"onclick="ouvrirOptionsMetier('{{ em.metier.nom|e('html_attr') }}')"class="text-[10px] font-semibold text-indigo-600 bg-indigo-100 hover:bg-indigo-600 hover:text-white px-2.5 py-1.5 rounded-full transition-all flex items-center gap-1 self-start sm:self-auto flex-shrink-0"><i class="fas fa-eye text-[9px]"></i> Voir les options</button></div>{% endif %}{% endfor %}</div></div>{% else %}<div class="mb-5 flex-grow"><div class="h-32 flex items-center justify-center border-2 border-dashed border-slate-200 rounded-xl"><p class="text-xs text-slate-400">Aucun métier disponible</p></div></div>{% endif %}{# --- CTA principal --- #}<div class="mt-auto pt-2"><a href="{{ path('app_register') }}?etablissement={{ etablissement.id }}"class="block w-full text-center bg-gradient-to-r from-indigo-600 to-purple-600 hover:from-indigo-700 hover:to-purple-700 text-white font-bold py-3 rounded-xl transition-all transform hover:-translate-y-0.5 hover:shadow-lg text-sm"><i class="fas fa-paper-plane mr-2"></i>Candidater ici</a></div></div></div>{% else %}<div class="col-span-full text-center py-12"><div class="w-16 h-16 bg-slate-100 rounded-full flex items-center justify-center mx-auto mb-4"><i class="fas fa-school text-2xl text-slate-400"></i></div><p class="text-lg text-white font-semibold">Aucun établissement trouvé</p><p class="text-sm text-white/70">Vérifiez la configuration de l'ID établissement</p></div>{% endfor %}{# ============================================================MODAL "VOIR LES OPTIONS" — Affiché au clic sur un métierContenu extrait des documents officiels (images fournies).============================================================ #}<div id="modal-options-metier"class="fixed inset-0 z-50 hidden overflow-y-auto"role="dialog" aria-modal="true">{# Overlay #}<div class="fixed inset-0 bg-slate-900/70 backdrop-blur-sm"onclick="fermerOptionsMetier()"></div>{# Panneau #}<div class="relative min-h-screen flex items-start justify-center pt-8 pb-12 px-4"><div class="relative bg-white rounded-2xl shadow-2xl w-full max-w-2xl overflow-hidden">{# En-tête du modal #}<div class="bg-gradient-to-r from-indigo-600 to-purple-600 px-6 py-4 flex items-center justify-between"><div><p class="text-xs text-white/70 font-medium uppercase tracking-wider mb-0.5">Options du métier</p><h3 id="modal-metier-titre" class="text-lg font-bold text-white"></h3></div><button onclick="fermerOptionsMetier()"class="w-8 h-8 bg-white/20 hover:bg-white/30 rounded-full flex items-center justify-center transition"><i class="fas fa-times text-white text-sm"></i></button></div>{# Bandeau info consultatif #}<div class="bg-amber-50 border-b border-amber-100 px-6 py-2 flex items-center gap-2"><i class="fas fa-info-circle text-amber-500 text-sm"></i><p class="text-xs text-amber-700">Ces informations sont fournies à titre consultatif.</p></div>{# Corps : tableau des options #}<div class="px-6 py-5 max-h-[70vh] overflow-y-auto"><div id="modal-options-contenu"></div>{# Message si métier non trouvé #}<div id="modal-options-vide" class="hidden text-center py-10"><i class="fas fa-search text-3xl text-slate-300 mb-3"></i><p class="text-slate-500 text-sm">Aucune option détaillée disponible pour ce métier.</p></div></div>{# Pied du modal #}<div class="px-6 py-4 border-t border-slate-100 flex justify-between items-center bg-slate-50"><p class="text-xs text-slate-400"><i class="fas fa-file-alt mr-1"></i>Certificat de Formation Qualifiante — DAIP 2026</p><button onclick="fermerOptionsMetier()"class="px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white text-sm font-semibold rounded-lg transition">Fermer</button></div></div></div></div>{# ============================================================DONNÉES DES OPTIONS — Extraites des documents officielsClé = nom du métier (doit correspondre au nom en base).============================================================ #}<script>const METIERS_OPTIONS = {"COUTURE INDUSTRIELLE": {description: "Certificat de Formation Qualifiante",options: [{ nom: "CHEMISE / TUNIQUE CLASSIQUE HOMME/DAME", niveau: "CEPE (18 ans - 40 ans)", duree: "4 mois", places: 20 },{ nom: "JEANS ET TENUE DE TRAVAIL", niveau: "CEPE (18 ans - 40 ans)", duree: "4 mois", places: 20 },{ nom: "JUPE, ROBE ET BUSTIER", niveau: "CEPE (18 ans - 40 ans)", duree: "4 mois", places: 20 },{ nom: "PANTALON CLASSIQUE HOMME/DAME", niveau: "CEPE (18 ans - 40 ans)", duree: "4 mois", places: 20 },{ nom: "VESTE HOMME/DAME", niveau: "CEPE (20 ans - 40 ans)", duree: "4 mois", places: 20 },{ nom: "CHAPELIER MODISTE", niveau: "CEPE (18 ans - 40 ans)", duree: "4 mois", places: 10 },{ nom: "T-SHIRT ET POLO", niveau: "CEPE (18 ans - 40 ans)", duree: "4 mois", places: 20 },{ nom: "SAC ET PORTEFEUILLE", niveau: "CEPE (18 ans - 40 ans)", duree: "4 mois", places: 10 },]},"MODELISME": {description: "Certificat de Formation Qualifiante",options: [{ nom: "COUPE HOMME", niveau: "BEPC (25 ans - 40 ans)", duree: "4 mois", places: 6 },{ nom: "COUPE DAME", niveau: "BEPC (25 ans - 40 ans)", duree: "4 mois", places: 6 },{ nom: "COUPE VESTE HOMME/DAME", niveau: "BEPC (25 ans - 40 ans)", duree: "4 mois", places: 6 },{ nom: "COUPE INDUSTRIELLE", niveau: "BEPC (25 ans - 40 ans)", duree: "4 mois", places: 6 },]},// Support du pluriel"METIERS DE LA MODE": {description: "Certificat de Formation Qualifiante",options: [{ nom: "AGENT DE NETTOYAGE ET DE MARQUAGE", niveau: "CEPE (20 ans - 40 ans)", duree: "4 mois", places: 6 },{ nom: "AGENT CONTROLEUR QUALITE ET FINITION", niveau: "CEPE (20 ans - 40 ans)", duree: "4 mois", places: 6 },]},// Support du singulier"METIER DE LA MODE": {description: "Certificat de Formation Qualifiante",options: [{ nom: "AGENT DE NETTOYAGE ET DE MARQUAGE", niveau: "CEPE (20 ans - 40 ans)", duree: "4 mois", places: 6 },{ nom: "AGENT CONTROLEUR QUALITE ET FINITION", niveau: "CEPE (20 ans - 40 ans)", duree: "4 mois", places: 6 },]},"BRODERIE": {description: "Certificat de Formation Qualifiante",options: [{ nom: "BRODERIE SUR MACHINE AUTOMATISEE", niveau: "CEPE (18 ans - 40 ans)", duree: "4 mois", places: 10 },{ nom: "GRAPHISTE BRODERIE", niveau: "BEPC avec bonne notion en outil informatique (20 ans - 40 ans)", duree: "4 mois", places: 4 },]},"SERIGRAPHIE": {description: "Certificat de Formation Qualifiante",options: [{ nom: "SERIGRAPHE", niveau: "CEPE (18 ans - 40 ans)", duree: "4 mois", places: 6 },{ nom: "GRAPHISTE IMPRESSION NUMERIQUE", niveau: "BEPC avec bonne notion en outil informatique (20 ans - 40 ans)", duree: "4 mois", places: 4 },]}};// ---- Recherche floue : tolère les majuscules/minuscules, espaces et accents ----function trouverMetier(nomBrut) {// Supprimer les accents (ex: É -> E) et mettre en majusculesconst nomNorm = nomBrut.normalize("NFD").replace(/[\u0300-\u036f]/g, "").trim().toUpperCase();// Correspondance exacteif (METIERS_OPTIONS[nomNorm]) return METIERS_OPTIONS[nomNorm];// Correspondance partielleconst cle = Object.keys(METIERS_OPTIONS).find(k => nomNorm.includes(k) || k.includes(nomNorm));return cle ? METIERS_OPTIONS[cle] : null;}function ouvrirOptionsMetier(nomMetier) {const modal = document.getElementById('modal-options-metier');const titre = document.getElementById('modal-metier-titre');const contenu = document.getElementById('modal-options-contenu');const vide = document.getElementById('modal-options-vide');titre.textContent = nomMetier;const data = trouverMetier(nomMetier);if (data && data.options && data.options.length > 0) {vide.classList.add('hidden');contenu.classList.remove('hidden');let html = `<p class="text-xs text-slate-500 mb-4 font-medium"><i class="fas fa-certificate mr-1 text-indigo-400"></i>${data.description}</p><div class="overflow-x-auto rounded-xl border border-slate-200"><table class="w-full text-sm"><thead><tr class="bg-indigo-50 text-indigo-700 text-xs uppercase tracking-wider"><th class="px-4 py-3 text-left font-semibold">Option</th><th class="px-4 py-3 text-left font-semibold">Niveau requis</th><th class="px-3 py-3 text-center font-semibold">Durée</th><th class="px-3 py-3 text-center font-semibold">Places</th></tr></thead><tbody class="divide-y divide-slate-100">`;data.options.forEach((opt, i) => {html += `<tr class="${i % 2 === 0 ? 'bg-white' : 'bg-slate-50'} hover:bg-indigo-50/40 transition-colors"><td class="px-4 py-3 font-semibold text-slate-800">${opt.nom}</td><td class="px-4 py-3 text-slate-600 text-xs">${opt.niveau}</td><td class="px-3 py-3 text-center"><span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-purple-100 text-purple-700"><i class="fas fa-clock mr-1 text-[9px]"></i>${opt.duree}</span></td><td class="px-3 py-3 text-center"><span class="inline-flex items-center justify-center w-8 h-8 rounded-full text-sm font-bold bg-green-100 text-green-700">${opt.places}</span></td></tr>`;});html += `</tbody></table></div>`;contenu.innerHTML = html;} else {contenu.innerHTML = '';vide.classList.remove('hidden');}modal.classList.remove('hidden');document.body.style.overflow = 'hidden';}function fermerOptionsMetier() {document.getElementById('modal-options-metier').classList.add('hidden');document.body.style.overflow = '';}// Fermer avec Échapdocument.addEventListener('keydown', e => {if (e.key === 'Escape') fermerOptionsMetier();});</script>