diff --git a/assets/js/add-lieu.js b/assets/js/add-lieu.js new file mode 100644 index 0000000..063d2dd --- /dev/null +++ b/assets/js/add-lieu.js @@ -0,0 +1,182 @@ +document.addEventListener("DOMContentLoaded", () => { + console.log("Script chargé"); + + const addLieuButton = document.getElementById("add-lieu-button"); + const addLieuModal = document.getElementById("add-lieu-modal"); + const cancelAddLieu = document.getElementById("cancel-add-lieu"); + const selectLocationButton = document.getElementById("select-location"); + const addressDisplay = document.getElementById("lieu-details"); + + let map, marker, selectedAddress; + + if (addLieuButton && addLieuModal && cancelAddLieu && selectLocationButton) { + // Affiche la modal + addLieuButton.addEventListener("click", () => { + const villeId = document.getElementById("sortie_ville").value; + + if (!villeId) { + alert("Veuillez sélectionner une ville avant d'ajouter un lieu."); + return; + } + + addLieuModal.classList.remove("hidden"); + + // Détruire la carte si elle existe déjà + if (map) { + map.remove(); + map = null; + marker = null; + } + + // Récupère les limites de la ville + fetch(`/get-bounds/${villeId}`) + .then(response => { + if (!response.ok) { + throw new Error("Erreur lors de la récupération des limites de la ville"); + } + return response.json(); + }) + .then(data => { + console.log("Bounds de la ville :", data); + + // Initialise la carte + map = L.map("map").setView([data.centerLat, data.centerLng], 13); + + // Ajout du fond de carte + L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { + maxZoom: 19, + }).addTo(map); + + // Limite le déplacement de la carte aux bounds + const bounds = L.latLngBounds( + [data.south, data.west], + [data.north, data.east] + ); + map.setMaxBounds(bounds); + map.fitBounds(bounds); + + // Empêche de dézoomer au-delà de la ville + map.setMinZoom(map.getZoom()); + + // Gestion de la sélection d'un lieu sur la carte + map.on("click", async (e) => { + const { lat, lng } = e.latlng; + + // Place un marqueur + if (marker) { + marker.setLatLng([lat, lng]); + } else { + marker = L.marker([lat, lng]).addTo(map); + } + + // Récupère l'adresse à partir des coordonnées + try { + const response = await fetch( + `https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lng}` + ); + if (!response.ok) { + throw new Error("Erreur lors de la récupération des informations du lieu."); + } + + const data = await response.json(); + console.log("Détails du lieu :", data); + + selectedAddress = data.display_name; + + // Affiche les détails du lieu + const addressDetails = ` +
Rue : ${data.address.road || "Non disponible"}
+Ville : ${data.address.city || data.address.town || "Non disponible"}
+Code postal : ${data.address.postcode || "Non disponible"}
+Pays : ${data.address.country || "Non disponible"}
+ `; + addressDisplay.innerHTML = addressDetails; + + } catch (error) { + console.error("Erreur lors de la récupération des informations :", error); + addressDisplay.textContent = "Impossible de récupérer l'adresse."; + } + }); + }) + .catch(error => { + console.error("Erreur :", error); + }); + }); + + // Ferme la modal sans enregistrer + cancelAddLieu.addEventListener("click", () => { + addLieuModal.classList.add("hidden"); + addressDisplay.innerHTML = ""; // Réinitialise les détails de l'adresse + }); + + // Sélectionne l'emplacement et envoie les données au serveur + selectLocationButton.addEventListener("click", () => { + if (marker) { + const lat = marker.getLatLng().lat; + const lng = marker.getLatLng().lng; + const villeId = document.getElementById("sortie_ville").value; + + if (!villeId) { + alert("Veuillez sélectionner une ville avant d'ajouter un lieu."); + return; + } + + if (!selectedAddress) { + alert("Veuillez sélectionner un emplacement sur la carte."); + return; + } + + // Demande le nom du lieu à l'utilisateur + const nom = prompt("Nom du lieu ?"); + if (!nom) { + alert("Le nom du lieu est obligatoire."); + return; + } + + // Envoie les données au serveur + fetch("/lieu/set", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + nom, + rue: selectedAddress, + latitude: lat, + longitude: lng, + villeId, + }), + }) + .then((response) => { + if (!response.ok) { + throw new Error("Erreur lors de l'ajout du lieu."); + } + return response.json(); + }) + .then((data) => { + console.log("Lieu ajouté :", data); + + // Ajoute le lieu à la liste déroulante + const lieuSelect = document.getElementById("sortie_lieu"); + const option = document.createElement("option"); + option.value = data.id; + option.textContent = data.nom; + lieuSelect.appendChild(option); + + // Sélectionne automatiquement le nouveau lieu + lieuSelect.value = data.id; + + // Ferme la modal + addLieuModal.classList.add("hidden"); + }) + .catch((error) => { + console.error("Erreur :", error); + }); + } else { + alert("Veuillez sélectionner un emplacement sur la carte."); + } + }); + } else { + console.error("Éléments requis pour ajouter un lieu introuvables."); + } +}); diff --git a/assets/js/lieu.js b/assets/js/lieu.js new file mode 100644 index 0000000..27721b9 --- /dev/null +++ b/assets/js/lieu.js @@ -0,0 +1,62 @@ +document.addEventListener('DOMContentLoaded', function () { + const villeSelect = document.getElementById('sortie_ville'); + const lieuSelect = document.getElementById('sortie_lieu'); + + const rueLabel = document.getElementById('rue-value'); + const codePostalLabel = document.getElementById('codePostal-value'); + const latitudeLabel = document.getElementById('latitude-value'); + const longitudeLabel = document.getElementById('longitude-value'); + + if (villeSelect && lieuSelect) { + villeSelect.addEventListener('change', function () { + const villeId = villeSelect.value; + + lieuSelect.innerHTML = ''; + lieuSelect.disabled = true; + + if (villeId) { + fetch(`/get-lieux/${villeId}`) + .then(response => { + if (!response.ok) { + throw new Error('Erreur lors de la récupération des lieux'); + } + return response.json(); + }) + .then(data => { + lieuSelect.innerHTML = ''; + data.forEach(lieu => { + const option = document.createElement('option'); + option.value = lieu.id; + option.textContent = lieu.nom; + option.dataset.details = JSON.stringify(lieu); + lieuSelect.appendChild(option); + }); + + lieuSelect.disabled = false; + }) + .catch(error => { + console.error('Erreur lors de la récupération des lieux :', error); + }); + } + }); + + lieuSelect.addEventListener('change', function () { + const selectedOption = lieuSelect.options[lieuSelect.selectedIndex]; + if (selectedOption && selectedOption.dataset.details) { + const lieuDetails = JSON.parse(selectedOption.dataset.details); + + rueLabel.textContent = lieuDetails.rue || 'Non renseignée'; + codePostalLabel.textContent = lieuDetails.codePostal || 'Non renseigné'; + latitudeLabel.textContent = lieuDetails.latitude || 'Non renseignée'; + longitudeLabel.textContent = lieuDetails.longitude || 'Non renseignée'; + } else { + rueLabel.textContent = 'Renseigner avec le lieu'; + codePostalLabel.textContent = 'Renseigner avec le lieu'; + latitudeLabel.textContent = 'Renseigner avec le lieu'; + longitudeLabel.textContent = 'Renseigner avec le lieu'; + } + }); + } else { + console.error('Les champs ville-select ou lieu-select sont introuvables.'); + } +}); diff --git a/src/Controller/LieuController.php b/src/Controller/LieuController.php index fdd02f3..dba6b40 100644 --- a/src/Controller/LieuController.php +++ b/src/Controller/LieuController.php @@ -2,7 +2,13 @@ namespace App\Controller; +use App\Entity\Lieu; +use App\Entity\Ville; +use App\Repository\VilleRepository; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; @@ -15,4 +21,93 @@ class LieuController extends AbstractController 'controller_name' => 'LieuController', ]); } + + #[Route('/lieu/set', name: 'lieu_set', methods: ['POST'])] + public function setLieu( + Request $request, + VilleRepository $villeRepository, + EntityManagerInterface $entityManager + ): JsonResponse { + $data = json_decode($request->getContent(), true); + + + if (!isset($data['nom'], $data['rue'], $data['latitude'], $data['longitude'], $data['villeId'])) { + return new JsonResponse(['error' => 'Données manquantes'], Response::HTTP_BAD_REQUEST); + } + + + $ville = $villeRepository->find($data['villeId']); + if (!$ville) { + return new JsonResponse(['error' => 'Ville non trouvée'], Response::HTTP_NOT_FOUND); + } + + + $lieu = new Lieu(); + $lieu->setNom($data['nom']); + $lieu->setRue($data['rue']); + $lieu->setLatitude($data['latitude']); + $lieu->setLongitude($data['longitude']); + $lieu->setVille($ville); + + + $entityManager->persist($lieu); + $entityManager->flush(); + + + return new JsonResponse([ + 'id' => $lieu->getIdLieu(), + 'nom' => $lieu->getNom(), + 'rue' => $lieu->getRue(), + 'latitude' => $lieu->getLatitude(), + 'longitude' => $lieu->getLongitude(), + ], Response::HTTP_CREATED); + } + + #[Route('/get-bounds/{villeId}', name: 'get_bounds', methods: ['GET'])] + public function getBounds(VilleRepository $villeRepository, string $villeId): JsonResponse + { + $ville = $villeRepository->find($villeId); + + if (!$ville) { + return new JsonResponse(['error' => 'Ville non trouvée'], Response::HTTP_NOT_FOUND); + } + + // Utilisez l'API Nominatim pour récupérer les bounds + $params = [ + 'q' => $ville->getNom(), + 'format' => 'json', + 'polygon_geojson' => 1, + ]; + $url = 'https://nominatim.openstreetmap.org/search?' . http_build_query($params); + + try { + $context = stream_context_create([ + 'http' => [ + 'header' => "User-Agent: MyApp/1.0 (contact@myapp.com)\r\n", + ], + ]); + + $response = file_get_contents($url, false, $context); + $data = json_decode($response, true); + + if (!empty($data[0]['boundingbox'])) { + $boundingBox = $data[0]['boundingbox']; + $centerLat = ($boundingBox[0] + $boundingBox[1]) / 2; + $centerLng = ($boundingBox[2] + $boundingBox[3]) / 2; + + return new JsonResponse([ + 'south' => $boundingBox[0], + 'north' => $boundingBox[1], + 'west' => $boundingBox[2], + 'east' => $boundingBox[3], + 'centerLat' => $centerLat, + 'centerLng' => $centerLng, + ]); + } + + return new JsonResponse(['error' => 'Bounding box non trouvée'], Response::HTTP_NOT_FOUND); + } catch (\Exception $e) { + return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_INTERNAL_SERVER_ERROR); + } + } } diff --git a/src/Entity/Etat.php b/src/Entity/Etat.php index b04fcd0..4fc749d 100644 --- a/src/Entity/Etat.php +++ b/src/Entity/Etat.php @@ -30,7 +30,7 @@ class Etat $this->sorties = new ArrayCollection(); } - public function getIdEtat(): ?string // Changement ici + public function getIdEtat(): ?string { return $this->idEtat; } @@ -68,7 +68,6 @@ class Etat public function removeSortie(Sortie $sortie): self { if ($this->sorties->removeElement($sortie)) { - // Set the owning side to null (unless already changed) if ($sortie->getEtat() === $this) { $sortie->setEtat(null); } diff --git a/src/Entity/Lieu.php b/src/Entity/Lieu.php index 286c0f5..7cfafa6 100644 --- a/src/Entity/Lieu.php +++ b/src/Entity/Lieu.php @@ -137,4 +137,6 @@ class Lieu return $this; } + + } diff --git a/src/Form/SortieType.php b/src/Form/SortieType.php index c63d691..efc3f92 100644 --- a/src/Form/SortieType.php +++ b/src/Form/SortieType.php @@ -65,7 +65,7 @@ class SortieType extends AbstractType 'choice_label' => 'nom', 'label' => 'Lieu', 'placeholder' => 'Sélectionnez une ville d\'abord', - 'choices' => [], // Pas de choix au début + 'choices' => [], 'attr' => ['id' => 'lieu-select'], ]); } diff --git a/templates/sortie/create.html.twig b/templates/sortie/create.html.twig index 2963bc5..c3ace0c 100644 --- a/templates/sortie/create.html.twig +++ b/templates/sortie/create.html.twig @@ -8,21 +8,24 @@ {{ encore_entry_link_tags('app') }} + {% endblock %} {% endblock %} {% block content %}