diff --git a/assets/utils.js b/assets/utils.js index 7358a94..8b692b7 100644 --- a/assets/utils.js +++ b/assets/utils.js @@ -1,4 +1,3 @@ - function colorHeadingTable() { const headers = document.querySelectorAll('th'); @@ -21,7 +20,7 @@ function check_validity(e) { 'input[name="commerce_tag_value__contact:email"]', 'input[name="commerce_tag_value__contact:phone"]', 'input[name="commerce_tag_value__contact:website"]', - 'commerce_tag_value__contact:mastodon', + 'input[name="commerce_tag_value__contact:mastodon"]', 'input[name="commerce_tag_value__address"]', 'input[name="custom_opening_hours"]', 'input[name="commerce_tag_value__contact:street"]', diff --git a/labourage.sh b/labourage.sh index cc51777..59dca32 100644 --- a/labourage.sh +++ b/labourage.sh @@ -12,6 +12,18 @@ codes_insee=( "33063" # Bordeaux "59350" # Lille "35238" # Rennes + "75101" # Paris 1er + "75102" # Paris 2e + "75103" # Paris 3e + "75104" # Paris 4e + "75105" # Paris 5e + "75106" # Paris 6e + "75107" # Paris 7e + "75108" # Paris 8e + "75109" # Paris 9e + "75110" # Paris 10e + "75111" # Paris 11e + "75112" # Paris 12e "75113" # Paris 13e "75114" # Paris 14e "75115" # Paris 15e diff --git a/migrations/Version20250617141249.php b/migrations/Version20250617141249.php new file mode 100644 index 0000000..006f42b --- /dev/null +++ b/migrations/Version20250617141249.php @@ -0,0 +1,35 @@ +addSql(<<<'SQL' + ALTER TABLE place ADD habitants INT DEFAULT NULL + SQL); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql(<<<'SQL' + ALTER TABLE place DROP habitants + SQL); + } +} diff --git a/migrations/Version20250617141824.php b/migrations/Version20250617141824.php new file mode 100644 index 0000000..c6d01f3 --- /dev/null +++ b/migrations/Version20250617141824.php @@ -0,0 +1,35 @@ +addSql(<<<'SQL' + ALTER TABLE stats ADD population INT DEFAULT NULL + SQL); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql(<<<'SQL' + ALTER TABLE stats DROP population + SQL); + } +} diff --git a/public/assets/img/josm.png b/public/assets/img/josm.png new file mode 100644 index 0000000..1764904 Binary files /dev/null and b/public/assets/img/josm.png differ diff --git a/public/assets/img/logo-osm.png b/public/assets/img/logo-osm.png new file mode 100644 index 0000000..4388167 Binary files /dev/null and b/public/assets/img/logo-osm.png differ diff --git a/public/assets/img/osm-id.png b/public/assets/img/osm-id.png new file mode 100644 index 0000000..2ea1914 Binary files /dev/null and b/public/assets/img/osm-id.png differ diff --git a/public/js/utils.js b/public/js/utils.js new file mode 100644 index 0000000..bc42570 --- /dev/null +++ b/public/js/utils.js @@ -0,0 +1,166 @@ +// Fonction pour gérer la recherche de villes +/** + * Configure la recherche de ville avec autocomplétion + * @param {string} inputId - ID de l'input de recherche + * @param {string} suggestionListId - ID de la liste des suggestions + * @param {Function} onSelect - Callback appelé lors de la sélection d'une ville + */ +export function setupCitySearch(inputId, suggestionListId, onSelect) { + const searchInput = document.getElementById(inputId); + const suggestionList = document.getElementById(suggestionListId); + + if (!searchInput || !suggestionList) return; + + let timeoutId = null; + + searchInput.addEventListener('input', function () { + clearTimeout(timeoutId); + const query = this.value.trim(); + + if (query.length < 2) { + clearSuggestions(); + return; + } + + timeoutId = setTimeout(() => performSearch(query), 300); + }); + + function performSearch(query) { + fetch(`https://geo.api.gouv.fr/communes?nom=${encodeURIComponent(query)}&fields=nom,code,codesPostaux&limit=5`) + .then(response => response.json()) + .then(data => { + const citySuggestions = data.map(city => ({ + name: city.nom, + postcode: city.codesPostaux[0], + insee: city.code + })); + displaySuggestions(citySuggestions); + }) + .catch(error => { + console.error('Erreur lors de la recherche:', error); + clearSuggestions(); + }); + } + + function displaySuggestions(suggestions) { + clearSuggestions(); + suggestions.forEach(suggestion => { + const li = document.createElement('li'); + li.className = 'list-group-item'; + li.textContent = `${suggestion.name} (${suggestion.postcode})`; + li.addEventListener('click', () => { + searchInput.value = suggestion.name; + clearSuggestions(); + if (onSelect) onSelect(suggestion); + }); + suggestionList.appendChild(li); + }); + } + + function clearSuggestions() { + suggestionList.innerHTML = ''; + } + + // Fermer les suggestions en cliquant en dehors + document.addEventListener('click', function (e) { + if (!searchInput.contains(e.target) && !suggestionList.contains(e.target)) { + clearSuggestions(); + } + }); +} + +// Fonction pour formater l'URL de labourage +/** + * Génère l'URL de labourage pour un code postal donné + * @param {string} zipCode - Le code postal + * @returns {string} L'URL de labourage + */ +export function getLabourerUrl(zipCode) { + return `/admin/labourer/${zipCode}`; +} + +// Fonction pour gérer la soumission du formulaire d'ajout de ville +export function handleAddCityFormSubmit(event) { + event.preventDefault(); + const form = event.target; + const submitButton = form.querySelector('button[type="submit"]'); + const zipCodeInput = form.querySelector('input[name="zip_code"]'); + if (!zipCodeInput.value) { + return; + } + // Afficher le spinner + submitButton.disabled = true; + const originalContent = submitButton.innerHTML; + submitButton.innerHTML = ' Labourer...'; + // Rediriger + window.location.href = getLabourerUrl(zipCodeInput.value); +} + +/** + * Colore les cellules d'un tableau en fonction des pourcentages + * @param {string} selector - Le sélecteur CSS pour cibler les cellules à colorer + * @param {string} color - La couleur de base en format RGB (ex: '154, 205, 50') + */ +export function colorizePercentageCells(selector, color = '154, 205, 50') { + document.querySelectorAll(selector).forEach(cell => { + const percentage = parseInt(cell.textContent); + if (!isNaN(percentage)) { + const alpha = percentage / 100; + cell.style.backgroundColor = `rgba(${color}, ${alpha})`; + } + }); +} + +/** + * Colore les cellules d'un tableau avec un gradient relatif à la valeur maximale + * @param {string} selector - Le sélecteur CSS pour cibler les cellules à colorer + * @param {string} color - La couleur de base en format RGB (ex: '154, 205, 50') + */ +export function colorizePercentageCellsRelative(selector, color = '154, 205, 50') { + // Récupérer toutes les cellules + const cells = document.querySelectorAll(selector); + + // Trouver la valeur maximale + let maxValue = 0; + cells.forEach(cell => { + const value = parseInt(cell.textContent); + if (!isNaN(value) && value > maxValue) { + maxValue = value; + } + }); + + // Appliquer le gradient relatif à la valeur max + cells.forEach(cell => { + const value = parseInt(cell.textContent); + if (!isNaN(value)) { + const alpha = value / maxValue; // Ratio relatif au maximum + cell.style.backgroundColor = `rgba(${color}, ${alpha})`; + } + }); +} + +/** + * Ajuste dynamiquement la taille du texte des éléments list-group-item selon leur nombre + * @param {string} selector - Le sélecteur CSS des éléments à ajuster + * @param {number} [minFont=0.8] - Taille de police minimale en rem + * @param {number} [maxFont=1.2] - Taille de police maximale en rem + */ +export function adjustListGroupFontSize(selector, minFont = 0.8, maxFont = 1.2) { + const items = document.querySelectorAll(selector); + const count = items.length; + let fontSize = maxFont; + if (count > 0) { + // Plus il y a d'items, plus la taille diminue, mais jamais en dessous de minFont + fontSize = Math.max(minFont, maxFont - (count - 5) * 0.05); + } + items.forEach(item => { + item.style.fontSize = fontSize + 'rem'; + }); +} + +function check_validity() { + if (!document.getElementById('editLand')) { + return; + } + // ... suite du code ... +} \ No newline at end of file diff --git a/src/Controller/AdminController.php b/src/Controller/AdminController.php index 6c74ab3..0b3b30f 100644 --- a/src/Controller/AdminController.php +++ b/src/Controller/AdminController.php @@ -131,10 +131,8 @@ final class AdminController extends AbstractController // Récupérer ou créer les stats pour cette zone $stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $zip_code]); - $city = $this->motocultrice->get_city_osm_from_zip_code($zip_code); if (!$stats) { - $stats = new Stats(); $stats->setZone($zip_code) ->setPlacesCount(0) @@ -144,11 +142,27 @@ final class AdminController extends AbstractController ->setAvecAccessibilite(0) ->setAvecNote(0) ->setCompletionPercent(0); - $this->entityManager->persist($stats); - $this->entityManager->flush(); - } + $this->entityManager->persist($stats); + $this->entityManager->flush(); + } $stats->setName($city); + // Récupérer la population via l'API + $population = null; + try { + $apiUrl = 'https://geo.api.gouv.fr/communes/' . $zip_code . '?fields=population'; + $response = file_get_contents($apiUrl); + if ($response !== false) { + $data = json_decode($response, true); + if (isset($data['population'])) { + $population = (int)$data['population']; + $stats->setPopulation($population); + } + } + } catch (\Exception $e) { + // Ne rien faire si l'API échoue + } + // Récupérer toutes les données $places = $this->motocultrice->labourer($zip_code); $processedCount = 0; diff --git a/src/Controller/PublicController.php b/src/Controller/PublicController.php index 7dff42e..593c560 100644 --- a/src/Controller/PublicController.php +++ b/src/Controller/PublicController.php @@ -102,7 +102,7 @@ class PublicController extends AbstractController $message = (new Email()) ->from('contact@osm-commerce.fr') ->to($destinataire) - ->subject('Votre lien de modification Ope nStreetMap') + ->subject('Votre lien de modification OpenStreetMap') ->text('Bonjour, nous sommes des bénévoles d\'OpenStreetMap France et nous vous proposons de modifier les informations de votre commerce. Voici votre lien unique de modification: ' . $this->generateUrl('app_public_edit', [ 'zipcode' => $zipCode, 'name' => $place_name, @@ -117,10 +117,11 @@ class PublicController extends AbstractController #[Route('/', name: 'app_public_index')] public function index(): Response { + $stats = $this->entityManager->getRepository(Stats::class)->findAll(); return $this->render('public/home.html.twig', [ 'controller_name' => 'PublicController', - + 'stats' => $stats ]); } @@ -190,7 +191,6 @@ class PublicController extends AbstractController #[Route('/modify/{osm_object_id}/{version}/{changesetID}', name: 'app_public_submit')] public function submit($osm_object_id, $version, $changesetID): Response { - $place = $this->entityManager->getRepository(Place::class)->findOneBy(['osmId' => $osm_object_id]); if (!$place) { $this->addFlash('warning', 'Ce commerce n\'existe pas.'); @@ -212,11 +212,9 @@ class PublicController extends AbstractController $request_post = $request->request->all(); - $request_post = $this->motocultrice->map_post_values($request_post); foreach ($request_post as $key => $value) { - if (strpos($key, 'commerce_tag_value__') === 0) { $tagKey = str_replace('commerce_tag_value__', '', $key); if (!empty($value)) { @@ -236,7 +234,6 @@ class PublicController extends AbstractController // Récupérer le token OSM depuis les variables d'environnement $osm_api_token = $_ENV['APP_OSM_BEARER']; - $exception = false; $exception_message = ""; try { @@ -293,7 +290,6 @@ class PublicController extends AbstractController // Debug du XML généré $xmlString = $xml->asXML(); - // echo('xml :
'.$xmlString); $response = $client->put("https://api.openstreetmap.org/api/0.6/{$osm_kind}/" . $osm_object_id, [ 'body' => $xmlString, @@ -327,15 +323,13 @@ class PublicController extends AbstractController } // après envoi on récupère les données - $commerce = $this->motocultrice->get_osm_object_data($osm_kind, $osm_object_id); + $commerce_overpass = $this->motocultrice->get_osm_object_data($osm_kind, $osm_object_id); - - $place->update_place_from_overpass_data($commerce); + $place->update_place_from_overpass_data($commerce_overpass); $this->entityManager->persist($place); $this->entityManager->flush(); $this->entityManager->clear(); - $stats = $place->getStats(); if(!$stats) { $stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zip_code' => $place->getZipCode()]); @@ -345,19 +339,20 @@ class PublicController extends AbstractController $stats->setZipCode($place->getZipCode()); } - $stats->addPlace($place); - $place->setStats($stats); - $place->setModifiedDate(new \DateTime()); + $stats->addPlace($place); + $place->setStats($stats); + $place->setModifiedDate(new \DateTime()); - $stats->computeCompletionPercent(); - $this->entityManager->persist($stats); - $this->entityManager->persist($place); - $this->entityManager->flush(); - $this->entityManager->clear(); + $stats->computeCompletionPercent(); + $this->entityManager->persist($stats); + $this->entityManager->persist($place); + $this->entityManager->flush(); + $this->entityManager->clear(); return $this->render('public/view.html.twig', [ 'controller_name' => 'PublicController', - 'commerce' => $commerce, + 'commerce' => $commerce_overpass, + 'commerce_overpass' => $commerce_overpass, 'place' => $place, 'status' => $status, 'exception' => $exception, diff --git a/src/Entity/Place.php b/src/Entity/Place.php index 1ceb91b..a3d3328 100644 --- a/src/Entity/Place.php +++ b/src/Entity/Place.php @@ -100,6 +100,9 @@ class Place #[ORM\Column(length: 255, nullable: true)] private ?string $siret = null; + #[ORM\Column(nullable: true)] + private ?int $habitants = null; + public function getMainTag(): ?string { return $this->main_tag; @@ -579,4 +582,16 @@ class Place return $this; } + + public function getHabitants(): ?int + { + return $this->habitants; + } + + public function setHabitants(?int $habitants): static + { + $this->habitants = $habitants; + + return $this; + } } diff --git a/src/Entity/Stats.php b/src/Entity/Stats.php index 872fda9..6db0de4 100644 --- a/src/Entity/Stats.php +++ b/src/Entity/Stats.php @@ -17,7 +17,7 @@ class Stats private ?int $id = null; #[ORM\Column(length: 255)] - private ?string $zone = null; + private ?string $zone = null; // code insee de la zone #[ORM\Column(type: Types::SMALLINT)] private ?int $completion_percent = null; @@ -55,6 +55,10 @@ class Stats #[ORM\Column(length: 255, nullable: true)] private ?string $name = null; + // nombre d'habitants dans la zone + #[ORM\Column(type: Types::INTEGER, nullable: true)] + private ?int $population = null; + // calcule le pourcentage de complétion de la zone public function computeCompletionPercent(): ?int { @@ -255,6 +259,17 @@ class Stats return $this; } + + public function getPopulation(): ?int + { + return $this->population; + } + + public function setPopulation(?int $population): static + { + $this->population = $population; + return $this; + } } diff --git a/templates/admin/stats.html.twig b/templates/admin/stats.html.twig index 933415a..a4cf711 100644 --- a/templates/admin/stats.html.twig +++ b/templates/admin/stats.html.twig @@ -16,6 +16,9 @@ height: 300px; margin: 20px 0; } + .completion-info { + margin-bottom: 2rem; + } {% endblock %} @@ -34,6 +37,27 @@ + {% if stats.population %} +
+
+ + Population : {{ stats.population|number_format(0, '.', ' ') }} + +
+
+ + 1 lieu pour + {% set ratio = (stats.population and stats.places|length > 0) ? (stats.population / stats.places|length)|round(0, 'ceil') : '?' %} + {{ ratio|number_format(0, '.', ' ') }} habitants + +
+
+ + {{ stats.getAvecNote() }} / {{ stats.places|length }} commerces avec note + +
+
+ {% endif %}
@@ -78,6 +102,29 @@ commerces avec note renseignée.
+ +
+
+
+ +

Comment est calculé le score de complétion ?

+ +
+ +
+
@@ -101,12 +148,9 @@
- -
-

Tableau des {{ stats.places |length }} lieux

@@ -128,11 +172,19 @@
-

requête overpass

-
-    {{query_places|raw}}
-    
-
+
+
+

Requête Overpass

+
+
+
+            {{query_places|raw}}
+            
+ + Exécuter dans Overpass Turbo + +
+
@@ -167,28 +219,52 @@ function calculateCompletion(element) { let completionCount = 0; let totalFields = 0; + let missingFields = []; const fieldsToCheck = [ - 'name', - 'contact:street', - 'contact:housenumber', - 'opening_hours', - 'contact:website', - 'contact:phone', - 'wheelchair' + {name: 'name', label: 'Nom du commerce'}, + {name: 'contact:street', label: 'Rue'}, + {name: 'contact:housenumber', label: 'Numéro'}, + {name: 'opening_hours', label: 'Horaires d\'ouverture'}, + {name: 'contact:website', label: 'Site web'}, + {name: 'contact:phone', label: 'Téléphone'}, + {name: 'wheelchair', label: 'Accessibilité PMR'} ]; fieldsToCheck.forEach(field => { totalFields++; - if (element.tags && element.tags[field]) { + if (element.tags && element.tags[field.name]) { completionCount++; + } else { + missingFields.push(field.label); } }); - return (completionCount / totalFields) * 100; + return { + percentage: (completionCount / totalFields) * 100, + missingFields: missingFields + }; + } + + function showMissingFieldsPopup(element) { + const completion = calculateCompletion(element); + if (completion.percentage < 100) { + const popup = new maplibregl.Popup() + .setLngLat(element.geometry.coordinates) + .setHTML(` +
+
Informations manquantes pour ${element.tags?.name || 'ce commerce'}
+ +
+ `); + popup.addTo(map); + } } function createPopupContent(element) { + const completion = calculateCompletion(element); let content = `
@@ -200,6 +276,17 @@
`; + if (completion.percentage < 100) { + content += ` +
+
Informations manquantes :
+ +
+ `; + } + content += ''; // Ajouter tous les tags @@ -219,7 +306,7 @@ elements.forEach(element => { const completion = calculateCompletion(element); - const bucketIndex = Math.floor(completion / 10); + const bucketIndex = Math.floor(completion.percentage / 10); buckets[bucketIndex]++; }); @@ -325,7 +412,7 @@ properties: { id: element.id, name: element.tags?.name || 'Sans nom', - completion: completion, + completion: completion.percentage, center: [lon, lat] }, geometry: { @@ -369,86 +456,33 @@ function updateMarkers() { // Supprimer tous les marqueurs existants - features.forEach(feature => { - const layerId = `marker-${feature.properties.id}`; - // Supprimer d'abord la couche - if (map.getLayer(layerId)) { - map.removeLayer(layerId); - } - // Puis supprimer la source - if (map.getSource(layerId)) { - map.removeSource(layerId); - } - }); - - // Supprimer tous les marqueurs en goutte existants dropMarkers.forEach(marker => marker.remove()); dropMarkers = []; - if (currentMarkerType === 'circle') { - // Afficher les cercles - features.forEach(feature => { - const layerId = `marker-${feature.properties.id}`; - const circle = turf.circle( - feature.properties.center, - 5/1000, - { steps: 64, units: 'kilometers' } - ); + features.forEach(feature => { + const el = document.createElement('div'); + el.className = 'marker'; + el.style.backgroundColor = getCompletionColor(feature.properties.completion); + el.style.width = '15px'; + el.style.height = '15px'; + el.style.borderRadius = '50%'; + el.style.border = '2px solid white'; + el.style.cursor = 'pointer'; - map.addSource(layerId, { - 'type': 'geojson', - 'data': circle - }); + const marker = new maplibregl.Marker(el) + .setLngLat(feature.geometry.coordinates) + .addTo(map); - map.addLayer({ - 'id': layerId, - 'type': 'fill', - 'source': layerId, - 'paint': { - 'fill-color': getCompletionColor(feature.properties.completion), - 'fill-opacity': 0.7 - } - }); - }); - - // Ajouter les popups sur les cercles - map.on('click', function(e) { - const clickedFeatures = map.queryRenderedFeatures(e.point, { - layers: features.map(f => `marker-${f.properties.id}`) - }); - - if (clickedFeatures.length > 0) { - const feature = clickedFeatures[0]; - const elementId = feature.layer.id.replace('marker-', ''); - const element = overpassData[elementId]; - - if (element) { - // Créer le contenu de la popup - const popupContent = createPopupContent(element); - - new maplibregl.Popup() - .setLngLat(e.lngLat) - .setHTML(popupContent) - .addTo(map); - } + // Ajouter l'événement de clic + el.addEventListener('click', () => { + const element = overpassData[feature.properties.id]; + if (element) { + showMissingFieldsPopup(element); } }); - } else { - // Afficher les marqueurs en goutte - features.forEach(feature => { - const element = overpassData[feature.properties.id]; - const popupContent = element ? createPopupContent(element) : `

${feature.properties.name}

`; - - const marker = new maplibregl.Marker({ - color: getCompletionColor(feature.properties.completion) - }) - .setLngLat(feature.properties.center) - .setPopup(new maplibregl.Popup({ offset: 25 }) - .setHTML(popupContent)) - .addTo(map); - dropMarkers.push(marker); - }); - } + + dropMarkers.push(marker); + }); } function draw_circle_containing_all_features(map) { @@ -691,6 +725,55 @@ }); sortTable(); + + // Initialiser les popovers pour les cellules de complétion + const completionCells = document.querySelectorAll('.completion-cell'); + completionCells.forEach(cell => { + new bootstrap.Popover(cell, { + trigger: 'hover', + html: true + }); + + // Fermer tous les popovers au clic sur une cellule + cell.addEventListener('click', function(e) { + e.stopPropagation(); + completionCells.forEach(otherCell => { + if (otherCell !== cell) { + const popover = bootstrap.Popover.getInstance(otherCell); + if (popover) { + popover.hide(); + } + } + }); + }); + }); + + // Fermer tous les popovers quand on clique ailleurs + document.addEventListener('click', function(e) { + if (!e.target.closest('.completion-cell')) { + completionCells.forEach(cell => { + const popover = bootstrap.Popover.getInstance(cell); + if (popover) { + popover.hide(); + } + }); + } + }); }); + + function toggleCompletionInfo() { + const content = document.getElementById('completionInfoContent'); + const icon = document.getElementById('completionInfoIcon'); + + if (content.style.display === 'none') { + content.style.display = 'block'; + icon.classList.remove('bi-chevron-down'); + icon.classList.add('bi-chevron-up'); + } else { + content.style.display = 'none'; + icon.classList.remove('bi-chevron-up'); + icon.classList.add('bi-chevron-down'); + } + } {% endblock %} \ No newline at end of file diff --git a/templates/admin/stats/row.html.twig b/templates/admin/stats/row.html.twig index dba5d08..4e351a4 100644 --- a/templates/admin/stats/row.html.twig +++ b/templates/admin/stats/row.html.twig @@ -10,7 +10,37 @@ {% endif %} -
+ {{ commerce.getCompletionPercentage() }} diff --git a/templates/public/dashboard.html.twig b/templates/public/dashboard.html.twig index a317a01..b1a21ce 100644 --- a/templates/public/dashboard.html.twig +++ b/templates/public/dashboard.html.twig @@ -14,216 +14,184 @@ width: 100%; margin-bottom: 1rem; } + .suggestion-list { + position: absolute; + background: white; + border: 1px solid #ddd; + border-radius: 4px; + max-height: 200px; + overflow-y: auto; + width: 100%; + z-index: 1000; + display: none; + } + .suggestion-item { + padding: 8px 12px; + cursor: pointer; + border-bottom: 1px solid #eee; + } + .suggestion-item:hover { + background-color: #f5f5f5; + } + .suggestion-name { + font-weight: bold; + } + .suggestion-details { + font-size: 0.9em; + color: #666; + } + .suggestion-type { + margin-right: 8px; + } + .search-container { + position: relative; + margin-bottom: 1rem; + } {% endblock %} {% block javascripts %} {{ parent() }} - - - + {% endblock %} {% block body %} -
+
-

Dashboard

+

Tableau de bord

+
+ +
-

Statistiques : {{ stats|length }} codes postaux

- - +

Statistiques par ville

+
+ + + + + + + + + + + + {% for stat in stats %} + + + + + + + + {% endfor %} + +
VilleCode postalComplétionNombre de commercesActions
+ {{ stat.name }} + {{ stat.zone }}{{ stat.completionPercent }}%{{ stat.places|length }} + +
+
+
+
- - - - - - - - - - - {% for stat in stats %} - - - - - - - {% endfor %} - -
ZoneNombre de lieuxComplétude %Actions
- {{ stat.zone }} {{ stat.name }} - {{ stat.placesCount }}{{ stat.completionPercent }} - - - -
- - -

{{ places_count }} Lieux

-

-
{% endblock %} diff --git a/templates/public/edit.html.twig b/templates/public/edit.html.twig index e8cf7a2..a205bfb 100644 --- a/templates/public/edit.html.twig +++ b/templates/public/edit.html.twig @@ -4,11 +4,7 @@ {% block body %} -
- -
-    {{ dump(commerce_overpass) }}
-
+
@@ -19,7 +15,7 @@ {% if commerce_overpass is not empty %}
- {# nom #} +
@@ -90,13 +86,10 @@
- - {% endif %}
-
@@ -130,23 +123,31 @@ {{ 'display.by'|trans }} {{ commerce_overpass['@attributes'].user }}
- -
{{ 'display.view_on_osm'|trans }} + {{ asset('img/logo-osm.png') }} - -
+ {% if commerce.stats %} + + zone {{commerce.stats.zone}} + + {% endif %} + - - Dashboard + Dashboard
diff --git a/templates/public/edit/tags.html.twig b/templates/public/edit/tags.html.twig index ee403ef..35500ac 100644 --- a/templates/public/edit/tags.html.twig +++ b/templates/public/edit/tags.html.twig @@ -1,43 +1,45 @@ {% block tags %}
- - {% for k, v in commerce_overpass.tags_converted %} - -
-
- {% if k not in excluded_tags_to_render %} - {% if k == 'phone' or k == 'contact:phone' %} - - {% elseif k == 'addr:housenumber' or k == 'addr:street' or k == 'addr:city' or k == 'addr:postcode' or k == 'addr:country' %} - - {% elseif k == 'contact:mastodon' %} - - {% elseif k == 'email' or k == 'contact:email' %} - - {% elseif k == 'website' or k == 'contact:website' %} - {% elseif k == 'opening_hours' %} - - {% else %} - - {% endif %} - {% endif %} - - {% if k not in excluded_tags_to_render %} - - {{ ('display.keys.' ~ k)|trans }} - {% endif %} -
-
+ {% for k, v in commerce_overpass.tags_converted %} +
+
{% if k not in excluded_tags_to_render %} - - +
+ {% if k == 'phone' or k == 'contact:phone' %} + + {% elseif k == 'addr:housenumber' or k == 'addr:street' or k == 'addr:city' or k == 'addr:postcode' or k == 'addr:country' %} + + {% elseif k == 'contact:mastodon' %} + + {% elseif k == 'email' or k == 'contact:email' %} + + {% elseif k == 'website' or k == 'contact:website' %} + + {% elseif k == 'opening_hours' %} + + {% else %} + + {% endif %} + {{ ('display.keys.' ~ k)|trans }} +
+ {% endif %} -
- - {% endfor %} - +
+ {% if k not in excluded_tags_to_render %} +
+ +
+ {% endif %} +
+
+ {% endfor %}
{% endblock %} \ No newline at end of file diff --git a/templates/public/home.html.twig b/templates/public/home.html.twig index f85eda6..0f5a149 100644 --- a/templates/public/home.html.twig +++ b/templates/public/home.html.twig @@ -6,7 +6,63 @@ {{ parent() }} {% endblock %} @@ -14,40 +70,56 @@
+

+ Mon Commerce OSM +

+

+ Bonjour, ce site permet de modifier les informations de votre commerce sur OpenStreetMap afin de gagner en visibilité sur des milliers de sites web à la fois en une minute, c'est gratuit et sans engagement. +
Nous sommes bénévoles dans une association à but non lucratif. +
Nous vous enverrons un lien unique pour cela par email, et si vous en avez besoin, nous pouvons vous aider. +

+
+
+ + +
+
+ +
+ +
+ + +
+
- -

- Mon Commerce OSM -

-

- Bonjour, ce site permet de modifier les informations de votre commerce sur OpenStreetMap afin de gagner en visibilité sur des milliers de sites web à la fois en une minute, c'est gratuit et sans engagement. -
Nous sommes bénévoles dans une association à but non lucratif. -
Nous vous enverrons un lien unique pour cela par email, et si vous en avez besoin, nous pouvons vous aider. -

-

- - -

-
- - - -
-
- -
- -
- - - -
-
- +
+
+ +
+

Villes disponibles

+

Visualisez un tableau de bord de la complétion des commerces et autres lieux d'intérêt pour votre ville grâce à OpenStreetMap

+ +
+ + {% for stat in stats %} + +
+ {{ stat.zone }} + {{ stat.name }} +
+ {{ stat.placesCount }} lieux +
+ {% endfor %} + + + +
{% endblock %} +{% block javascripts %} + {{ parent() }} + +{% endblock %} + diff --git a/templates/public/view.html.twig b/templates/public/view.html.twig index c73df0b..8ef74fe 100644 --- a/templates/public/view.html.twig +++ b/templates/public/view.html.twig @@ -27,7 +27,7 @@
- + {% include 'public/edit/yenaunpeuplusjevouslemets.html.twig' %}