Compact search improvements + drivers map in the dashboard
This commit is contained in:
parent
5d546c0efc
commit
c7d263fded
|
@ -78,6 +78,7 @@ views:
|
||||||
- web/layouts/dashboard/_partials/agenda-widget.html
|
- web/layouts/dashboard/_partials/agenda-widget.html
|
||||||
- web/layouts/dashboard/_partials/beneficiaries-widget.html
|
- web/layouts/dashboard/_partials/beneficiaries-widget.html
|
||||||
- web/layouts/dashboard/_partials/bookings-widget.html
|
- web/layouts/dashboard/_partials/bookings-widget.html
|
||||||
|
- web/layouts/dashboard/_partials/drivers-map-widget.html
|
||||||
- web/layouts/dashboard/dashboard.html
|
- web/layouts/dashboard/dashboard.html
|
||||||
beneficiaries:
|
beneficiaries:
|
||||||
list:
|
list:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{{define "beneficiary_journeys"}}
|
{{define "beneficiary_journeys"}}
|
||||||
<div class="px-4 py-6 sm:px-6">
|
<div class="px-4 py-6 sm:px-6">
|
||||||
<form action="/app/journeys/" method="GET">
|
<form action="{{if eq $.ViewState.search_view "compact"}}/app/journeys/search{{else}}/app/journeys/{{end}}" method="GET">
|
||||||
|
|
||||||
{{ $departureField := "departure" }}
|
{{ $departureField := "departure" }}
|
||||||
{{ $departureLabel := "Départ" }}
|
{{ $departureLabel := "Départ" }}
|
||||||
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
{{define "drivers_map_widget"}}
|
||||||
|
<div class="bg-white overflow-hidden shadow rounded-2xl">
|
||||||
|
<div class="p-6">
|
||||||
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||||
|
Carte des conducteurs
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="drivers-map" class="w-full rounded-lg overflow-hidden border border-gray-200" style="height: 500px;"></div>
|
||||||
|
|
||||||
|
<div class="mt-4 flex items-center justify-center gap-6 text-sm">
|
||||||
|
{{if moduleAvailable "solidarity_transport"}}
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="w-6 h-6 rounded-co bg-co-blue border border-white shadow-md mr-2"></div>
|
||||||
|
<span class="text-gray-700">Transport solidaire ({{len .solidarity_drivers}})</span>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{if moduleAvailable "organized_carpool"}}
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="w-6 h-6 rounded-co bg-co-green border border-white shadow-md mr-2"></div>
|
||||||
|
<span class="text-gray-700">Covoiturage solidaire ({{len .organized_carpool_drivers}})</span>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Check if map libraries are available
|
||||||
|
if (typeof maplibregl === 'undefined' || typeof pmtiles === 'undefined') {
|
||||||
|
console.warn('Map libraries not available');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize PMTiles protocol
|
||||||
|
let protocol = new pmtiles.Protocol();
|
||||||
|
maplibregl.addProtocol("pmtiles", protocol.tile);
|
||||||
|
|
||||||
|
// Initialize map centered on France with protomaps style
|
||||||
|
const map = new maplibregl.Map({
|
||||||
|
container: 'drivers-map',
|
||||||
|
style: '/public/maps/protomaps-light/style.json',
|
||||||
|
center: [2.3522, 48.8566], // Paris
|
||||||
|
zoom: 5
|
||||||
|
});
|
||||||
|
|
||||||
|
map.addControl(new maplibregl.NavigationControl(), 'top-right');
|
||||||
|
|
||||||
|
const bounds = new maplibregl.LngLatBounds();
|
||||||
|
let hasMarkers = false;
|
||||||
|
|
||||||
|
map.on('load', function() {
|
||||||
|
// Add solidarity transport drivers
|
||||||
|
{{if moduleAvailable "solidarity_transport"}}
|
||||||
|
const solidarityDrivers = [
|
||||||
|
{{range .solidarity_drivers}}
|
||||||
|
{{if .Data.address}}
|
||||||
|
{
|
||||||
|
name: '{{.Data.first_name}} {{.Data.last_name}}',
|
||||||
|
coordinates: {{if and .Data.address.geometry .Data.address.geometry.coordinates}}[{{index .Data.address.geometry.coordinates 0}}, {{index .Data.address.geometry.coordinates 1}}]{{else}}null{{end}},
|
||||||
|
address: {{if .Data.address.properties}}'{{.Data.address.properties.label}}'{{else}}''{{end}},
|
||||||
|
type: 'solidarity-transport',
|
||||||
|
driverId: '{{.ID}}'
|
||||||
|
},
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
].filter(d => d.coordinates !== null);
|
||||||
|
|
||||||
|
solidarityDrivers.forEach(function(driver) {
|
||||||
|
// Create custom marker element matching compact search style
|
||||||
|
const el = document.createElement('div');
|
||||||
|
el.className = 'w-8 h-8 rounded-co bg-co-blue border border-white shadow-md flex items-center justify-center cursor-pointer';
|
||||||
|
|
||||||
|
// User icon matching compact search
|
||||||
|
el.innerHTML = `
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
||||||
|
<circle cx="12" cy="7" r="4"></circle>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const marker = new maplibregl.Marker({element: el})
|
||||||
|
.setLngLat(driver.coordinates)
|
||||||
|
.setPopup(new maplibregl.Popup({offset: 25, className: 'rounded-lg'})
|
||||||
|
.setHTML(`
|
||||||
|
<div class="p-3">
|
||||||
|
<a href="/app/solidarity-transport/drivers/${driver.driverId}" class="font-semibold text-sm text-gray-900 hover:text-co-blue">${driver.name}</a>
|
||||||
|
<p class="text-xs text-gray-600 mt-1">${driver.address}</p>
|
||||||
|
<p class="text-xs text-co-blue font-medium mt-2">Transport solidaire</p>
|
||||||
|
</div>
|
||||||
|
`))
|
||||||
|
.addTo(map);
|
||||||
|
|
||||||
|
bounds.extend(driver.coordinates);
|
||||||
|
hasMarkers = true;
|
||||||
|
});
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
// Add organized carpool drivers
|
||||||
|
{{if moduleAvailable "organized_carpool"}}
|
||||||
|
const organizedCarpoolDrivers = [
|
||||||
|
{{range .organized_carpool_drivers}}
|
||||||
|
{{if .Data.address}}
|
||||||
|
{
|
||||||
|
name: '{{.Data.first_name}} {{.Data.last_name}}',
|
||||||
|
coordinates: {{if and .Data.address.geometry .Data.address.geometry.coordinates}}[{{index .Data.address.geometry.coordinates 0}}, {{index .Data.address.geometry.coordinates 1}}]{{else}}null{{end}},
|
||||||
|
address: {{if .Data.address.properties}}'{{.Data.address.properties.label}}'{{else}}''{{end}},
|
||||||
|
type: 'organized-carpool',
|
||||||
|
driverId: '{{.ID}}'
|
||||||
|
},
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
].filter(d => d.coordinates !== null);
|
||||||
|
|
||||||
|
organizedCarpoolDrivers.forEach(function(driver) {
|
||||||
|
// Create custom marker element matching compact search style
|
||||||
|
const el = document.createElement('div');
|
||||||
|
el.className = 'w-8 h-8 rounded-co bg-co-green border border-white shadow-md flex items-center justify-center cursor-pointer';
|
||||||
|
|
||||||
|
// User icon matching compact search
|
||||||
|
el.innerHTML = `
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
||||||
|
<circle cx="12" cy="7" r="4"></circle>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const marker = new maplibregl.Marker({element: el})
|
||||||
|
.setLngLat(driver.coordinates)
|
||||||
|
.setPopup(new maplibregl.Popup({offset: 25, className: 'rounded-lg'})
|
||||||
|
.setHTML(`
|
||||||
|
<div class="p-3">
|
||||||
|
<a href="/app/organized-carpool/drivers/${driver.driverId}" class="font-semibold text-sm text-gray-900 hover:text-co-green">${driver.name}</a>
|
||||||
|
<p class="text-xs text-gray-600 mt-1">${driver.address}</p>
|
||||||
|
<p class="text-xs text-co-green font-medium mt-2">Covoiturage solidaire</p>
|
||||||
|
</div>
|
||||||
|
`))
|
||||||
|
.addTo(map);
|
||||||
|
|
||||||
|
bounds.extend(driver.coordinates);
|
||||||
|
hasMarkers = true;
|
||||||
|
});
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
// Fit map to markers bounds with padding
|
||||||
|
if (hasMarkers) {
|
||||||
|
map.fitBounds(bounds, {
|
||||||
|
padding: 50,
|
||||||
|
maxZoom: 12
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.maplibregl-popup-content {
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
.maplibregl-popup-close-button {
|
||||||
|
font-size: 20px;
|
||||||
|
padding: 4px;
|
||||||
|
color: #6B7280;
|
||||||
|
}
|
||||||
|
.maplibregl-popup-close-button:hover {
|
||||||
|
background-color: #F3F4F6;
|
||||||
|
color: #111827;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{{end}}
|
|
@ -14,40 +14,12 @@
|
||||||
<div
|
<div
|
||||||
class="flex-1 flex items-center justify-between border-t border-r border-b border-gray-200 bg-white rounded-r-3xl truncate">
|
class="flex-1 flex items-center justify-between border-t border-r border-b border-gray-200 bg-white rounded-r-3xl truncate">
|
||||||
<div class="flex-1 px-4 py-2 text-sm truncate">
|
<div class="flex-1 px-4 py-2 text-sm truncate">
|
||||||
<a href="#" class="text-gray-900 font-medium hover:text-gray-600">Bénéficiaires</a>
|
<a href="/app/beneficiaries/" class="text-gray-900 font-medium hover:text-gray-600">Bénéficiaires</a>
|
||||||
<p class="text-gray-500">{{.ViewState.beneficiaries.count}} bénéficiaires</p>
|
<p class="text-gray-500">{{.ViewState.beneficiaries.count}} bénéficiaires</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="col-span-1 flex shadow-sm rounded-3xl">
|
|
||||||
<div
|
|
||||||
class="flex-shrink-0 flex items-center justify-center w-16 bg-co-green text-white text-sm font-medium rounded-l-3xl">
|
|
||||||
{{.IconSet.Icon "hero:outline/shield-check" "h-6 w-6"}}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="flex-1 flex items-center justify-between border-t border-r border-b border-gray-200 bg-white rounded-r-3xl truncate">
|
|
||||||
<div class="flex-1 px-4 py-2 text-sm truncate">
|
|
||||||
<a href="#" class="text-gray-900 font-medium hover:text-gray-600">Accompagnement</a>
|
|
||||||
<p class="text-gray-500">0 actions réalisées</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="col-span-1 flex shadow-sm rounded-3xl">
|
|
||||||
<div
|
|
||||||
class="flex-shrink-0 flex items-center justify-center w-16 bg-co-yellow text-white text-sm font-medium rounded-l-3xl">
|
|
||||||
{{.IconSet.Icon "hero:outline/office-building" "h-6 w-6"}}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="flex-1 flex items-center justify-between border-t border-r border-b border-gray-200 bg-white rounded-r-3xl truncate">
|
|
||||||
<div class="flex-1 px-4 py-2 text-sm truncate">
|
|
||||||
<a href="#" class="text-gray-900 font-medium hover:text-gray-600">Groupes</a>
|
|
||||||
<p class="text-gray-500">0 groupes créés</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="col-span-1 flex shadow-sm rounded-3xl">
|
<li class="col-span-1 flex shadow-sm rounded-3xl">
|
||||||
<div
|
<div
|
||||||
class="flex-shrink-0 flex items-center justify-center w-16 bg-co-red text-white text-sm font-medium rounded-l-3xl">
|
class="flex-shrink-0 flex items-center justify-center w-16 bg-co-red text-white text-sm font-medium rounded-l-3xl">
|
||||||
|
@ -61,6 +33,44 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
{{if moduleAvailable "solidarity_transport"}}
|
||||||
|
<li class="col-span-1 flex shadow-sm rounded-3xl">
|
||||||
|
<div
|
||||||
|
class="flex-shrink-0 flex items-center justify-center w-16 bg-co-orange text-white text-sm font-medium rounded-l-3xl">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
||||||
|
<circle cx="12" cy="7" r="4"></circle>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex-1 flex items-center justify-between border-t border-r border-b border-gray-200 bg-white rounded-r-3xl truncate">
|
||||||
|
<div class="flex-1 px-4 py-2 text-sm truncate">
|
||||||
|
<a href="/app/solidarity-transport/?tab=drivers" class="text-gray-900 font-medium hover:text-gray-600">Conducteurs solidaires</a>
|
||||||
|
<p class="text-gray-500">{{len .ViewState.solidarity_drivers}} conducteurs</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if moduleAvailable "organized_carpool"}}
|
||||||
|
<li class="col-span-1 flex shadow-sm rounded-3xl">
|
||||||
|
<div
|
||||||
|
class="flex-shrink-0 flex items-center justify-center w-16 bg-co-green text-white text-sm font-medium rounded-l-3xl">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
||||||
|
<circle cx="12" cy="7" r="4"></circle>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex-1 flex items-center justify-between border-t border-r border-b border-gray-200 bg-white rounded-r-3xl truncate">
|
||||||
|
<div class="flex-1 px-4 py-2 text-sm truncate">
|
||||||
|
<a href="/app/organized-carpool/?tab=drivers" class="text-gray-900 font-medium hover:text-gray-600">Covoitureurs solidaires</a>
|
||||||
|
<p class="text-gray-500">{{len .ViewState.organized_carpool_drivers}} covoitureurs</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -79,5 +89,11 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{if or (moduleAvailable "solidarity_transport") (moduleAvailable "organized_carpool")}}
|
||||||
|
<div class="py-4">
|
||||||
|
{{template "drivers_map_widget" .ViewState}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
<td class="relative py-3 px-3 text-right text-sm font-medium whitespace-nowrap">
|
<td class="relative py-3 px-3 text-right text-sm font-medium whitespace-nowrap">
|
||||||
<a href="/app/journeys/?departure={{json .Departure}}&destination={{json .Destination}}&departuredate={{timeFormat .DateTime "2006-01-02"}}&departuretime={{timeFormat .DateTime "15:04"}}{{if and .Data .Data.passenger_id}}&passengerid={{.Data.passenger_id}}{{end}}" class="text-co-blue hover:text-co-blue-dark mr-4">
|
<a href="{{if eq $.ViewState.search_view "compact"}}/app/journeys/search{{else}}/app/journeys/{{end}}?departure={{json .Departure}}&destination={{json .Destination}}&departuredate={{timeFormat .DateTime "2006-01-02"}}&departuretime={{timeFormat .DateTime "15:04"}}{{if and .Data .Data.passenger_id}}&passengerid={{.Data.passenger_id}}{{end}}" class="text-co-blue hover:text-co-blue-dark mr-4">
|
||||||
Rechercher
|
Rechercher
|
||||||
</a>
|
</a>
|
||||||
<a href="/app/journeys/saved-searches/{{.ID}}/delete"
|
<a href="/app/journeys/saved-searches/{{.ID}}/delete"
|
||||||
|
|
|
@ -120,6 +120,10 @@
|
||||||
class="p-2 focus:ring-co-blue focus:border-co-blue block w-full shadow-sm sm:text-sm border-gray-300 rounded-none">
|
class="p-2 focus:ring-co-blue focus:border-co-blue block w-full shadow-sm sm:text-sm border-gray-300 rounded-none">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{if ne .ViewState.passengerid ""}}
|
||||||
|
<input type="hidden" name="passengerid" value="{{.ViewState.passengerid}}">
|
||||||
|
{{end}}
|
||||||
|
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
class="px-4 py-2 border border-transparent text-sm font-medium rounded-r-lg text-white bg-co-blue hover:bg-co-blue-dark focus:outline-none">
|
class="px-4 py-2 border border-transparent text-sm font-medium rounded-r-lg text-white bg-co-blue hover:bg-co-blue-dark focus:outline-none">
|
||||||
Rechercher
|
Rechercher
|
||||||
|
@ -151,6 +155,10 @@
|
||||||
<input type="checkbox" x-model="filters.kb" class="rounded border-gray-300 text-co-blue focus:ring-co-blue">
|
<input type="checkbox" x-model="filters.kb" class="rounded border-gray-300 text-co-blue focus:ring-co-blue">
|
||||||
<span class="ml-2 text-gray-600">Solutions locales</span>
|
<span class="ml-2 text-gray-600">Solutions locales</span>
|
||||||
</label>
|
</label>
|
||||||
|
<label class="inline-flex items-center cursor-pointer">
|
||||||
|
<input type="checkbox" x-model="filters.vehicles" class="rounded border-gray-300 text-co-blue focus:ring-co-blue">
|
||||||
|
<span class="ml-2 text-gray-600">Véhicules</span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<!-- Bouton Enregistrer -->
|
<!-- Bouton Enregistrer -->
|
||||||
<a href="/app/journeys/save?departure={{json .ViewState.departure}}&destination={{json .ViewState.destination}}&departuredate={{.ViewState.departuredate}}&departuretime={{.ViewState.departuretime}}{{if ne .ViewState.passengerid ""}}&passengerid={{.ViewState.passengerid}}{{end}}"
|
<a href="/app/journeys/save?departure={{json .ViewState.departure}}&destination={{json .ViewState.destination}}&departuredate={{.ViewState.departuredate}}&departuretime={{.ViewState.departuretime}}{{if ne .ViewState.passengerid ""}}&passengerid={{.ViewState.passengerid}}{{end}}"
|
||||||
|
@ -163,7 +171,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Main Content: Results List (Left) + Map (Right) -->
|
<!-- Main Content: Results List (Left) + Map (Right) -->
|
||||||
<div class="flex overflow-hidden" style="height: calc(100% - 11rem);">
|
<div class="flex overflow-hidden" style="height: calc(100% - 8rem);">
|
||||||
<!-- Results List (Left Side) -->
|
<!-- Results List (Left Side) -->
|
||||||
<div class="w-96 flex-shrink-0 bg-white border-r border-gray-200 overflow-y-auto">
|
<div class="w-96 flex-shrink-0 bg-white border-r border-gray-200 overflow-y-auto">
|
||||||
{{if .ViewState.searched}}
|
{{if .ViewState.searched}}
|
||||||
|
@ -306,6 +314,26 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
<!-- Vehicles Results -->
|
||||||
|
{{if .ViewState.vehicles}}
|
||||||
|
<div x-show="filters.vehicles" @click="selectSolution('vehicles', 0)"
|
||||||
|
:class="selectedType === 'vehicles' ? 'bg-orange-50 border-l-4 border-co-orange' : 'hover:bg-gray-50'"
|
||||||
|
class="p-4 cursor-pointer transition-colors">
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<span class="text-sm font-semibold text-gray-900">Véhicules disponibles</span>
|
||||||
|
<span class="text-xs font-medium bg-orange-50 text-co-orange px-2 py-1 rounded-full">
|
||||||
|
{{len .ViewState.vehicles}} véhicule{{if gt (len .ViewState.vehicles) 1}}s{{end}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-orange-50 text-co-orange">
|
||||||
|
{{$.IconSet.Icon "tabler-icons:car" "h-3 w-3"}}
|
||||||
|
<span class="ml-1">Véhicules partagés</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="p-8 text-center text-gray-500">
|
<div class="p-8 text-center text-gray-500">
|
||||||
|
@ -638,7 +666,7 @@
|
||||||
|
|
||||||
<!-- Action Button -->
|
<!-- Action Button -->
|
||||||
<div class="pt-4 border-t border-gray-200">
|
<div class="pt-4 border-t border-gray-200">
|
||||||
<a :href="'/app/organized-carpool/drivers/' + organizedCarpools[selectedOrganizedCarpoolIndex].driverId + '/journeys/' + organizedCarpools[selectedOrganizedCarpoolIndex].id + '{{if ne .ViewState.passengerid ""}}?passengerid={{.ViewState.passengerid}}{{end}}'"
|
<a :href="'/app/organized-carpool/drivers/' + organizedCarpools[selectedOrganizedCarpoolIndex].driverId + '/journeys/' + organizedCarpools[selectedOrganizedCarpoolIndex].id + (passengerId ? '?passengerid=' + passengerId : '')"
|
||||||
class="block w-full text-center bg-co-blue text-white px-4 py-2 rounded-2xl hover:bg-blue-700 transition-colors">
|
class="block w-full text-center bg-co-blue text-white px-4 py-2 rounded-2xl hover:bg-blue-700 transition-colors">
|
||||||
Organiser le covoiturage solidaire
|
Organiser le covoiturage solidaire
|
||||||
</a>
|
</a>
|
||||||
|
@ -771,6 +799,122 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- Vehicles List (Middle Column) -->
|
||||||
|
<template x-if="selectedType === 'vehicles'">
|
||||||
|
<div x-transition
|
||||||
|
class="w-80 flex-shrink-0 bg-white border-r border-gray-200 overflow-y-auto">
|
||||||
|
<div class="p-4 border-b border-gray-200 bg-gray-50">
|
||||||
|
<h3 class="text-sm font-semibold text-gray-900">Véhicules disponibles</h3>
|
||||||
|
</div>
|
||||||
|
<div class="divide-y divide-gray-200">
|
||||||
|
<template x-for="(vehicle, idx) in vehicles" :key="idx">
|
||||||
|
<div @click="selectVehicle(idx)"
|
||||||
|
:class="selectedVehicleIndex === idx ? 'bg-orange-50 border-l-4 border-co-orange' : 'hover:bg-gray-50'"
|
||||||
|
class="p-4 cursor-pointer transition-colors">
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="text-sm font-semibold text-gray-900" x-text="vehicle.name"></div>
|
||||||
|
<div class="text-xs text-gray-500 mt-1">
|
||||||
|
<span x-text="vehicle.type"></span>
|
||||||
|
<span x-show="vehicle.type === 'Voiture' && vehicle.automatic"> (boite auto)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-1 text-xs text-gray-600">
|
||||||
|
<div x-show="vehicle.licencePlate" class="flex items-center gap-2">
|
||||||
|
<span>Numéro:</span>
|
||||||
|
<span class="font-medium" x-text="vehicle.licencePlate"></span>
|
||||||
|
</div>
|
||||||
|
<div x-show="vehicle.address" class="flex items-start gap-2">
|
||||||
|
<span class="flex-shrink-0">Localisation:</span>
|
||||||
|
<span class="font-medium" x-text="vehicle.address"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Vehicle Details (Third Column) -->
|
||||||
|
<template x-if="selectedType === 'vehicles' && selectedVehicleIndex !== null">
|
||||||
|
<div x-transition
|
||||||
|
class="w-96 flex-shrink-0 bg-white border-r border-gray-200 overflow-y-auto">
|
||||||
|
<template x-if="selectedVehicleIndex !== null && vehicles[selectedVehicleIndex]">
|
||||||
|
<div>
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="p-4 border-b border-gray-200 bg-co-orange">
|
||||||
|
<div class="text-white">
|
||||||
|
<div class="text-xl font-bold mb-2" x-text="vehicles[selectedVehicleIndex].name"></div>
|
||||||
|
<div class="text-sm" x-text="vehicles[selectedVehicleIndex].type"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Vehicle Details -->
|
||||||
|
<div class="p-4 space-y-4">
|
||||||
|
<!-- Vehicle Info -->
|
||||||
|
<div class="bg-orange-50 rounded-lg p-3 border border-orange-200">
|
||||||
|
<div class="text-xs font-semibold text-gray-700 mb-2">Informations du véhicule</div>
|
||||||
|
<div class="space-y-2 text-sm">
|
||||||
|
<div x-show="vehicles[selectedVehicleIndex].type" class="flex items-center justify-between">
|
||||||
|
<span class="text-gray-600">Type:</span>
|
||||||
|
<span class="font-medium text-gray-900">
|
||||||
|
<span x-text="vehicles[selectedVehicleIndex].type"></span>
|
||||||
|
<span x-show="vehicles[selectedVehicleIndex].type === 'Voiture' && vehicles[selectedVehicleIndex].automatic" class="text-gray-500"> (boite auto)</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div x-show="vehicles[selectedVehicleIndex].licencePlate" class="flex items-center justify-between">
|
||||||
|
<span class="text-gray-600">Numéro:</span>
|
||||||
|
<span class="font-medium text-gray-900" x-text="vehicles[selectedVehicleIndex].licencePlate"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Location -->
|
||||||
|
<div x-show="vehicles[selectedVehicleIndex].address" class="bg-orange-50 rounded-lg p-3 border border-orange-200">
|
||||||
|
<div class="text-xs font-semibold text-gray-700 mb-2">Localisation</div>
|
||||||
|
<div class="text-sm text-gray-900" x-text="vehicles[selectedVehicleIndex].address"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
|
<div x-show="vehicles[selectedVehicleIndex].description" class="space-y-2">
|
||||||
|
<div class="text-xs font-semibold text-gray-700">Description</div>
|
||||||
|
<div class="text-sm text-gray-600" x-text="vehicles[selectedVehicleIndex].description"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Optional Fields -->
|
||||||
|
<template x-if="vehicleOptionalFields && vehicleOptionalFields.length > 0">
|
||||||
|
<div class="bg-orange-50 rounded-lg p-3 border border-orange-200">
|
||||||
|
<div class="text-xs font-semibold text-gray-700 mb-2">Autres propriétés</div>
|
||||||
|
<div class="space-y-2 text-sm">
|
||||||
|
<template x-for="field in vehicleOptionalFields" :key="field.name">
|
||||||
|
<div x-show="vehicles[selectedVehicleIndex].data[field.name]" class="flex items-center justify-between">
|
||||||
|
<span class="text-gray-600" x-text="field.label"></span>
|
||||||
|
<span class="font-medium text-gray-900">
|
||||||
|
<template x-if="field.type === 'select'">
|
||||||
|
<span x-text="getSelectLabel(field, vehicles[selectedVehicleIndex].data[field.name])"></span>
|
||||||
|
</template>
|
||||||
|
<template x-if="field.type !== 'select'">
|
||||||
|
<span x-text="vehicles[selectedVehicleIndex].data[field.name]"></span>
|
||||||
|
</template>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Booking Button -->
|
||||||
|
<div class="pt-4">
|
||||||
|
<a :href="getVehicleBookingUrl()"
|
||||||
|
class="block w-full bg-co-orange hover:bg-co-orange-dark text-white text-center font-medium py-2 px-4 rounded-2xl transition-colors">
|
||||||
|
Réserver un véhicule
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- Map (Right Side) -->
|
<!-- Map (Right Side) -->
|
||||||
<div class="flex-1 bg-gray-100 relative">
|
<div class="flex-1 bg-gray-100 relative">
|
||||||
<!-- Driver Detail Panel -->
|
<!-- Driver Detail Panel -->
|
||||||
|
@ -815,7 +959,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<a :href="'/app/solidarity-transport/drivers/' + solidarityJourneys[selectedDriverIndex].driverId + '/journeys/' + solidarityJourneys[selectedDriverIndex].id"
|
<a :href="'/app/solidarity-transport/drivers/' + solidarityJourneys[selectedDriverIndex].driverId + '/journeys/' + solidarityJourneys[selectedDriverIndex].id + (passengerId ? '?passengerid=' + passengerId : '')"
|
||||||
class="block w-full text-center px-4 py-2 bg-co-blue text-white rounded-lg hover:bg-co-blue-dark transition-colors">
|
class="block w-full text-center px-4 py-2 bg-co-blue text-white rounded-lg hover:bg-co-blue-dark transition-colors">
|
||||||
Organiser le transport solidaire
|
Organiser le transport solidaire
|
||||||
</a>
|
</a>
|
||||||
|
@ -971,11 +1115,31 @@ function compactJourneySearch() {
|
||||||
{{end}}
|
{{end}}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const vehicleOptionalFields = {{if .ViewState.vehicle_optional_fields}}{{json .ViewState.vehicle_optional_fields}}{{else}}[]{{end}};
|
||||||
|
|
||||||
|
const vehicles = [
|
||||||
|
{{range $index, $vehicle := .ViewState.vehicles}}
|
||||||
|
{
|
||||||
|
id: '{{$vehicle.ID}}',
|
||||||
|
name: {{if $vehicle.Data.name}}'{{$vehicle.Data.name}}'{{else}}'Véhicule'{{end}},
|
||||||
|
type: {{if $vehicle.Type}}'{{$vehicle.Type}}'{{else}}null{{end}},
|
||||||
|
automatic: {{if $vehicle.Data.automatic}}true{{else}}false{{end}},
|
||||||
|
licencePlate: {{if $vehicle.Data.licence_plate}}'{{$vehicle.Data.licence_plate}}'{{else}}null{{end}},
|
||||||
|
description: {{if $vehicle.Data.description}}'{{$vehicle.Data.description}}'{{else}}null{{end}},
|
||||||
|
address: {{if and $vehicle.Data.address $vehicle.Data.address.properties}}'{{$vehicle.Data.address.properties.label}}'{{else}}null{{end}},
|
||||||
|
location: {{if and $vehicle.Data.address $vehicle.Data.address.geometry $vehicle.Data.address.geometry.coordinates}}[{{index $vehicle.Data.address.geometry.coordinates 0}}, {{index $vehicle.Data.address.geometry.coordinates 1}}]{{else}}null{{end}},
|
||||||
|
distance: null,
|
||||||
|
data: {{json $vehicle.Data}}
|
||||||
|
},
|
||||||
|
{{end}}
|
||||||
|
];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
selectedType: null,
|
selectedType: null,
|
||||||
selectedIndex: null,
|
selectedIndex: null,
|
||||||
selectedDriverIndex: null,
|
selectedDriverIndex: null,
|
||||||
selectedOrganizedCarpoolIndex: null,
|
selectedOrganizedCarpoolIndex: null,
|
||||||
|
selectedVehicleIndex: null,
|
||||||
map: null,
|
map: null,
|
||||||
startMarker: null,
|
startMarker: null,
|
||||||
endMarker: null,
|
endMarker: null,
|
||||||
|
@ -985,13 +1149,18 @@ function compactJourneySearch() {
|
||||||
organizedCarpools: organizedCarpools,
|
organizedCarpools: organizedCarpools,
|
||||||
carpools: carpools,
|
carpools: carpools,
|
||||||
kbSolutions: kbSolutions,
|
kbSolutions: kbSolutions,
|
||||||
|
vehicles: vehicles,
|
||||||
|
vehicleOptionalFields: vehicleOptionalFields,
|
||||||
|
passengerId: '{{.ViewState.passengerid}}',
|
||||||
|
departureDate: '{{.ViewState.departuredate}}',
|
||||||
|
|
||||||
filters: {
|
filters: {
|
||||||
transit: true,
|
transit: true,
|
||||||
solidarity: true,
|
solidarity: true,
|
||||||
organizedCarpool: true,
|
organizedCarpool: true,
|
||||||
carpool: true,
|
carpool: true,
|
||||||
kb: true
|
kb: true,
|
||||||
|
vehicles: true
|
||||||
},
|
},
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
@ -1063,6 +1232,7 @@ function compactJourneySearch() {
|
||||||
this.selectedIndex = null;
|
this.selectedIndex = null;
|
||||||
this.selectedDriverIndex = null;
|
this.selectedDriverIndex = null;
|
||||||
this.selectedOrganizedCarpoolIndex = null;
|
this.selectedOrganizedCarpoolIndex = null;
|
||||||
|
this.selectedVehicleIndex = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1076,6 +1246,9 @@ function compactJourneySearch() {
|
||||||
if (type !== 'organized_carpool') {
|
if (type !== 'organized_carpool') {
|
||||||
this.selectedOrganizedCarpoolIndex = null;
|
this.selectedOrganizedCarpoolIndex = null;
|
||||||
}
|
}
|
||||||
|
if (type !== 'vehicles') {
|
||||||
|
this.selectedVehicleIndex = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Update selection
|
// Update selection
|
||||||
this.selectedType = type;
|
this.selectedType = type;
|
||||||
|
@ -1096,6 +1269,9 @@ function compactJourneySearch() {
|
||||||
this.displayCarpoolRoute(index);
|
this.displayCarpoolRoute(index);
|
||||||
} else if (type === 'kb') {
|
} else if (type === 'kb') {
|
||||||
this.displayKBSolution(index);
|
this.displayKBSolution(index);
|
||||||
|
} else if (type === 'vehicles') {
|
||||||
|
this.selectedVehicleIndex = null;
|
||||||
|
this.displayVehiclesMarkers();
|
||||||
}
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
},
|
},
|
||||||
|
@ -1126,6 +1302,19 @@ function compactJourneySearch() {
|
||||||
}, 500);
|
}, 500);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
selectVehicle(vehicleIndex) {
|
||||||
|
// Clear routes before selecting new vehicle
|
||||||
|
this.clearRoutes();
|
||||||
|
|
||||||
|
// Update vehicle selection
|
||||||
|
this.selectedVehicleIndex = vehicleIndex;
|
||||||
|
|
||||||
|
// Use setTimeout to ensure clearing completes before displaying new route
|
||||||
|
setTimeout(() => {
|
||||||
|
this.displayVehicleMarker(vehicleIndex);
|
||||||
|
}, 500);
|
||||||
|
},
|
||||||
|
|
||||||
clearRoutes() {
|
clearRoutes() {
|
||||||
// Remove route markers
|
// Remove route markers
|
||||||
this.routeMarkers.forEach(marker => marker.remove());
|
this.routeMarkers.forEach(marker => marker.remove());
|
||||||
|
@ -1162,7 +1351,7 @@ function compactJourneySearch() {
|
||||||
const allCoords = [];
|
const allCoords = [];
|
||||||
|
|
||||||
journey.legs.forEach((leg, legIndex) => {
|
journey.legs.forEach((leg, legIndex) => {
|
||||||
const lineColor = leg.mode === 'WALK' ? '#9ca3af' : '#' + leg.color;
|
const lineColor = leg.mode === 'WALK' ? '#9ca3af' : (leg.color && leg.color !== '' ? '#' + leg.color : '#243887');
|
||||||
const lineWidth = leg.mode === 'WALK' ? 2 : 4;
|
const lineWidth = leg.mode === 'WALK' ? 2 : 4;
|
||||||
const lineDasharray = leg.mode === 'WALK' ? [2, 2] : undefined;
|
const lineDasharray = leg.mode === 'WALK' ? [2, 2] : undefined;
|
||||||
|
|
||||||
|
@ -1758,6 +1947,111 @@ function compactJourneySearch() {
|
||||||
padding: 50
|
padding: 50
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
displayVehiclesMarkers() {
|
||||||
|
if (!this.map || !this.map.loaded()) return;
|
||||||
|
|
||||||
|
const bounds = new maplibregl.LngLatBounds();
|
||||||
|
let hasMarkers = false;
|
||||||
|
|
||||||
|
// Display all vehicles as markers
|
||||||
|
this.vehicles.forEach((vehicle, idx) => {
|
||||||
|
if (!vehicle.location) return;
|
||||||
|
|
||||||
|
const el = document.createElement('div');
|
||||||
|
el.className = 'w-10 h-10 rounded-co bg-co-orange border-2 border-white shadow-md flex items-center justify-center cursor-pointer hover:scale-110 transition-transform';
|
||||||
|
el.innerHTML = `
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M19 17h2c.6 0 1-.4 1-1v-3c0-.9-.7-1.7-1.5-1.9C18.7 10.6 16 10 16 10s-1.3-1.4-2.2-2.3c-.5-.4-1.1-.7-1.8-.7H5c-.6 0-1.1.4-1.4.9l-1.4 2.9A3.7 3.7 0 0 0 2 12v4c0 .6.4 1 1 1h2"></path>
|
||||||
|
<circle cx="7" cy="17" r="2"></circle>
|
||||||
|
<circle cx="17" cy="17" r="2"></circle>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const marker = new maplibregl.Marker({element: el})
|
||||||
|
.setLngLat(vehicle.location)
|
||||||
|
.setPopup(new maplibregl.Popup({offset: 25, className: 'rounded-lg'})
|
||||||
|
.setHTML(`
|
||||||
|
<div class="p-3">
|
||||||
|
<div class="font-semibold text-sm text-gray-900">${vehicle.name}</div>
|
||||||
|
${vehicle.type ? `<p class="text-xs text-gray-600 mt-1">${vehicle.type}</p>` : ''}
|
||||||
|
${vehicle.address ? `<p class="text-xs text-gray-500 mt-1">${vehicle.address}</p>` : ''}
|
||||||
|
</div>
|
||||||
|
`))
|
||||||
|
.addTo(this.map);
|
||||||
|
|
||||||
|
this.routeMarkers.push(marker);
|
||||||
|
bounds.extend(vehicle.location);
|
||||||
|
hasMarkers = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fit map to show all vehicle markers
|
||||||
|
if (hasMarkers) {
|
||||||
|
this.map.fitBounds(bounds, {
|
||||||
|
padding: 100,
|
||||||
|
maxZoom: 14
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
displayVehicleMarker(vehicleIndex) {
|
||||||
|
if (!this.map || !this.map.loaded() || !this.vehicles[vehicleIndex]) return;
|
||||||
|
|
||||||
|
const vehicle = this.vehicles[vehicleIndex];
|
||||||
|
if (!vehicle.location) return;
|
||||||
|
|
||||||
|
// Create a larger marker for the selected vehicle
|
||||||
|
const el = document.createElement('div');
|
||||||
|
el.className = 'w-12 h-12 rounded-co bg-co-orange border-2 border-white shadow-lg flex items-center justify-center';
|
||||||
|
el.innerHTML = `
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M19 17h2c.6 0 1-.4 1-1v-3c0-.9-.7-1.7-1.5-1.9C18.7 10.6 16 10 16 10s-1.3-1.4-2.2-2.3c-.5-.4-1.1-.7-1.8-.7H5c-.6 0-1.1.4-1.4.9l-1.4 2.9A3.7 3.7 0 0 0 2 12v4c0 .6.4 1 1 1h2"></path>
|
||||||
|
<circle cx="7" cy="17" r="2"></circle>
|
||||||
|
<circle cx="17" cy="17" r="2"></circle>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const marker = new maplibregl.Marker({element: el})
|
||||||
|
.setLngLat(vehicle.location)
|
||||||
|
.addTo(this.map);
|
||||||
|
|
||||||
|
this.routeMarkers.push(marker);
|
||||||
|
|
||||||
|
// Center map on the vehicle
|
||||||
|
this.map.flyTo({
|
||||||
|
center: vehicle.location,
|
||||||
|
zoom: 15,
|
||||||
|
duration: 1000
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getVehicleBookingUrl() {
|
||||||
|
let url = '/app/vehicles/?';
|
||||||
|
|
||||||
|
if (this.passengerId) {
|
||||||
|
url += 'beneficiaryid=' + this.passengerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the departure date from search as start date
|
||||||
|
if (this.departureDate) {
|
||||||
|
url += '&startdate=' + this.departureDate;
|
||||||
|
|
||||||
|
// Calculate end date as 7 days after start date
|
||||||
|
const startDate = new Date(this.departureDate);
|
||||||
|
startDate.setDate(startDate.getDate() + 7);
|
||||||
|
const endDate = startDate.toISOString().split('T')[0];
|
||||||
|
url += '&enddate=' + endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
},
|
||||||
|
|
||||||
|
getSelectLabel(field, value) {
|
||||||
|
if (!field.options || !value) return value;
|
||||||
|
|
||||||
|
const option = field.options.find(opt => opt.value === value);
|
||||||
|
return option ? option.label : value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<div class="bg-white shadow sm:rounded-2xl">
|
<div class="bg-white shadow sm:rounded-2xl">
|
||||||
<h2 id="timeline-title" class="text-lg font-medium text-gray-900 p-4 sm:px-6">Chercher une solution</h2>
|
<h2 id="timeline-title" class="text-lg font-medium text-gray-900 p-4 sm:px-6">Chercher une solution</h2>
|
||||||
<div class="border-t border-gray-200 px-4 py-5 sm:px-6">
|
<div class="border-t border-gray-200 px-4 py-5 sm:px-6">
|
||||||
<form method="GET" x-data="journeySearch()">
|
<form method="GET" action="{{if eq .ViewState.search_view "compact"}}/app/journeys/search{{else}}/app/journeys/{{end}}" x-data="journeySearch()">
|
||||||
|
|
||||||
<div class="py-4">
|
<div class="py-4">
|
||||||
<label for="beneficiary" class="block text-sm font-medium text-gray-700">Bénéficiaire (optionnel)</label>
|
<label for="beneficiary" class="block text-sm font-medium text-gray-700">Bénéficiaire (optionnel)</label>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<div class="divide-y divide-gray-200">
|
<div class="divide-y divide-gray-200">
|
||||||
<div>
|
<div>
|
||||||
<div class="hidden sm:block">
|
<div class="hidden sm:block">
|
||||||
<div class="border-b border-gray-200 pl-4">
|
<div class="border-b border-gray-200 pl-4 flex justify-between items-center">
|
||||||
<nav class="-mb-px flex space-x-8" aria-label="Tabs">
|
<nav class="-mb-px flex space-x-8" aria-label="Tabs">
|
||||||
<a href="#" @click="tab = 'carpoolService'"
|
<a href="#" @click="tab = 'carpoolService'"
|
||||||
class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"
|
class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"
|
||||||
|
@ -29,6 +29,24 @@
|
||||||
:class="tab == 'carpoolHistory' ? 'border-co-blue text-co-blue' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'">
|
:class="tab == 'carpoolHistory' ? 'border-co-blue text-co-blue' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'">
|
||||||
Trajets passés </a>
|
Trajets passés </a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<div class="pr-4" x-show="tab == 'carpoolHistory'">
|
||||||
|
{{$exportURL := "/exports/organized-carpool/bookings.xlsx"}}
|
||||||
|
{{$hasParams := false}}
|
||||||
|
{{if .ViewState.hist_filters.date_start}}{{$exportURL = printf "%s?start_date=%s" $exportURL .ViewState.hist_filters.date_start}}{{$hasParams = true}}{{end}}
|
||||||
|
{{if .ViewState.hist_filters.date_end}}{{if $hasParams}}{{$exportURL = printf "%s&end_date=%s" $exportURL .ViewState.hist_filters.date_end}}{{else}}{{$exportURL = printf "%s?end_date=%s" $exportURL .ViewState.hist_filters.date_end}}{{$hasParams = true}}{{end}}{{end}}
|
||||||
|
{{if .ViewState.hist_filters.status}}{{if $hasParams}}{{$exportURL = printf "%s&status=%s" $exportURL .ViewState.hist_filters.status}}{{else}}{{$exportURL = printf "%s?status=%s" $exportURL .ViewState.hist_filters.status}}{{end}}{{end}}
|
||||||
|
|
||||||
|
<a href="{{$exportURL}}">
|
||||||
|
<button type="button"
|
||||||
|
class="inline-flex items-center justify-center bg-white hover:bg-gray-50 border-gray-300 border px-4 py-2 text-gray-700 flex items-center text-sm rounded-2xl focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-co-blue">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||||
|
</svg>
|
||||||
|
Exporter
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<div class="divide-y divide-gray-200">
|
<div class="divide-y divide-gray-200">
|
||||||
<div>
|
<div>
|
||||||
<div class="hidden sm:block">
|
<div class="hidden sm:block">
|
||||||
<div class="border-b border-gray-200 pl-4">
|
<div class="border-b border-gray-200 pl-4 flex justify-between items-center">
|
||||||
<nav class="-mb-px flex space-x-8" aria-label="Tabs">
|
<nav class="-mb-px flex space-x-8" aria-label="Tabs">
|
||||||
<a href="#" @click="tab = 'solidarityService'"
|
<a href="#" @click="tab = 'solidarityService'"
|
||||||
class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"
|
class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"
|
||||||
|
@ -34,6 +34,24 @@
|
||||||
:class="tab == 'solidarityHistory' ? 'border-co-blue text-co-blue' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'">
|
:class="tab == 'solidarityHistory' ? 'border-co-blue text-co-blue' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'">
|
||||||
Trajets passés </a>
|
Trajets passés </a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<div class="pr-4" x-show="tab == 'solidarityHistory'">
|
||||||
|
{{$exportURL := "/exports/solidarity-transport/bookings.xlsx"}}
|
||||||
|
{{$hasParams := false}}
|
||||||
|
{{if .ViewState.hist_filters.date_start}}{{$exportURL = printf "%s?start_date=%s" $exportURL .ViewState.hist_filters.date_start}}{{$hasParams = true}}{{end}}
|
||||||
|
{{if .ViewState.hist_filters.date_end}}{{if $hasParams}}{{$exportURL = printf "%s&end_date=%s" $exportURL .ViewState.hist_filters.date_end}}{{else}}{{$exportURL = printf "%s?end_date=%s" $exportURL .ViewState.hist_filters.date_end}}{{$hasParams = true}}{{end}}{{end}}
|
||||||
|
{{if .ViewState.hist_filters.status}}{{if $hasParams}}{{$exportURL = printf "%s&status=%s" $exportURL .ViewState.hist_filters.status}}{{else}}{{$exportURL = printf "%s?status=%s" $exportURL .ViewState.hist_filters.status}}{{end}}{{end}}
|
||||||
|
|
||||||
|
<a href="{{$exportURL}}">
|
||||||
|
<button type="button"
|
||||||
|
class="inline-flex items-center justify-center bg-white hover:bg-gray-50 border-gray-300 border px-4 py-2 text-gray-700 flex items-center text-sm rounded-2xl focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-co-blue">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||||
|
</svg>
|
||||||
|
Exporter
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,10 +11,13 @@
|
||||||
--color-red-600: oklch(0.577 0.245 27.325);
|
--color-red-600: oklch(0.577 0.245 27.325);
|
||||||
--color-red-800: oklch(0.444 0.177 26.899);
|
--color-red-800: oklch(0.444 0.177 26.899);
|
||||||
--color-red-900: oklch(0.396 0.141 25.723);
|
--color-red-900: oklch(0.396 0.141 25.723);
|
||||||
|
--color-orange-50: oklch(0.98 0.016 73.684);
|
||||||
|
--color-orange-200: oklch(0.901 0.076 70.697);
|
||||||
--color-yellow-50: oklch(0.987 0.026 102.212);
|
--color-yellow-50: oklch(0.987 0.026 102.212);
|
||||||
--color-yellow-100: oklch(0.973 0.071 103.193);
|
--color-yellow-100: oklch(0.973 0.071 103.193);
|
||||||
--color-yellow-800: oklch(0.476 0.114 61.907);
|
--color-yellow-800: oklch(0.476 0.114 61.907);
|
||||||
--color-green-100: oklch(0.962 0.044 156.743);
|
--color-green-100: oklch(0.962 0.044 156.743);
|
||||||
|
--color-green-500: oklch(0.723 0.219 149.579);
|
||||||
--color-green-600: oklch(0.627 0.194 149.214);
|
--color-green-600: oklch(0.627 0.194 149.214);
|
||||||
--color-green-800: oklch(0.448 0.119 151.328);
|
--color-green-800: oklch(0.448 0.119 151.328);
|
||||||
--color-blue-50: oklch(0.97 0.014 254.604);
|
--color-blue-50: oklch(0.97 0.014 254.604);
|
||||||
|
@ -30,6 +33,7 @@
|
||||||
--color-purple-50: oklch(0.977 0.014 308.299);
|
--color-purple-50: oklch(0.977 0.014 308.299);
|
||||||
--color-purple-100: oklch(0.946 0.033 307.174);
|
--color-purple-100: oklch(0.946 0.033 307.174);
|
||||||
--color-purple-200: oklch(0.902 0.063 306.703);
|
--color-purple-200: oklch(0.902 0.063 306.703);
|
||||||
|
--color-purple-500: oklch(0.627 0.265 303.9);
|
||||||
--color-purple-600: oklch(0.558 0.288 302.321);
|
--color-purple-600: oklch(0.558 0.288 302.321);
|
||||||
--color-purple-700: oklch(0.496 0.265 301.924);
|
--color-purple-700: oklch(0.496 0.265 301.924);
|
||||||
--color-purple-800: oklch(0.438 0.218 303.724);
|
--color-purple-800: oklch(0.438 0.218 303.724);
|
||||||
|
@ -1804,6 +1808,9 @@
|
||||||
.border-indigo-500 {
|
.border-indigo-500 {
|
||||||
border-color: var(--color-indigo-500);
|
border-color: var(--color-indigo-500);
|
||||||
}
|
}
|
||||||
|
.border-orange-200 {
|
||||||
|
border-color: var(--color-orange-200);
|
||||||
|
}
|
||||||
.border-purple-200 {
|
.border-purple-200 {
|
||||||
border-color: var(--color-purple-200);
|
border-color: var(--color-purple-200);
|
||||||
}
|
}
|
||||||
|
@ -1840,6 +1847,9 @@
|
||||||
.bg-blue-100 {
|
.bg-blue-100 {
|
||||||
background-color: var(--color-blue-100);
|
background-color: var(--color-blue-100);
|
||||||
}
|
}
|
||||||
|
.bg-blue-500 {
|
||||||
|
background-color: var(--color-blue-500);
|
||||||
|
}
|
||||||
.bg-blue-600 {
|
.bg-blue-600 {
|
||||||
background-color: var(--color-blue-600);
|
background-color: var(--color-blue-600);
|
||||||
}
|
}
|
||||||
|
@ -1852,6 +1862,9 @@
|
||||||
.bg-co-lightblue {
|
.bg-co-lightblue {
|
||||||
background-color: var(--color-co-lightblue);
|
background-color: var(--color-co-lightblue);
|
||||||
}
|
}
|
||||||
|
.bg-co-orange {
|
||||||
|
background-color: var(--color-co-orange);
|
||||||
|
}
|
||||||
.bg-co-red {
|
.bg-co-red {
|
||||||
background-color: var(--color-co-red);
|
background-color: var(--color-co-red);
|
||||||
}
|
}
|
||||||
|
@ -1882,6 +1895,9 @@
|
||||||
.bg-green-100 {
|
.bg-green-100 {
|
||||||
background-color: var(--color-green-100);
|
background-color: var(--color-green-100);
|
||||||
}
|
}
|
||||||
|
.bg-green-500 {
|
||||||
|
background-color: var(--color-green-500);
|
||||||
|
}
|
||||||
.bg-green-600 {
|
.bg-green-600 {
|
||||||
background-color: var(--color-green-600);
|
background-color: var(--color-green-600);
|
||||||
}
|
}
|
||||||
|
@ -1891,12 +1907,18 @@
|
||||||
.bg-indigo-600 {
|
.bg-indigo-600 {
|
||||||
background-color: var(--color-indigo-600);
|
background-color: var(--color-indigo-600);
|
||||||
}
|
}
|
||||||
|
.bg-orange-50 {
|
||||||
|
background-color: var(--color-orange-50);
|
||||||
|
}
|
||||||
.bg-purple-50 {
|
.bg-purple-50 {
|
||||||
background-color: var(--color-purple-50);
|
background-color: var(--color-purple-50);
|
||||||
}
|
}
|
||||||
.bg-purple-100 {
|
.bg-purple-100 {
|
||||||
background-color: var(--color-purple-100);
|
background-color: var(--color-purple-100);
|
||||||
}
|
}
|
||||||
|
.bg-purple-500 {
|
||||||
|
background-color: var(--color-purple-500);
|
||||||
|
}
|
||||||
.bg-purple-600 {
|
.bg-purple-600 {
|
||||||
background-color: var(--color-purple-600);
|
background-color: var(--color-purple-600);
|
||||||
}
|
}
|
||||||
|
@ -2132,6 +2154,9 @@
|
||||||
.p-4 {
|
.p-4 {
|
||||||
padding: calc(var(--spacing) * 4);
|
padding: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
|
.p-6 {
|
||||||
|
padding: calc(var(--spacing) * 6);
|
||||||
|
}
|
||||||
.p-8 {
|
.p-8 {
|
||||||
padding: calc(var(--spacing) * 8);
|
padding: calc(var(--spacing) * 8);
|
||||||
}
|
}
|
||||||
|
@ -2467,6 +2492,9 @@
|
||||||
.text-black {
|
.text-black {
|
||||||
color: var(--color-black);
|
color: var(--color-black);
|
||||||
}
|
}
|
||||||
|
.text-blue-600 {
|
||||||
|
color: var(--color-blue-600);
|
||||||
|
}
|
||||||
.text-blue-800 {
|
.text-blue-800 {
|
||||||
color: var(--color-blue-800);
|
color: var(--color-blue-800);
|
||||||
}
|
}
|
||||||
|
@ -3113,6 +3141,16 @@
|
||||||
outline-style: none;
|
outline-style: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.hover\:scale-110 {
|
||||||
|
&:hover {
|
||||||
|
@media (hover: hover) {
|
||||||
|
--tw-scale-x: 110%;
|
||||||
|
--tw-scale-y: 110%;
|
||||||
|
--tw-scale-z: 110%;
|
||||||
|
scale: var(--tw-scale-x) var(--tw-scale-y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.hover\:border-gray-300 {
|
.hover\:border-gray-300 {
|
||||||
&:hover {
|
&:hover {
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
|
@ -3183,6 +3221,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.hover\:text-co-green {
|
||||||
|
&:hover {
|
||||||
|
@media (hover: hover) {
|
||||||
|
color: var(--color-co-green);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.hover\:text-gray-500 {
|
.hover\:text-gray-500 {
|
||||||
&:hover {
|
&:hover {
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
|
|
Loading…
Reference in New Issue