From f158d2f3fd54c75c6e6b64386b15ceb3da196962 Mon Sep 17 00:00:00 2001 From: Leo Gourdin Date: Fri, 24 Jan 2025 12:58:48 +0100 Subject: [PATCH 01/21] adapt nginx config for so preprod --- docker/nginx.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/nginx.conf b/docker/nginx.conf index 9cf69d1f0..f29a8293f 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -1,5 +1,6 @@ server { - listen ${PORT} proxy_protocol; + listen ${PORT}; + #listen ${PORT} proxy_protocol; server_name ${SERVER_NAME}; root /usr/share/nginx/html; index index.html; From c8cce714383cc94be6743cc23ae9b0d9dbb2bc4d Mon Sep 17 00:00:00 2001 From: Leo Gourdin Date: Mon, 27 Jan 2025 11:53:36 +0100 Subject: [PATCH 02/21] set our internal api url --- vue.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vue.config.js b/vue.config.js index 32d616025..9eda95044 100644 --- a/vue.config.js +++ b/vue.config.js @@ -92,7 +92,7 @@ const config = { urlsConfigurations: { demo: { name: 'demo', - api: 'https://api.demov6.camptocamp.org', + api: 'https://preprod.c2c.preprod0.smart-origin.com/api', media: 'https://sos-ch-dk-2.exo.io/c2corg-demov6-active', imageBackend: 'https://images.demov6.camptocamp.org', tracking: 'https://tracking.demov6.camptocamp.org', @@ -114,7 +114,7 @@ const config = { }, prod: { name: 'prod', - api: 'https://api.camptocamp.org', + api: 'https://preprod.c2c.preprod0.smart-origin.com/api', media: 'https://media.camptocamp.org/c2corg-active', imageBackend: 'https://images.camptocamp.org', tracking: 'https://tracking.camptocamp.org', From 3660d3f4a3447b4897ffebc439202837237289d3 Mon Sep 17 00:00:00 2001 From: Leo Gourdin Date: Mon, 27 Jan 2025 13:13:53 +0100 Subject: [PATCH 03/21] trying debug features --- vue.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vue.config.js b/vue.config.js index 9eda95044..465835a34 100644 --- a/vue.config.js +++ b/vue.config.js @@ -185,10 +185,12 @@ if (process.env.BUILD_ENV === 'local' || process.env.BUILD_ENV === undefined) { config.bingApiKey = 'AudizIfCd3NAdt91ubJMGkMI-swfHxe1R-_U7KiLxCHqepDy70txQ-_-89_eevxc'; - config.isBackendSelectable = false; // explicit flag + // config.isBackendSelectable = false; // explicit flag // set a warning if bundle size is too big result.configureWebpack.performance.hints = 'warning'; + // add map for debbuging tools + result.configureWebpack.devtool = 'source-map'; } else { throw new Error('Unknown BUILD_ENV'); } From 3820318be14cb2b50c418e4c9c6d762ccd96cdfb Mon Sep 17 00:00:00 2001 From: Leo Gourdin Date: Mon, 27 Jan 2025 16:02:49 +0100 Subject: [PATCH 04/21] Revert "trying debug features" This reverts commit 3660d3f4a3447b4897ffebc439202837237289d3. --- vue.config.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vue.config.js b/vue.config.js index 465835a34..9eda95044 100644 --- a/vue.config.js +++ b/vue.config.js @@ -185,12 +185,10 @@ if (process.env.BUILD_ENV === 'local' || process.env.BUILD_ENV === undefined) { config.bingApiKey = 'AudizIfCd3NAdt91ubJMGkMI-swfHxe1R-_U7KiLxCHqepDy70txQ-_-89_eevxc'; - // config.isBackendSelectable = false; // explicit flag + config.isBackendSelectable = false; // explicit flag // set a warning if bundle size is too big result.configureWebpack.performance.hints = 'warning'; - // add map for debbuging tools - result.configureWebpack.devtool = 'source-map'; } else { throw new Error('Unknown BUILD_ENV'); } From 2704688021cc2b2c44e564de2238aae8a3f6cbda Mon Sep 17 00:00:00 2001 From: "floriane.jandot" Date: Fri, 31 Jan 2025 11:53:02 +0100 Subject: [PATCH 05/21] add transport box --- .eslintrc.json | 1 + src/assets/img/boxes/public_transports.png | Bin 0 -> 7782 bytes src/translations/fr.json | 2 + src/views/document/RouteView.vue | 2 + .../document/utils/boxes/TransportsBox.vue | 74 ++++++++++++++++++ .../document/utils/document-view-mixin.js | 2 + vue.config.js | 11 ++- 7 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/assets/img/boxes/public_transports.png create mode 100644 src/views/document/utils/boxes/TransportsBox.vue diff --git a/.eslintrc.json b/.eslintrc.json index 8d6c83c5a..bc0bf1308 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -11,6 +11,7 @@ ], "reportUnusedDisableDirectives": true, "rules": { + "prettier/prettier": ["warn", { "endOfLine": "auto" }], "no-unused-vars": "warn", "no-console": "warn", "vue/no-v-html": "off", diff --git a/src/assets/img/boxes/public_transports.png b/src/assets/img/boxes/public_transports.png new file mode 100644 index 0000000000000000000000000000000000000000..a8ab729082d20c16736a653ed3529032c483e2ae GIT binary patch literal 7782 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 + + diff --git a/src/views/document/utils/boxes/TransportsBox.vue b/src/views/document/utils/boxes/TransportsBox.vue new file mode 100644 index 000000000..fa3c8dc9e --- /dev/null +++ b/src/views/document/utils/boxes/TransportsBox.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/src/views/document/utils/document-view-mixin.js b/src/views/document/utils/document-view-mixin.js index ae101ece2..e751e9ead 100644 --- a/src/views/document/utils/document-view-mixin.js +++ b/src/views/document/utils/document-view-mixin.js @@ -6,6 +6,7 @@ import MapBox from './boxes/MapBox'; import RecentOutingsBox from './boxes/RecentOutingsBox'; import RoutesBox from './boxes/RoutesBox'; import ToolBox from './boxes/ToolBox'; +import TransportsBox from './boxes/TransportsBox'; import ActivitiesField from './field-viewers/ActivitiesField'; import DoubleNumericField from './field-viewers/DoubleNumericField'; import EventActivityField from './field-viewers/EventActivityField'; @@ -40,6 +41,7 @@ export default { ToolBox, RoutesBox, ImagesBox, + TransportsBox, }, mixins: [viewModeMixin, isEditableMixin], diff --git a/vue.config.js b/vue.config.js index 32d616025..2ef93e051 100644 --- a/vue.config.js +++ b/vue.config.js @@ -134,10 +134,19 @@ const config = { corosConnectAuthUrl: 'https://open.coros.com/oauth2/authorize', corosClientId: 'f263ed9257c74e808befaf548a27852c', }, + localhost: { + name: 'localhost', + api: 'http://localhost:6543', + media: 'https://sos-ch-dk-2.exo.io/c2corg-demov6-active', + imageBackend: 'https://images.demov6.camptocamp.org', + forum: 'https://forum.demov6.camptocamp.org', + modernThumbnailsTimestamp: 0, + modernThumbnailsId: 0, + }, }, }; -config.urls = config.urlsConfigurations.prod; // default: prod +config.urls = config.urlsConfigurations.localhost; // default: prod const bundleAnalyzerConfig = { analyzerMode: 'disabled', From a53d9f1794eea1c632d619c14ad56f407cba3a47 Mon Sep 17 00:00:00 2001 From: "floriane.jandot" Date: Mon, 3 Mar 2025 14:21:49 +0100 Subject: [PATCH 06/21] [new feature] Display all stop points on list and map --- src/translations/fr.json | 5 + src/views/document/RouteView.vue | 2 - src/views/document/WaypointView.vue | 2 + .../document/utils/boxes/TransportsBox.vue | 221 +++++++++++++++++- 4 files changed, 221 insertions(+), 9 deletions(-) diff --git a/src/translations/fr.json b/src/translations/fr.json index 317c50fd1..1e66690bd 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -215,6 +215,7 @@ "Directions (Google Maps)": "Se rendre à ce lieu (Google Maps)", "Disabled at this zoom level": "Désactivé à ce niveau de zoom", "Disclaimer": "Avertissement", + "Distance between the stop and the starting point of the topo" : "Distance entre l'arrêt et le point de départ du topo", "Do you really want to leave? you have unsaved changes!": "Voulez-vous vraiment quitter cette page ? Des changements n'ont pas été sauvegardés !", "Document quality": "Qualité du document", "Donate": "Faire un don à l'association Camptocamp", @@ -385,6 +386,7 @@ "Let's preserve our playground! I create an account on Outdoorvision to share my GPS tracks for the preservation and design of my practice sites in France.": "Préservons notre terrain de jeu ! Je crée un compte sur Outdoorvision pour y partager mes traces GPS pour la préservation et l’aménagement de mes sites de pratique en France.", "Library:": "Une bibliothèque comportant ", "Licenses": "Licences", + "Line" : "Ligne", "Lines chunks": "Portions de lignes", "Links": "Liens", "List mode": "Vue en liste", @@ -491,6 +493,7 @@ "Open fields to deeply explain the event circumstances.": "Champs libres pour raconter au mieux les circonstances de l'évènement.", "Open fields to detail the picture's context": "Champs libre pour décrire le contexte de l'image", "Open in a new tab": "Ouvrir dans un nouvel onglet", + "Operator" : "Opérateur", "Ordered list": "Liste triée", "Ordnance Survey (uk)": { "Map layer": "Ordn. Survey" @@ -542,6 +545,7 @@ "Protection areas": "Zones de protection", "Protection status": "Status de la protection", "Provide information and improve its quality, following the contribution rules and respecting copyright.": "Vous êtes invité à compléter les informations et améliorer la qualité du document en suivant les règles de contribution et dans le respect du droit d'auteur.", + "Public transport stops nearby (less than 5km)" : "Arrêts de transports en commun à proximité (à moins de 5km)", "Put it back": "Remettre", "Quote": "Citation", "ROMMA station": "Station ROMMA", @@ -629,6 +633,7 @@ "Statistical cookies": "Cookies statistiques", "Statistics": "Statistiques", "Stay careful while skiing": "Skier avec prudence", + "Stop" : "Arrêt", "Stop following this contributor": "Ne plus suivre ce contributeur", "Subcription revokal failed": "La souscription au service n'a pu être révoquée.", "Subcription revoked": "Souscription supprimée", diff --git a/src/views/document/RouteView.vue b/src/views/document/RouteView.vue index 1615cf927..692c88538 100644 --- a/src/views/document/RouteView.vue +++ b/src/views/document/RouteView.vue @@ -123,8 +123,6 @@
- - diff --git a/src/views/document/WaypointView.vue b/src/views/document/WaypointView.vue index a87c4f0e8..f896dce2a 100644 --- a/src/views/document/WaypointView.vue +++ b/src/views/document/WaypointView.vue @@ -130,6 +130,8 @@
+ + diff --git a/src/views/document/utils/boxes/TransportsBox.vue b/src/views/document/utils/boxes/TransportsBox.vue index fa3c8dc9e..a7b6bbab3 100644 --- a/src/views/document/utils/boxes/TransportsBox.vue +++ b/src/views/document/utils/boxes/TransportsBox.vue @@ -8,11 +8,31 @@ {{ $gettext('Show nearby stops') }}
-
+
+

+ {{ $gettext('Public transport stops nearby (less than 5km)') }} +

+
+
+ {{ $gettext('Stop') }} : {{ stop.stop_name }} +
+
+ {{ $gettext('Line') }} : {{ stop.line }} +
+
+ {{ $gettext('Operator') }} : {{ stop.operator }} +
+
+ {{ $gettext('Distance between the stop and the starting point of the topo') }} : + {{ formattedDistance(stop.distance) }} +
+
+
+
({ + ...stop, + distance: stop.distance ?? 0, + })); + + // Créer les documents pour les stops + this.createStopDocuments(); + }) + .catch((error) => { + console.error('Erreur lors de la récupération des données :', error); + }); + }, + methods: { + formattedDistance(distance) { + return `${distance.toFixed(3)} km`; + }, + + // Méthode pour créer les documents des stops + createStopDocuments() { + if (!this.stops || !this.stops.length) return; + + this.stopDocuments = this.stops + .map((stop) => { + try { + // Vérifier que les coordonnées sont disponibles + if (!stop.coordinates || !stop.coordinates.x || !stop.coordinates.y) { + console.warn(`Stop ${stop.id} n'a pas de coordonnées valides:`, stop); + return null; + } + + // Créer un document basé sur le modèle du document principal + const stopDoc = JSON.parse(JSON.stringify(this.document)); + + // Mettre à jour l'ID et le titre + stopDoc.document_id = stop.id; + + if (stopDoc.locales && stopDoc.locales.length > 0) { + stopDoc.locales[0].title = `${stop.stop_name} (${stop.line})`; + } + + // Modifier la géométrie avec les coordonnées du stop + if (stopDoc.geometry) { + const geom = { + type: 'Point', + coordinates: [stop.coordinates.x, stop.coordinates.y], + }; + stopDoc.geometry.geom = JSON.stringify(geom); + } + + // Ajouter des propriétés spécifiques aux stops pour différencier l'affichage si nécessaire + stopDoc.isStopPoint = true; + stopDoc.stopInfo = { + operator: stop.operator, + line: stop.line, + distance: stop.distance, + }; + + return stopDoc; + } catch (error) { + console.error(`Erreur lors de la création du document pour le stop ${stop.id}:`, error); + return null; + } + }) + .filter(Boolean); // Filtrer les valeurs null + + console.log('Documents pour les stops créés:', this.stopDocuments); + }, + + // Méthode pour créer une copie du document avec des coordonnées décalées + createTestDocument() { + // Vérifier que document est défini + if (!this.document) { + return null; + } + + try { + // Copie profonde de l'objet document + const test = JSON.parse(JSON.stringify(this.document)); + + // Modifions l'ID pour éviter toute confusion + test.document_id = this.document.document_id + 1; + + // Modifions le titre pour identifier facilement ce point test + if (test.locales && test.locales.length > 0) { + test.locales[0].title = 'Point de test (30m)'; + } + + // Modification des coordonnées - décalage d'environ 30 mètres + if (test.geometry && test.geometry.geom) { + const geom = JSON.parse(test.geometry.geom); + if (geom.coordinates && geom.coordinates.length >= 2) { + // Décalage de 150 mètres vers l'est et le nord + geom.coordinates[0] += 150; + geom.coordinates[1] += 150; + test.geometry.geom = JSON.stringify(geom); + } + } + + return test; + } catch (error) { + console.error('Erreur lors de la création du document test:', error); + return null; + } + }, }, }; @@ -58,11 +252,24 @@ export default { gap: 20px; .public-transports-result { - width: 100%; - height: 400px; - border: 1px solid lightgray; - border-radius: 4px; + margin-top: 20px; + + .stop-card { + border: 2px solid lightgray; + border-radius: 8px; + padding: 15px; + margin-bottom: 10px; + background: white; + + .stop-header { + font-weight: bold; + font-size: 1.1em; + color: #2a2a2a; + margin-bottom: 5px; + } + } } + .public-transports-map { width: 100%; height: 400px; From 355fd215ea5716497e03230d79bb84a667eb6b9a Mon Sep 17 00:00:00 2001 From: "floriane.jandot" Date: Tue, 4 Mar 2025 09:03:21 +0100 Subject: [PATCH 07/21] [new feature] Add card reaction with map --- src/components/map/OlMap.vue | 49 +++++++ src/components/map/map-utils.js | 21 ++- .../document/utils/boxes/TransportsBox.vue | 138 +++++++++--------- 3 files changed, 134 insertions(+), 74 deletions(-) diff --git a/src/components/map/OlMap.vue b/src/components/map/OlMap.vue index a9f9924a7..b5eee0438 100644 --- a/src/components/map/OlMap.vue +++ b/src/components/map/OlMap.vue @@ -1094,6 +1094,10 @@ export default { if (feature) { const document = feature.get('document'); + if (document && document.type === 's') { + this.$emit('stop-clicked', document.document_id); + return; + } if (document) { if (this.documents.length === 1 && document.document_id === this.documents[0].document_id) { return; @@ -1256,6 +1260,51 @@ export default { ); this.editMapLink = `https://www.openstreetmap.org/#map=13/${coords[1]}/${coords[0]}`; }, + + highlightStop(stopId) { + this.resetStopStyles(); + const stopFeature = this.findStopPoint(stopId); + + if (!stopFeature) { + console.warn(`Arrêt avec l'ID ${stopId} non trouvé.`); + return; + } + + const title = stopFeature.get('document').stop_name; + stopFeature.setStyle(getDocumentPointStyle(stopFeature.get('document'), title, true)); + }, + + resetStopStyles() { + const documentsSource = this.documentsLayer.getSource(); + const waypointsSource = this.waypointsLayer.getSource(); + + documentsSource.forEachFeature((feature) => { + feature.setStyle(feature.get('normalStyle')); + }); + + waypointsSource.forEachFeature((feature) => { + feature.setStyle(feature.get('normalStyle')); + }); + }, + + findStopPoint(stopId) { + const documentsSource = this.documentsLayer.getSource(); + const documentFeature = documentsSource.getFeatureById(stopId); + + if (documentFeature) { + return documentFeature; + } + + const waypointsSource = this.waypointsLayer.getSource(); + const waypointFeature = waypointsSource.getFeatureById(stopId); + + if (waypointFeature) { + return waypointFeature; + } + + console.warn(`Arrêt avec l'ID ${stopId} non trouvé.`); + return null; + }, }, }; diff --git a/src/components/map/map-utils.js b/src/components/map/map-utils.js index baa3bb282..b15dc7898 100644 --- a/src/components/map/map-utils.js +++ b/src/components/map/map-utils.js @@ -58,8 +58,13 @@ const buildPointStyle = function (title, svgSrc, color, highlight) { const imgSize = highlight ? 30 : 20; const circleRadius = highlight ? 20 : 15; + if (svgSrc.includes('bus')) { + svgSrc = svgSrc.replace('fill="currentColor"', 'fill="white"'); // Icône blanche + } else { + svgSrc = svgSrc.replace('fill="currentColor"', `fill="${color}"`); + } + svgSrc = svgSrc.replace('
-

