Grille des Experts L'pieces

Légende avis : 📦 = notes sur les transactions pièce (marketplace) · 🔩 = notes sur la prestation atelier (carnet / MO). Les deux séries sont calculées séparément ; un même pro peut avoir les deux.

Trouve un pro près de toi — choisis ta zone (Rabat-Salé-Témara), marque voiture, type d'aide.

Effacer

Marques voiture (défilant)

Marques pièces (défilant)

🗺️ Carte des experts

0 sur la carte · 0 au total

🛒 Vendeur · 🔧 Réparateur méca · ⚡ Électricien · 🎨 Tôlier — Clique un marker → popup expert + lien vers sa carte ci-dessous

Aucun expert disponible sur la grille pour le moment.

(string → JSON) function parseJsonScript(id, fallback) { const node = document.getElementById(id); if (!node) return fallback; try { return JSON.parse(node.textContent); } catch (e) { console.warn('Bad JSON in #' + id, e); return fallback; } } const rawData = parseJsonScript('experts-map-json', '[]'); // experts_map_json est dumpé string JSON par la view → reparse const markers = (typeof rawData === 'string') ? JSON.parse(rawData) : rawData; const center = parseJsonScript('experts-map-center-json', {lat: 33.8, lng: -7.2, zoom: 7}); // Init map OSM (doctrine zéro Google Maps) const map = L.map('experts-map', { scrollWheelZoom: false, // évite scroll-jacking sur la page tap: true, // mobile-friendly }).setView([center.lat, center.lng], center.zoom); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18, attribution: '© OpenStreetMap', }).addTo(map); // CEO 10/05 — Me localiser control natif HTML5 geolocation + OSM marker if (window.LpGeolocate) { LpGeolocate.addControl(map); } // Activer scrollWheelZoom au focus user (UX) map.on('focus', function() { map.scrollWheelZoom.enable(); }); map.on('blur', function() { map.scrollWheelZoom.disable(); }); if (!markers || markers.length === 0) { const empty = L.marker([center.lat, center.lng], {opacity: 0}); empty.bindPopup('Aucun expert localisé pour ces filtres. Élargis ta recherche ou supprime un filtre.').addTo(map); empty.openPopup(); return; } // Création markers (divIcon emoji + couleur pastille) function makeIcon(emoji, color) { return L.divIcon({ className: 'gx-map-marker-icon', html: '
' + '' + emoji + '
', iconSize: [32, 32], iconAnchor: [16, 32], popupAnchor: [0, -28], }); } function escapeHtml(s) { return String(s == null ? '' : s) .replace(/&/g, '&').replace(//g, '>') .replace(/"/g, '"').replace(/'/g, '''); } const bounds = []; const markerGroup = L.layerGroup().addTo(map); markers.forEach(function(m) { if (typeof m.lat !== 'number' || typeof m.lng !== 'number') return; const marqueListHtml = (m.marques && m.marques.length) ? '

🛠️ ' + m.marques.map(escapeHtml).join(', ') + '

' : ''; const sourceTag = (m.coord_source === 'ville_fallback') ? '(centre ville approx.)' : ''; const popupHtml = '

' + m.icon + ' ' + escapeHtml(m.nom) + '

' + '

📍 ' + escapeHtml(m.ville) + ' ' + sourceTag + '

' + '

' + escapeHtml(m.role) + (m.specialite ? ' · ' + escapeHtml(m.specialite) : '') + '

' + marqueListHtml + '

⭐ Niyya ' + m.score + '/100 · ' + m.ventes + ' vente(s)

' + 'Voir sa fiche ↓'; const marker = L.marker([m.lat, m.lng], {icon: makeIcon(m.icon, m.color), title: m.nom + ' — ' + m.ville}); marker.bindPopup(popupHtml); marker.addTo(markerGroup); bounds.push([m.lat, m.lng]); // Click marker → scroll vers card grille (sans changer URL) marker.on('popupopen', function() { const link = document.querySelector('.leaflet-popup-content .gx-map-popup-link'); if (link) link.addEventListener('click', function(ev) { const target = document.querySelector(link.getAttribute('href')); if (target) { ev.preventDefault(); target.scrollIntoView({behavior: 'smooth', block: 'center'}); target.style.outline = '2px solid var(--accent, #e85d4c)'; setTimeout(function() { target.style.outline = ''; }, 1800); } }); }); }); // Auto-fit bounds si plus d'1 marker ET pas de filtre ville (sinon respecte le centre ville filtré) const villeFilter = ""; if (markers.length > 1 && !villeFilter) { try { map.fitBounds(bounds, {padding: [30, 30], maxZoom: 11}); } catch (e) { /* keep default center */ } } })();