Add search and PARCOURSMOB integration
All checks were successful
Publish To Prod / deploy_and_publish (push) Successful in 40s

This commit is contained in:
Arnaud Delcasse
2026-01-07 11:46:19 +01:00
parent ed5dade5c3
commit 36dd81e661
10 changed files with 14048 additions and 110 deletions

View File

@@ -0,0 +1,161 @@
{{ define "main" }}
<!-- Placeholder pour les données hydratées par Parcoursmob -->
<script id="dynamic-data" type="application/json"></script>
{{ $iconSearch := resources.Get "images/picto/search_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg" }}
{{ $iconArrow := resources.Get "images/picto/arrow_right_alt_24dp_1F1F1F_FILL1_wght400_GRAD0_opsz24.svg" }}
<section class="page-recherche" x-data="rechercheApp()" :class="{ 'has-results': searched }">
<!-- Formulaire de recherche (caché en mobile si recherche effectuée) -->
<div class="search-form-container" :class="{ 'hide-on-mobile-searched': searched }">
{{ partial "search-block.html" (dict "showTitle" false "action" "/recherche/") }}
</div>
<!-- Résultats de recherche -->
<template x-if="searched">
<div class="search-results-wrapper">
<!-- Carte en premier sur mobile -->
<div class="mobile-map-container">
<div id="mobile-map"></div>
</div>
<!-- Résumé compact de recherche (mobile uniquement) -->
<div class="compact-search-summary">
<a href="/recherche/" class="compact-search-content">
<div class="compact-search-route">
<span class="compact-search-place" x-text="departureLabel"></span>
{{ if $iconArrow }}<img src="{{ $iconArrow.RelPermalink }}" alt="" class="compact-search-arrow" />{{ end }}
<span class="compact-search-place" x-text="destinationLabel"></span>
</div>
<div class="compact-search-date" x-text="formatSearchDate()"></div>
</a>
<a href="/recherche/" class="compact-search-icon">
{{ if $iconSearch }}<img src="{{ $iconSearch.RelPermalink }}" alt="Modifier la recherche" />{{ end }}
</a>
</div>
{{ partial "search-results.html" . }}
</div>
</template>
</section>
<script>
function rechercheApp() {
const data = window.__PARCOURSMOB_DATA__ || {};
return {
searched: data.searched || false,
results: data.results || {},
selectedJourney: null,
departure: data.departure || null,
destination: data.destination || null,
departureDate: data.departure_date || '',
departureTime: data.departure_time || '',
get departureLabel() {
return this.departure?.properties?.label || this.departure?.properties?.name || 'Départ';
},
get destinationLabel() {
return this.destination?.properties?.label || this.destination?.properties?.name || 'Destination';
},
formatSearchDate() {
if (!this.departureDate) return '';
const [year, month, day] = this.departureDate.split('-');
const date = new Date(year, month - 1, day);
const formatted = date.toLocaleDateString('fr-FR', { weekday: 'long', day: 'numeric', month: 'long' });
return this.departureTime ? formatted + ' à ' + this.departureTime : formatted;
},
get totalResults() {
const r = this.results;
return (r.solidarity_drivers?.number || 0) +
(r.organized_carpools?.number || 0) +
(r.public_transit?.number || 0) +
(r.vehicles?.number || 0) +
(r.local_solutions?.number || 0);
},
showJourneyOnMap(journey, index) {
console.log('showJourneyOnMap called', index, journey);
this.selectedJourney = index;
if (!window.parcoursmobMap) {
console.log('Map not found');
return;
}
const map = window.parcoursmobMap;
// Supprimer l'ancien tracé s'il existe
if (map.getSource('journey-route')) {
map.removeLayer('journey-route-line');
map.removeSource('journey-route');
}
// Collecter toutes les coordonnées des legs
const coordinates = [];
journey.legs.forEach(leg => {
if (leg.legGeometry && leg.legGeometry.points) {
try {
const decoded = polyline.decode(leg.legGeometry.points);
decoded.forEach(point => {
const lng = point[1];
const lat = point[0];
if (lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180) {
coordinates.push([lng, lat]);
}
});
} catch (e) {
console.error('Erreur décodage polyline:', e);
}
} else if (leg.from && leg.to) {
const fromLng = leg.from.lon || leg.from.lng;
const fromLat = leg.from.lat;
const toLng = leg.to.lon || leg.to.lng;
const toLat = leg.to.lat;
if (fromLat && fromLng) coordinates.push([fromLng, fromLat]);
if (toLat && toLng) coordinates.push([toLng, toLat]);
}
});
if (coordinates.length < 2) return;
// Ajouter le tracé sur la carte
map.addSource('journey-route', {
type: 'geojson',
data: {
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: coordinates
}
}
});
map.addLayer({
id: 'journey-route-line',
type: 'line',
source: 'journey-route',
layout: {
'line-join': 'round',
'line-cap': 'round'
},
paint: {
'line-color': '#283959',
'line-width': 4
}
});
// Ajuster la vue pour montrer tout le tracé
const bounds = new maplibregl.LngLatBounds();
coordinates.forEach(coord => bounds.extend(coord));
map.fitBounds(bounds, { padding: 50 });
}
};
}
</script>
{{ end }}