+

{{ $gettext('Public transport stops nearby (less than 5km)') }} -

-
-
- {{ $gettext('Stop') }} : {{ stop.stop_name }} -
-
- {{ $gettext('Line') }} : {{ stop.line }} -
-
- {{ $gettext('Operator') }} : {{ stop.operator }} -
-
- {{ $gettext('Distance between the stop and the starting point of the topo') }} : - {{ formattedDistance(stop.distance) }} +

+
+
+
+ {{ $gettext('Stop') }} : {{ stop.stop_name }} +
+
+ {{ $gettext('Line') }} : {{ stop.line }} +
+
+ {{ $gettext('Operator') }} : {{ stop.operator }} +
+
+ {{ $gettext('Distance between the stop and the starting point of the topo') }} : + {{ formattedDistance(stop.distance) }} +
@@ -41,11 +49,13 @@ :show-pin-to-top-button="true" @has-protection-area="$emit('has-protection-area')" @pin-to-top-clicked="togglePinToSide(true)" + @stop-clicked="handleStopClicked" />
+ @@ -250,16 +226,32 @@ export default { margin-top: 20px; display: flex; gap: 20px; + height: 500px; .public-transports-result { - margin-top: 20px; + .public-transports-subtitle { + font-size: 16px; + font-weight: bold; + margin-bottom: 20px; + } + + .stop-cards { + height: 430px; + overflow-y: scroll; + padding-right: 4px; + } .stop-card { border: 2px solid lightgray; - border-radius: 8px; + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; padding: 15px; margin-bottom: 10px; background: white; + border-left: 8px solid #337ab7; + cursor: pointer; .stop-header { font-weight: bold; @@ -267,12 +259,18 @@ export default { color: #2a2a2a; margin-bottom: 5px; } + + &.selected-stop { + border: 2px solid #4baf50; + border-left: 8px solid #4baf50; + background-color: #fbfaf6; + } } } .public-transports-map { - width: 100%; - height: 400px; + height: auto; + width: 800px; border: 1px solid lightgray; border-radius: 4px; } From 63aba4061607b57c35f166f08e835dc97aec54e7 Mon Sep 17 00:00:00 2001 From: "floriane.jandot" Date: Tue, 4 Mar 2025 09:04:19 +0100 Subject: [PATCH 08/21] [new feature] add "is reachable by public transport" box --- src/views/document/WaypointView.vue | 1 + .../IsReachableByPublicTransportsBox.vue | 91 +++++++++++++++++++ .../document/utils/document-view-mixin.js | 2 + 3 files changed, 94 insertions(+) create mode 100644 src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue diff --git a/src/views/document/WaypointView.vue b/src/views/document/WaypointView.vue index f896dce2a..f69342e70 100644 --- a/src/views/document/WaypointView.vue +++ b/src/views/document/WaypointView.vue @@ -17,6 +17,7 @@
+
diff --git a/src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue b/src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue new file mode 100644 index 000000000..8974a23a0 --- /dev/null +++ b/src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue @@ -0,0 +1,91 @@ + + + + + diff --git a/src/views/document/utils/document-view-mixin.js b/src/views/document/utils/document-view-mixin.js index e751e9ead..f8e382bb6 100644 --- a/src/views/document/utils/document-view-mixin.js +++ b/src/views/document/utils/document-view-mixin.js @@ -2,6 +2,7 @@ import DocumentPrintLicense from './DocumentPrintLicense'; import DocumentViewHeader from './DocumentViewHeader'; import CommentsBox from './boxes/CommentsBox'; import ImagesBox from './boxes/ImagesBox'; +import IsReachableByPublicTransportsBox from './boxes/IsReachableByPublicTransportsBox'; import MapBox from './boxes/MapBox'; import RecentOutingsBox from './boxes/RecentOutingsBox'; import RoutesBox from './boxes/RoutesBox'; @@ -34,6 +35,7 @@ export default { LabelValue, ActivitiesField, EventActivityField, + IsReachableByPublicTransportsBox, MapBox, MarkdownSection, ProfilesLinks, From efafb83f9d0f8a7deb7b8b3938ade9c7be0697b0 Mon Sep 17 00:00:00 2001 From: "floriane.jandot" Date: Wed, 5 Mar 2025 10:24:32 +0100 Subject: [PATCH 09/21] [new feature] display multiple stop_point for 1 stop_area, with toggle buttons --- src/assets/img/boxes/toggle_minus.svg | 17 ++ src/assets/img/boxes/toggle_plus.svg | 15 ++ .../document/utils/boxes/TransportsBox.vue | 148 ++++++++++++------ 3 files changed, 134 insertions(+), 46 deletions(-) create mode 100644 src/assets/img/boxes/toggle_minus.svg create mode 100644 src/assets/img/boxes/toggle_plus.svg diff --git a/src/assets/img/boxes/toggle_minus.svg b/src/assets/img/boxes/toggle_minus.svg new file mode 100644 index 000000000..d619a5253 --- /dev/null +++ b/src/assets/img/boxes/toggle_minus.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/boxes/toggle_plus.svg b/src/assets/img/boxes/toggle_plus.svg new file mode 100644 index 000000000..1790edf46 --- /dev/null +++ b/src/assets/img/boxes/toggle_plus.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/views/document/utils/boxes/TransportsBox.vue b/src/views/document/utils/boxes/TransportsBox.vue index 7651f30e7..abe3d3ffd 100644 --- a/src/views/document/utils/boxes/TransportsBox.vue +++ b/src/views/document/utils/boxes/TransportsBox.vue @@ -14,24 +14,38 @@

-
- {{ $gettext('Stop') }} : {{ stop.stop_name }} +
+ {{ $gettext('Stop') }} : {{ stopName }}
-
- {{ $gettext('Line') }} : {{ stop.line }} -
-
- {{ $gettext('Operator') }} : {{ stop.operator }} -
-
- {{ $gettext('Distance between the stop and the starting point of the topo') }} : - {{ formattedDistance(stop.distance) }} +
+
+
+ {{ $gettext('Line') }} : {{ stop.line }} + +
+
+
+ {{ $gettext('Operator') }} : {{ stop.operator }} +
+
+ {{ $gettext('Distance between the stop and the starting point of the topo') }} : + {{ formattedDistance(stop.distance) }} +
+
+
@@ -72,9 +86,20 @@ export default { elevationProfileHasData: false, testDocument: null, selectedStop: null, + selectedStopGroup: null, + expandedLines: {}, }; }, computed: { + groupedStops() { + return this.stops.reduce((acc, stop) => { + if (!acc[stop.stop_name]) { + acc[stop.stop_name] = []; + } + acc[stop.stop_name].push(stop); + return acc; + }, {}); + }, mapDocuments() { if (!this.document) { return []; @@ -91,11 +116,6 @@ export default { }, watch: { document: { - handler(newVal) { - if (newVal) { - this.testDocument = this.createTestDocument(); - } - }, deep: true, }, stops: { @@ -108,6 +128,7 @@ export default { }, }, mounted() { + console.log('Document reçu dans transports-box :', this.document); if (!this.document || !this.document.document_id) { console.warn('Aucun document ou ID trouvé !'); return; @@ -171,32 +192,9 @@ export default { }) .filter(Boolean); }, - createTestDocument() { - if (!this.document) { - return null; - } - try { - const test = JSON.parse(JSON.stringify(this.document)); - test.document_id = this.document.document_id + 1; - if (test.locales && test.locales.length > 0) { - test.locales[0].title = 'Point de test (30m)'; - } - if (test.geometry && test.geometry.geom) { - const geom = JSON.parse(test.geometry.geom); - if (geom.coordinates && geom.coordinates.length >= 2) { - geom.coordinates[0] += 150; - geom.coordinates[1] += 150; - test.geometry.geom = JSON.stringify(geom); - } - } - return test; - } catch (error) { - console.error('Erreur lors de la création du document test:', error); - return null; - } - }, - selectStop(stop) { - this.selectedStop = stop; + selectStopGroup(stopGroup) { + this.selectedStopGroup = stopGroup; + this.selectedStop = stopGroup[0]; // Default to the first stop in the group this.updateMap(); }, updateMap() { @@ -206,6 +204,19 @@ export default { }, handleStopClicked(stopId) { this.selectedStop = this.stops.find((stop) => stop.id === stopId); + // Find and set the selected stop group + this.selectedStopGroup = Object.values(this.groupedStops).find((group) => + group.some((stop) => stop.id === stopId) + ); + }, + isStopGroupSelected(stopGroup) { + return ( + this.selectedStopGroup && + stopGroup.some((stop) => this.selectedStopGroup.some((selectedStop) => selectedStop.id === stop.id)) + ); + }, + toggleLineDetails(lineId) { + this.$set(this.expandedLines, lineId, !this.expandedLines[lineId]); }, }, }; @@ -260,6 +271,51 @@ export default { margin-bottom: 5px; } + .stop-details { + margin-top: 10px; + padding-left: 10px; + border-top: 1px solid #f0f0f0; + + .line-details { + margin-bottom: 10px; + border: 1px solid #e0e0de; + padding: 7px; + border-radius: 4px; + + .line-header { + display: flex; + justify-content: space-between; + align-items: start; + gap: 4px; + + strong { + white-space: nowrap; + } + + .toggle-details-button { + background: none; + border: none; + cursor: pointer; + padding: 0; + margin-left: 5px; + margin-right: 5px; + margin-top: 5px; + + .toggle-icon { + width: 24px; + height: 24px; + } + } + } + + .line-info { + div { + margin-top: 10px; + } + } + } + } + &.selected-stop { border: 2px solid #4baf50; border-left: 8px solid #4baf50; From c4ecf84e7e8a7b8815f4e07301654238fd5d8087 Mon Sep 17 00:00:00 2001 From: "floriane.jandot" Date: Wed, 5 Mar 2025 10:51:30 +0100 Subject: [PATCH 10/21] [new feature] add public transports view on routes --- src/views/document/RouteView.vue | 2 + src/views/document/WaypointView.vue | 2 +- .../document/utils/boxes/TransportsBox.vue | 66 +++++++++++-------- 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/src/views/document/RouteView.vue b/src/views/document/RouteView.vue index 692c88538..cc46277d1 100644 --- a/src/views/document/RouteView.vue +++ b/src/views/document/RouteView.vue @@ -123,6 +123,8 @@
+ + diff --git a/src/views/document/WaypointView.vue b/src/views/document/WaypointView.vue index f69342e70..57c74c36a 100644 --- a/src/views/document/WaypointView.vue +++ b/src/views/document/WaypointView.vue @@ -131,7 +131,7 @@
- + diff --git a/src/views/document/utils/boxes/TransportsBox.vue b/src/views/document/utils/boxes/TransportsBox.vue index abe3d3ffd..bf95efd3c 100644 --- a/src/views/document/utils/boxes/TransportsBox.vue +++ b/src/views/document/utils/boxes/TransportsBox.vue @@ -76,7 +76,7 @@ import { requireDocumentProperty } from '@/js/properties-mixins'; export default { mixins: [requireDocumentProperty], props: { - document: Object, + document: Array, }, data() { return { @@ -101,10 +101,10 @@ export default { }, {}); }, mapDocuments() { - if (!this.document) { + if (!this.document || this.document.length === 0) { return []; } - const documents = [this.document]; + const documents = [...this.document]; // Utilisez tous les documents waypoints if (this.testDocument) { documents.push(this.testDocument); } @@ -116,7 +116,13 @@ export default { }, watch: { document: { + handler(newVal) { + if (newVal && newVal.length > 0) { + this.fetchStopsForDocuments(newVal); + } + }, deep: true, + immediate: true, // Déclenche le handler au montage }, stops: { handler(newStops) { @@ -127,32 +133,38 @@ export default { deep: true, }, }, - mounted() { - console.log('Document reçu dans transports-box :', this.document); - if (!this.document || !this.document.document_id) { - console.warn('Aucun document ou ID trouvé !'); - return; - } - const waypointUrl = `http://localhost:6543/waypoints/${this.document.document_id}/stops`; - fetch(waypointUrl) - .then((response) => { - if (!response.ok) { - throw new Error(`Erreur HTTP: ${response.status}`); + methods: { + fetchStopsForDocuments(documents) { + this.stops = []; // Réinitialise les stops avant de les remplir + const fetchPromises = documents.map((doc) => { + if (!doc || !doc.document_id) { + console.warn('Document invalide ou ID manquant :', doc); + return Promise.resolve(); } - return response.json(); - }) - .then((data) => { - this.stops = data.stops.map((stop) => ({ - ...stop, - distance: stop.distance ?? 0, - })); + const waypointUrl = `http://localhost:6543/waypoints/${doc.document_id}/stops`; + return fetch(waypointUrl) + .then((response) => { + if (!response.ok) { + throw new Error(`Erreur HTTP: ${response.status}`); + } + return response.json(); + }) + .then((data) => { + const stopsForDocument = data.stops.map((stop) => ({ + ...stop, + distance: stop.distance ?? 0, + })); + this.stops = this.stops.concat(stopsForDocument); // Concatène les stops + }) + .catch((error) => { + console.error('Erreur lors de la récupération des données :', error); + }); + }); + + Promise.all(fetchPromises).then(() => { this.createStopDocuments(); - }) - .catch((error) => { - console.error('Erreur lors de la récupération des données :', error); }); - }, - methods: { + }, formattedDistance(distance) { return `${distance.toFixed(3).replace('.', ',')} km`; }, @@ -165,7 +177,7 @@ export default { console.warn(`Stop ${stop.id} n'a pas de coordonnées valides:`, stop); return null; } - const stopDoc = JSON.parse(JSON.stringify(this.document)); + const stopDoc = JSON.parse(JSON.stringify(this.document[0])); // Utilise le premier document comme modèle stopDoc.document_id = stop.id; stopDoc.type = 's'; if (stopDoc.locales && stopDoc.locales.length > 0) { From c34be83b3ffe6270874ffd6d052d3c30579cda5d Mon Sep 17 00:00:00 2001 From: "floriane.jandot" Date: Thu, 6 Mar 2025 15:44:54 +0100 Subject: [PATCH 11/21] [new feature] add no public transport result --- src/translations/fr.json | 5 +++ src/views/document/RouteView.vue | 2 + .../document/utils/boxes/TransportsBox.vue | 39 ++++++++++++++++--- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/translations/fr.json b/src/translations/fr.json index 1e66690bd..f15b8a8f1 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -12,6 +12,7 @@ "4": { "paragliding_ratings": "P4" }, + "(less than 5km from one of the topo access points)" : "(à moins de 5km depuis l'un des points d'accès du topo)", "(MRD), you do not have to enter any parameters other than the danger level(s) given by the avalanche bulletin.": "(MRD), vous n’avez pas d’autres paramètres à entrer que le (ou les) niveau(x) de danger donné(s) par le bulletin d'avalanche.", "(MRE), you can enter the sectors of the compass rose that are reported as critical in the avalanche bulletin.": "(MRE), vous pouvez saisir les secteurs de la rose des vents signalés comme critique dans le bulletin d'avalanche.", "(MRP), you can refine the hazard potential, set group size and any precautionary measures being considered.": "(MRP), vous pouvez affiner le potentiel de danger, tenir compte de la taille du groupe et des mesures de précaution envisagées.", @@ -73,6 +74,7 @@ "Associated routes cotations": "Cotations des itinéraires associés au point de passage", "Association": "Camptocamp Association", "Associations history": "Historique des associations", + "At least one access point in the topo does not have a public transport stop within 5km.": "Au moins un point d'accès du topo ne dispose pas d'arrêt de transport en commun à moins de 5km.", "Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made.": "Attribution — Vous devez créditer l'Œuvre, intégrer un lien vers la licence et indiquer si des modifications ont été effectuées à l'Oeuvre. ", "Avalanche bulletins": "Bulletins d'avalanche", "Avalanche risk": "Risque d'avalanche", @@ -673,6 +675,7 @@ "This is where you may describe the route extensively, maybe starting with a brief summary and then developing the description (including approach, descent, etc.). Don't forget to mention the route history if you know it.": "Description complète de l'itinéraire (résumé, approche, descente, etc.) N'oubliez pas l'historique si vous le connaissez.", "This picture depicts a book cover. It is the property of its editor and/or author. It is presented here only for illustration purposes.": "Cette image montre une couverture de livre. Elle est la propriété de l'éditeur et/ou de l'auteur et n'est présentée ici qu'à des fins d'illustration.", "This profile is only available to authenticated users.": "Ce profil est accessible aux seuls utilisateurs authentifiés.", + "This route is partially accessible by public transport.": "Ce topo est partiellement accessible en transport en commun.", "This tool estimates the technical difficulty of a ski route (ski rating).": "Cet outil permet d'estimer la difficulté technique d'un itinéraire à ski (cotation ski)", "This version has been masked.": "Cette version a été masquée.", "Time": "Heure", @@ -696,6 +699,7 @@ "Unblock account": "Débloquer cet utilisateur", "Unfold section": "Déplier la section", "Unformatted text": "Texte brut", + "Unfortunately, this guide does not appear to be served by a public transport service": "Malheureusement, ce topoguide ne semble pas être desservi par un service de transport en commun", "Unmark this route as to do": "Enlever cet itinéraire de ses favoris", "Unordered list": "Liste non triée", "Unprotect document": "Déprotéger ce document", @@ -726,6 +730,7 @@ "Warning: This action cannot be undone!": "Attention : cette action est irréversible !", "Waypoint's main properties": "Principales données du point de passage", "Waypoint's textual description": "Descriptions textuelles du point de passage", + "We did not find any public transport stop near the topo route": "Nous n'avons pas trouvé d'arrêts de transport en commun à proximité de l'itinéraire du topo", "We sent you an email, please click on the link to reset password.": "Vous allez bientôt recevoir un email. Veuillez cliquer sur le lien qu'il contient pour réinitialiser votre mot de passe.", "Weather & conditions": "Météo & conditions", "Weather forecast (meteoblue)": "Prévisions météo (meteoblue)", diff --git a/src/views/document/RouteView.vue b/src/views/document/RouteView.vue index cc46277d1..cea1d8ee7 100644 --- a/src/views/document/RouteView.vue +++ b/src/views/document/RouteView.vue @@ -11,6 +11,8 @@
+ +
diff --git a/src/views/document/utils/boxes/TransportsBox.vue b/src/views/document/utils/boxes/TransportsBox.vue index bf95efd3c..1aa704fc1 100644 --- a/src/views/document/utils/boxes/TransportsBox.vue +++ b/src/views/document/utils/boxes/TransportsBox.vue @@ -7,7 +7,7 @@ {{ $gettext('Show nearby stops') }} -
+

{{ $gettext('Public transport stops nearby (less than 5km)') }} @@ -67,6 +67,17 @@ />

+ +
+ +
+ {{ + $gettext('Unfortunately, this guide does not appear to be served by a public transport service') + }} +

{{ $gettext('We did not find any public transport stop near the topo route') }}

+

{{ $gettext('(less than 5km from one of the topo access points)') }}

+
+
@@ -88,6 +99,7 @@ export default { selectedStop: null, selectedStopGroup: null, expandedLines: {}, + showAccessibilityInfo: false, }; }, computed: { @@ -104,10 +116,7 @@ export default { if (!this.document || this.document.length === 0) { return []; } - const documents = [...this.document]; // Utilisez tous les documents waypoints - if (this.testDocument) { - documents.push(this.testDocument); - } + const documents = [...this.document]; if (this.stopDocuments && this.stopDocuments.length > 0) { documents.push(...this.stopDocuments); } @@ -122,7 +131,7 @@ export default { } }, deep: true, - immediate: true, // Déclenche le handler au montage + immediate: true, }, stops: { handler(newStops) { @@ -150,6 +159,7 @@ export default { return response.json(); }) .then((data) => { + this.showAccessibilityInfo = data.stops.length > 0; const stopsForDocument = data.stops.map((stop) => ({ ...stop, distance: stop.distance ?? 0, @@ -343,5 +353,22 @@ export default { border-radius: 4px; } } + .public-transport-no-result { + display: flex; + padding: 20px; + border: 1px solid lightgray; + border-radius: 4px; + margin-top: 20px; + gap: 30px; + align-items: center; + + .public-transports-no-result-bus { + width: 100px; + height: 100px; + } + + .public-transport-no-result-text { + } + } } From f6f9db90ced183ea7f85d988491349fef103814a Mon Sep 17 00:00:00 2001 From: "floriane.jandot" Date: Thu, 6 Mar 2025 16:37:03 +0100 Subject: [PATCH 12/21] [new feature] add partial result case for many waypoints --- .../document/utils/boxes/TransportsBox.vue | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/views/document/utils/boxes/TransportsBox.vue b/src/views/document/utils/boxes/TransportsBox.vue index 1aa704fc1..5f83417ce 100644 --- a/src/views/document/utils/boxes/TransportsBox.vue +++ b/src/views/document/utils/boxes/TransportsBox.vue @@ -49,6 +49,15 @@
+
+

!

+
+ {{ $gettext('This route is partially accessible by public transport.') }} +

+ {{ $gettext('At least one access point in the topo does not have a public transport stop within 5km.') }} +

+
+
@@ -68,7 +77,7 @@
-
+
{{ @@ -100,6 +109,7 @@ export default { selectedStopGroup: null, expandedLines: {}, showAccessibilityInfo: false, + missingTransportForWaypoint: false, }; }, computed: { @@ -145,11 +155,17 @@ export default { methods: { fetchStopsForDocuments(documents) { this.stops = []; // Réinitialise les stops avant de les remplir + const documentResults = {}; + const fetchPromises = documents.map((doc) => { if (!doc || !doc.document_id) { console.warn('Document invalide ou ID manquant :', doc); return Promise.resolve(); } + + // Initialiser le résultat pour ce document comme n'ayant pas de transport + documentResults[doc.document_id] = false; + const waypointUrl = `http://localhost:6543/waypoints/${doc.document_id}/stops`; return fetch(waypointUrl) .then((response) => { @@ -160,6 +176,9 @@ export default { }) .then((data) => { this.showAccessibilityInfo = data.stops.length > 0; + // Marquer ce document comme ayant des transports si des arrêts sont trouvés + documentResults[doc.document_id] = data.stops.length > 0; + const stopsForDocument = data.stops.map((stop) => ({ ...stop, distance: stop.distance ?? 0, @@ -168,10 +187,14 @@ export default { }) .catch((error) => { console.error('Erreur lors de la récupération des données :', error); + // En cas d'erreur, on considère que le document n'a pas de transport + documentResults[doc.document_id] = false; }); }); Promise.all(fetchPromises).then(() => { + // Vérifier si au moins un document n'a pas de transport + this.missingTransportForWaypoint = Object.values(documentResults).some((hasTransport) => !hasTransport); this.createStopDocuments(); }); }, @@ -262,6 +285,9 @@ export default { height: 500px; .public-transports-result { + display: flex; + flex-direction: column; + height: 100%; .public-transports-subtitle { font-size: 16px; font-weight: bold; @@ -269,7 +295,7 @@ export default { } .stop-cards { - height: 430px; + height: inherit; overflow-y: scroll; padding-right: 4px; } @@ -344,6 +370,31 @@ export default { background-color: #fbfaf6; } } + + .missing-transports-warning { + display: flex; + padding: 10px; + border: 1px solid #ffa74f; + border-radius: 4px; + margin-top: 25px; + gap: 10px; + align-items: center; + background-color: #fec184; + .missing-transports-warning-exclamation { + height: 26px; + width: 26px; + background-color: #ff4d09; + border-radius: 14px; + color: #fec184; + font-weight: bold; + text-align: center; + flex: none; + font-size: 18px; + } + + .missing-transports-warning-text { + } + } } .public-transports-map { From de720c5421ecee103d81dea70ac072e8a406748a Mon Sep 17 00:00:00 2001 From: "floriane.jandot" Date: Fri, 7 Mar 2025 11:19:35 +0100 Subject: [PATCH 13/21] [new features] rename table, visuals corrections, map hover fixed, add transportService --- src/assets/img/boxes/public_transport.svg | 3 + src/assets/img/boxes/public_transports.png | Bin 7782 -> 0 bytes src/assets/img/boxes/transport_not_found.svg | 44 ++++ src/components/map/OlMap.vue | 11 +- src/components/map/map-utils.js | 2 +- src/js/apis/transport-service.js | 83 ++++++++ src/translations/fr.json | 3 +- src/views/document/RouteView.vue | 2 +- .../IsReachableByPublicTransportsBox.vue | 180 ++++++++++++----- .../document/utils/boxes/TransportsBox.vue | 189 +++++++++++------- 10 files changed, 379 insertions(+), 138 deletions(-) create mode 100644 src/assets/img/boxes/public_transport.svg delete mode 100644 src/assets/img/boxes/public_transports.png create mode 100644 src/assets/img/boxes/transport_not_found.svg create mode 100644 src/js/apis/transport-service.js diff --git a/src/assets/img/boxes/public_transport.svg b/src/assets/img/boxes/public_transport.svg new file mode 100644 index 000000000..fc5b32ff4 --- /dev/null +++ b/src/assets/img/boxes/public_transport.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/boxes/public_transports.png b/src/assets/img/boxes/public_transports.png deleted file mode 100644 index a8ab729082d20c16736a653ed3529032c483e2ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7782 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/map/OlMap.vue b/src/components/map/OlMap.vue index b5eee0438..5929f26b3 100644 --- a/src/components/map/OlMap.vue +++ b/src/components/map/OlMap.vue @@ -1266,11 +1266,11 @@ export default { const stopFeature = this.findStopPoint(stopId); if (!stopFeature) { - console.warn(`Arrêt avec l'ID ${stopId} non trouvé.`); + console.warn(`Stop with ID ${stopId} not found.`); return; } - const title = stopFeature.get('document').stop_name; + const title = stopFeature.get('document').stoparea_name; stopFeature.setStyle(getDocumentPointStyle(stopFeature.get('document'), title, true)); }, @@ -1279,10 +1279,13 @@ export default { const waypointsSource = this.waypointsLayer.getSource(); documentsSource.forEachFeature((feature) => { - feature.setStyle(feature.get('normalStyle')); + if (feature.values_.document.type !== 'w') { + feature.setStyle(feature.get('normalStyle')); + } }); waypointsSource.forEachFeature((feature) => { + console.log(feature); feature.setStyle(feature.get('normalStyle')); }); }, @@ -1302,7 +1305,7 @@ export default { return waypointFeature; } - console.warn(`Arrêt avec l'ID ${stopId} non trouvé.`); + console.warn(`Stop with ID ${stopId} not found.`); return null; }, }, diff --git a/src/components/map/map-utils.js b/src/components/map/map-utils.js index b15dc7898..3c1aacb5c 100644 --- a/src/components/map/map-utils.js +++ b/src/components/map/map-utils.js @@ -59,7 +59,7 @@ const buildPointStyle = function (title, svgSrc, color, highlight) { const circleRadius = highlight ? 20 : 15; if (svgSrc.includes('bus')) { - svgSrc = svgSrc.replace('fill="currentColor"', 'fill="white"'); // Icône blanche + svgSrc = svgSrc.replace('fill="currentColor"', 'fill="white"'); } else { svgSrc = svgSrc.replace('fill="currentColor"', `fill="${color}"`); } diff --git a/src/js/apis/transport-service.js b/src/js/apis/transport-service.js new file mode 100644 index 000000000..a1f47da58 --- /dev/null +++ b/src/js/apis/transport-service.js @@ -0,0 +1,83 @@ +import axios from 'axios'; +import config from '@/js/config'; + +function TransportService() { + this.axios = axios.create({ + baseURL: config.urls.api, + }); +} + +/** + * Récupère les arrêts de transport en commun pour un waypoint donné + * + * @param {string | number} waypointId - L'identifiant du waypoint + * @returns {Promise} Promesse contenant les données des arrêts + */ +TransportService.prototype.getStopareas = function (waypointId) { + return this.axios.get(`/waypoints/${waypointId}/stopareas`); +}; + +/** + * Vérifie si un waypoint est accessible en transport en commun + * + * @param {string | number} waypointId - L'identifiant du waypoint + * @returns {Promise} Promesse contenant un booléen indiquant l'accessibilité + */ +TransportService.prototype.isReachable = function (waypointId) { + return this.axios.get(`/waypoints/${waypointId}/isReachable`).then((response) => response.data); +}; + +/** + * Récupère les arrêts pour plusieurs waypoints et détermine si tous sont accessibles + * + * @param {Array} documents - Tableau de documents (waypoints) + * @returns {Promise} Promesse contenant les résultats et les données d'accessibilité + */ +TransportService.prototype.getStopareasForDocuments = function (documents) { + if (!documents || documents.length === 0) { + return Promise.resolve({ stopareas: [], missingTransportForWaypoint: false }); + } + + const documentResults = {}; + const allStopareas = []; + + const fetchPromises = documents.map((doc) => { + if (!doc || !doc.document_id) { + console.warn('Document invalide ou ID manquant :', doc); + return Promise.resolve(); + } + + documentResults[doc.document_id] = false; + + return this.getStopareas(doc.document_id) + .then((response) => { + const data = response.data; + const hasStopareas = data.stopareas && data.stopareas.length > 0; + + documentResults[doc.document_id] = hasStopareas; + + if (hasStopareas) { + const stopareasForDocument = data.stopareas.map((stoparea) => ({ + ...stoparea, + distance: stoparea.distance ?? 0, + })); + allStopareas.push(...stopareasForDocument); + } + }) + .catch((error) => { + console.error(`Erreur lors de la récupération des arrêts pour le document ${doc.document_id}:`, error); + documentResults[doc.document_id] = false; + }); + }); + + return Promise.all(fetchPromises).then(() => { + const missingTransportForWaypoint = Object.values(documentResults).some((hasTransport) => !hasTransport); + return { + stopareas: allStopareas, + missingTransportForWaypoint, + documentResults, + }; + }); +}; + +export default new TransportService(); diff --git a/src/translations/fr.json b/src/translations/fr.json index f15b8a8f1..35d967ac6 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -81,6 +81,7 @@ "Avalanche risk evaluation tool:": "Une aide à la gestion du risque d’avalanche :", "Average slope (degrees)": "Pente moyenne (degrés)", "Average slope in degree": "Pente moyenne en degrés", + "Away":"à ", "Back to code": "Retour au code", "Back to edit mode": "Retour en mode édition", "Back to the top": "Haut de page", @@ -217,7 +218,6 @@ "Directions (Google Maps)": "Se rendre à ce lieu (Google Maps)", "Disabled at this zoom level": "Désactivé à ce niveau de zoom", "Disclaimer": "Avertissement", - "Distance between the stop and the starting point of the topo" : "Distance entre l'arrêt et le point de départ du topo", "Do you really want to leave? you have unsaved changes!": "Voulez-vous vraiment quitter cette page ? Des changements n'ont pas été sauvegardés !", "Document quality": "Qualité du document", "Donate": "Faire un don à l'association Camptocamp", @@ -370,6 +370,7 @@ "Issue report": "Signalement d'un problème", "Join us": "Adhérer", "Know more about SERAC": "En savoir plus sur SERAC", + "km from the access point": "km du point d'accès", "Large group = 5 people and more": "Grand groupe = 5 personnes et plus", "Large group with load shedding distance": "Grand groupe avec distance de délestage", "Last activities": "Dernières activités", diff --git a/src/views/document/RouteView.vue b/src/views/document/RouteView.vue index cea1d8ee7..c53284bee 100644 --- a/src/views/document/RouteView.vue +++ b/src/views/document/RouteView.vue @@ -11,7 +11,7 @@
- +
diff --git a/src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue b/src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue index 8974a23a0..e3e819ca9 100644 --- a/src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue +++ b/src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue @@ -1,10 +1,10 @@