Skip to content

Smart origin/lot1#4357

Closed
brunobesson wants to merge 25 commits into
masterfrom
smart-origin/lot1
Closed

Smart origin/lot1#4357
brunobesson wants to merge 25 commits into
masterfrom
smart-origin/lot1

Conversation

@brunobesson
Copy link
Copy Markdown
Member

@brunobesson brunobesson commented Jul 17, 2025

Summary by CodeRabbit

  • New Features

    • Added public transport accessibility information and nearby stop details to route and waypoint views, including map highlighting and stop grouping.
    • Introduced new UI components to display whether a location is reachable by public transport and to show detailed transport stop information.
    • Enhanced map interactions to support highlighting and zooming on public transport stops.
  • Improvements

    • Expanded French translations with new entries related to public transport and route access points.
    • Updated API endpoint configurations to support local development and preproduction environments.
  • Bug Fixes

    • Improved map feature handling for public transport stops, including visual highlighting and event management.
  • Chores

    • Integrated Prettier formatting checks into ESLint configuration for consistent code style.
    • Adjusted Nginx configuration for improved compatibility.

lgourdin and others added 25 commits January 24, 2025 12:58
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jul 17, 2025

Hey there and thank you for opening this pull request! 👋🏼

We require pull request titles to follow the Conventional Commits specification and it looks like your proposed title needs to be adjusted.

Details:

No release type found in pull request title "Smart origin/lot1". Add a prefix to indicate what kind of release this pull request corresponds to. For reference, see https://www.conventionalcommits.org/

Available types:
 - feat
 - fix
 - docs
 - style
 - refactor
 - perf
 - test
 - chore
 - revert
 - i18n

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jul 17, 2025

Walkthrough

This update introduces public transport accessibility features throughout the application. New Vue components display and manage public transport stop information for routes and waypoints, including map integration, highlighting, and proximity warnings. Supporting API services, translation strings, and style adjustments are added. Configuration changes set new API endpoints and local development defaults.

Changes

File(s) Change Summary
.eslintrc.json Added Prettier integration as an ESLint rule for end-of-line normalization.
docker/nginx.conf Disabled proxy_protocol in the listen directive; original line commented out.
src/components/map/OlMap.vue Added methods for highlighting, zooming, and resetting styles for stop features; updated click handling for stop types.
src/components/map/map-utils.js Enhanced point style logic for new stop types ('s', 'z'); adjusted SVG and color handling; added custom style logic for 'z'.
src/js/apis/transport-service.js Introduced TransportService class with methods to fetch stop areas and check public transport reachability for waypoints.
src/translations/fr.json Added French translations for new public transport and access point UI/UX elements.
src/views/document/RouteView.vue, src/views/document/WaypointView.vue Added <is-reachable-by-public-transports-box> and <transports-box> components to route and waypoint views.
src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue New component to display if a location is reachable by public transport, querying API for each access waypoint.
src/views/document/utils/boxes/TransportsBox.vue New component to display and interact with public transport stops near access points, including map and UI state management.
src/views/document/utils/document-view-mixin.js Registered new transport-related box components for use in document views.
vue.config.js Changed API endpoints to preproduction; added localhost config; set localhost as default.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant RouteView/WaypointView
    participant IsReachableByPublicTransportsBox
    participant TransportsBox
    participant TransportService
    participant Map (OlMap.vue)

    User->>RouteView/WaypointView: Load document view
    RouteView/WaypointView->>IsReachableByPublicTransportsBox: Pass waypoints as prop
    IsReachableByPublicTransportsBox->>TransportService: isReachable(waypointId)
    TransportService-->>IsReachableByPublicTransportsBox: Reachability result
    IsReachableByPublicTransportsBox-->>User: Show/hide accessibility info

    RouteView/WaypointView->>TransportsBox: Pass waypoints as prop
    TransportsBox->>TransportService: getStopareasForDocuments(documents)
    TransportService-->>TransportsBox: Stop areas data
    TransportsBox-->>User: Show stops, warnings, details

    User->>TransportsBox: Select stop/stop group
    TransportsBox->>Map (OlMap.vue): highlightStop(stopId), goAndZoomOnStop(stopId)
    Map (OlMap.vue)-->>TransportsBox: Event feedback (stop-clicked)
Loading

Poem

In burrows deep and valleys wide,
The rabbit found a transit guide.
With stops and maps and boxes new,
Now journeys start with clearer view!
From code to route, the changes hop—
Public transport, just a stop!
🐇🚍

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm warn EBADENGINE Unsupported engine {
npm warn EBADENGINE package: '@achrinza/node-ipc@9.2.6',
npm warn EBADENGINE required: {
npm warn EBADENGINE node: '8 || 9 || 10 || 11 || 12 || 13 || 14 || 15 || 16 || 17 || 18 || 19'
npm warn EBADENGINE },
npm warn EBADENGINE current: { node: 'v24.3.0', npm: '11.4.2' }
npm warn EBADENGINE }
npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-07-17T20_06_30_045Z-debug-0.log

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🧹 Nitpick comments (6)
src/components/map/map-utils.js (1)

62-66: Consider extracting SVG fill logic for better readability

The conditional SVG fill replacement could be simplified.

-  if (svgSrc.includes('bus')) {
-    svgSrc = svgSrc.replace('fill="currentColor"', 'fill="white"');
-  } else {
-    svgSrc = svgSrc.replace('fill="currentColor"', `fill="${color}"`);
-  }
+  const fillColor = svgSrc.includes('bus') ? 'white' : color;
+  svgSrc = svgSrc.replace('fill="currentColor"', `fill="${fillColor}"`);
src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue (1)

42-50: Consider performance impact of deep watcher

The deep watcher on the document prop could cause performance issues if the document object is large and changes frequently.

Consider watching only the specific properties you need:

-  watch: {
-    document: {
-      handler() {
-        this.checkAccessibility();
-      },
-      deep: true,
-      immediate: true,
-    },
-  },
+  watch: {
+    accessWaypoints: {
+      handler() {
+        this.checkAccessibility();
+      },
+      immediate: true,
+    },
+  },
src/components/map/OlMap.vue (1)

1067-1067: Remove unnecessary comment markers

The comment /////////// doesn't provide any value and should be removed.

-      this.setHighlightedFeature(resultFeature); ///////////
+      this.setHighlightedFeature(resultFeature);
src/js/apis/transport-service.js (2)

5-10: Consider using ES6 class syntax for better readability

The service uses constructor function pattern. Consider modernizing to ES6 class syntax for improved readability and consistency with modern JavaScript practices.

-function TransportService() {
-  this.axios = axios.create({
-    baseURL: config.urls.api,
-  });
-}
+class TransportService {
+  constructor() {
+    this.axios = axios.create({
+      baseURL: config.urls.api,
+    });
+  }
+}

17-29: Add input validation for waypointId parameter

The methods accept waypointId without validation. Consider adding checks to ensure the parameter is valid before making API calls.

 TransportService.prototype.getStopareas = function (waypointId) {
+  if (!waypointId) {
+    return Promise.reject(new Error('waypointId is required'));
+  }
   return this.axios.get(`/waypoints/${waypointId}/stopareas`);
 };
src/views/document/utils/boxes/TransportsBox.vue (1)

495-497: Remove empty CSS class definitions

There are empty class definitions that serve no purpose and should be removed.

-        .missing-transports-warning-text {
-        }
       }
-    .public-transport-no-result-text {
-    }
   }

Also applies to: 522-524

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6dea8da and c0a6c29.

⛔ Files ignored due to path filters (4)
  • src/assets/img/boxes/public_transport.svg is excluded by !**/*.svg
  • src/assets/img/boxes/toggle_minus.svg is excluded by !**/*.svg
  • src/assets/img/boxes/toggle_plus.svg is excluded by !**/*.svg
  • src/assets/img/boxes/transport_not_found.svg is excluded by !**/*.svg
📒 Files selected for processing (12)
  • .eslintrc.json (1 hunks)
  • docker/nginx.conf (1 hunks)
  • src/components/map/OlMap.vue (3 hunks)
  • src/components/map/map-utils.js (4 hunks)
  • src/js/apis/transport-service.js (1 hunks)
  • src/translations/fr.json (16 hunks)
  • src/views/document/RouteView.vue (2 hunks)
  • src/views/document/WaypointView.vue (1 hunks)
  • src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue (1 hunks)
  • src/views/document/utils/boxes/TransportsBox.vue (1 hunks)
  • src/views/document/utils/document-view-mixin.js (2 hunks)
  • vue.config.js (3 hunks)
🔇 Additional comments (16)
docker/nginx.conf (1)

2-3: Verify the impact of removing proxy_protocol support.

The change removes proxy_protocol from the listen directive while keeping the original as a comment. This modification could affect how nginx handles connections from upstream proxies or load balancers that expect PROXY protocol support.

Please confirm this change is intentional and won't break existing proxy configurations in production environments.

.eslintrc.json (1)

14-14: Good addition for cross-platform compatibility.

The prettier/prettier rule with "endOfLine": "auto" is a solid choice for handling line ending differences across different operating systems. This will help maintain consistent formatting while avoiding issues in mixed development environments.

vue.config.js (2)

95-95: Verify the API endpoint change for demo environment.

The demo environment API URL has been changed to the preprod URL. Please confirm this change is intentional and won't break demo environment functionality.


149-149: Default configuration changed from prod to localhost.

The default configuration has been changed from production to localhost. This change could affect production builds if the BUILD_ENV is not properly set.

Please verify that production builds will set the appropriate BUILD_ENV to override this default.

src/views/document/WaypointView.vue (1)

132-132: Good integration of the transports-box component.

The component is properly positioned and the document prop is correctly passed. The array wrapping ([document]) suggests the TransportsBox component is designed to handle multiple documents, which is consistent with its usage pattern.

src/views/document/utils/document-view-mixin.js (4)

5-5: Proper import of IsReachableByPublicTransportsBox component.

The import is correctly placed in alphabetical order with other component imports.


10-10: Proper import of TransportsBox component.

The import is correctly placed in alphabetical order with other component imports.


38-38: Good component registration for IsReachableByPublicTransportsBox.

The component is properly registered in the components object, enabling its use in views that use this mixin.


46-46: Good component registration for TransportsBox.

The component is properly registered in the components object, enabling its use in views that use this mixin.

src/translations/fr.json (1)

15-15: Translation entries look good!

All new French translations for public transport features are properly formatted and grammatically correct.

Also applies to: 37-38, 78-78, 221-221, 310-310, 375-375, 394-394, 501-501, 530-530, 554-554, 594-594, 622-622, 643-643, 686-686, 710-710, 741-741

src/components/map/OlMap.vue (4)

1266-1277: LGTM!

The highlightStop method correctly resets styles and highlights the specified stop feature.


1279-1299: LGTM!

The goAndZoomOnStop method properly handles map animation with appropriate zoom level and animation cancellation.


1316-1333: LGTM!

The findStopPoint method properly searches both document and waypoint layers with appropriate error handling.


1096-1102: Add defensive null checks for document access

The code accesses document.type without verifying that document exists. While feature.get('document') is called at line 1095, it could return null/undefined.

-        if (document && document.type === 'z') {
-          return;
-        }
-        if (document && document.type === 's') {
-          this.$emit('stop-clicked', document.document_id);
-          return;
-        }
+        if (document) {
+          if (document.type === 'z') {
+            return;
+          }
+          if (document.type === 's') {
+            this.$emit('stop-clicked', document.document_id);
+            return;
+          }
+        }

Likely an incorrect or invalid review comment.

src/js/apis/transport-service.js (1)

37-83: Well-implemented method with robust error handling

The getStopareasForDocuments method handles edge cases well and efficiently fetches data in parallel. Good use of defensive programming with the null coalescing operator for the distance field.

Consider adding a comment explaining the purpose of documentResults for better code documentation.

src/views/document/utils/boxes/TransportsBox.vue (1)

307-325: LGTM!

The seeLineDetails method properly handles text selection check and smooth scrolling behavior.

Comment thread vue.config.js
prod: {
name: 'prod',
api: 'https://api.camptocamp.org',
api: 'https://preprod.c2c.preprod0.smart-origin.com/api',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Both demo and prod environments now use the same API endpoint.

Both demo and prod configurations now point to the same preprod URL (https://preprod.c2c.preprod0.smart-origin.com/api). This seems incorrect as they should typically point to different environments.

🤖 Prompt for AI Agents
In vue.config.js at line 117, the API endpoint for both demo and prod
environments is set to the same preprod URL, which is incorrect. Update the prod
environment configuration to use the correct production API endpoint URL instead
of the preprod URL, ensuring demo and prod environments point to their
respective distinct API endpoints.

Comment thread vue.config.js
Comment on lines +137 to +145
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,
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Duplicate localhost configuration detected.

The localhost configuration is defined here and again in the conditional block starting at line 158. This duplication could lead to confusion and maintenance issues.

Consider removing this duplicate configuration and relying on the conditional block below.

🤖 Prompt for AI Agents
In vue.config.js between lines 137 and 145, there is a duplicate localhost
configuration also defined in the conditional block starting at line 158. To fix
this, remove the localhost configuration from lines 137 to 145 and keep only the
one in the conditional block to avoid confusion and simplify maintenance.

<div class="column is-3 no-print">
<map-box :document="document" @has-protection-area="hasProtectionArea = true" />
<avalanche-box :document="document" v-if="!$screen.isMobile" />
<is-reachable-by-public-transports-box :document="document.associations.waypoints" />
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add null safety check for waypoints prop

The component accesses nested properties without checking if they exist. This could cause runtime errors if associations or waypoints are undefined.

Consider adding a computed property or default value:

-<is-reachable-by-public-transports-box :document="document.associations.waypoints" />
+<is-reachable-by-public-transports-box :document="document.associations?.waypoints || []" />

Or handle this in a computed property:

computed: {
  associatedWaypoints() {
    return this.document?.associations?.waypoints || [];
  }
}
🤖 Prompt for AI Agents
In src/views/document/RouteView.vue at line 14, the code passes
document.associations.waypoints directly without checking if associations or
waypoints exist, risking runtime errors. Fix this by adding a computed property
that safely returns document.associations.waypoints or an empty array if
undefined, and then bind this computed property to the
is-reachable-by-public-transports-box component instead of accessing nested
properties directly.

<div style="clear: both" />
</div>

<transports-box :document="document.associations.waypoints" />
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add null safety check for waypoints prop

Same issue as above - accessing nested properties without null checks.

Apply the same defensive programming approach:

-<transports-box :document="document.associations.waypoints" />
+<transports-box :document="document.associations?.waypoints || []" />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<transports-box :document="document.associations.waypoints" />
<transports-box :document="document.associations?.waypoints || []" />
🤖 Prompt for AI Agents
In src/views/document/RouteView.vue at line 128, the code accesses
document.associations.waypoints without checking if document or associations is
null or undefined. Add a null safety check to ensure document and
document.associations exist before accessing waypoints, for example by using
optional chaining or a conditional check, to prevent runtime errors.

Comment on lines +139 to +165
} else if (type === 'z') {
svgSrc = svgSrcByDocumentType['z'] || icon({ prefix: 'waypoint', iconName: 'access' }).html[0];

if (document.public_transportation_rating && document.public_transportation_rating !== 'no service') {
color = '#4baf50';
} else {
color = '#F93';
}

const styles = buildPointStyle(title, svgSrc, color, highlight);

styles.forEach((style) => {
const image = style.getImage();

if (image instanceof ol.style.Circle) {
image.getFill().setColor('rgba(255, 255, 255, 1)');
image.getStroke().setColor('#4baf50');

style.setZIndex(highlight ? 101 : 50);
}

if (image instanceof ol.style.Icon) {
style.setZIndex(highlight ? 102 : 51);
}
});

return styles;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Extract magic numbers as constants and optimize style iteration

The code uses magic numbers for z-index values and iterates through styles inefficiently.

Add constants at the top of the file:

const Z_INDEX = {
  NORMAL: { CIRCLE: 1, ICON: 2 },
  HIGHLIGHT: { CIRCLE: 101, ICON: 102 },
  ACCESS_NORMAL: { CIRCLE: 50, ICON: 51 },
  ACCESS_HIGHLIGHT: { CIRCLE: 101, ICON: 102 }
};

Then refactor the type 'z' logic:

-    const styles = buildPointStyle(title, svgSrc, color, highlight);
-
-    styles.forEach((style) => {
-      const image = style.getImage();
-
-      if (image instanceof ol.style.Circle) {
-        image.getFill().setColor('rgba(255, 255, 255, 1)');
-        image.getStroke().setColor('#4baf50');
-
-        style.setZIndex(highlight ? 101 : 50);
-      }
-
-      if (image instanceof ol.style.Icon) {
-        style.setZIndex(highlight ? 102 : 51);
-      }
-    });
-
-    return styles;
+    const styles = buildPointStyle(title, svgSrc, color, highlight);
+    const [circleStyle, iconStyle] = styles;
+    
+    // Customize circle style
+    const circleImage = circleStyle.getImage();
+    circleImage.getFill().setColor('rgba(255, 255, 255, 1)');
+    circleImage.getStroke().setColor('#4baf50');
+    circleStyle.setZIndex(highlight ? Z_INDEX.ACCESS_HIGHLIGHT.CIRCLE : Z_INDEX.ACCESS_NORMAL.CIRCLE);
+    
+    // Customize icon style
+    iconStyle.setZIndex(highlight ? Z_INDEX.ACCESS_HIGHLIGHT.ICON : Z_INDEX.ACCESS_NORMAL.ICON);
+    
+    return styles;
🤖 Prompt for AI Agents
In src/components/map/map-utils.js between lines 139 and 165, replace all
hardcoded z-index numbers with named constants for clarity and maintainability.
Define a Z_INDEX constant object at the top of the file with properties for
normal and highlight states for both circle and icon styles as suggested. Then
update the style iteration logic to use these constants instead of magic numbers
when calling style.setZIndex, ensuring the correct z-index is applied based on
whether the style is highlighted and the type of image (Circle or Icon).

Comment on lines +94 to +97
console.error(
`Erreur lors de la vérification de l'accessibilité pour le waypoint ${waypointIds[index]} :`,
error
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use i18n for error messages

Error message is hardcoded in French, which breaks internationalization.

-            console.error(
-              `Erreur lors de la vérification de l'accessibilité pour le waypoint ${waypointIds[index]} :`,
-              error
-            );
+            console.error(
+              this.$gettext('Error checking accessibility for waypoint %{id}:', { id: waypointIds[index] }),
+              error
+            );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.error(
`Erreur lors de la vérification de l'accessibilité pour le waypoint ${waypointIds[index]} :`,
error
);
console.error(
this.$gettext('Error checking accessibility for waypoint %{id}:', { id: waypointIds[index] }),
error
);
🤖 Prompt for AI Agents
In src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue around
lines 94 to 97, the error message is hardcoded in French, which breaks
internationalization. Replace the hardcoded French error string with a call to
the i18n translation function, passing the error message key and any dynamic
parameters like waypointIds[index] to ensure the message is localized properly.

Comment on lines +1301 to +1314
resetStopStyles() {
const documentsSource = this.documentsLayer.getSource();
const waypointsSource = this.waypointsLayer.getSource();

documentsSource.forEachFeature((feature) => {
if (feature.values_.document.type !== 'w' && feature.values_.document.type !== 'z') {
feature.setStyle(feature.get('normalStyle'));
}
});

waypointsSource.forEachFeature((feature) => {
feature.setStyle(feature.get('normalStyle'));
});
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid accessing internal properties of OpenLayers features

The code accesses feature.values_.document.type which uses OpenLayers' internal property structure. This is fragile and could break with library updates.

       documentsSource.forEachFeature((feature) => {
-        if (feature.values_.document.type !== 'w' && feature.values_.document.type !== 'z') {
+        const document = feature.get('document');
+        if (document && document.type !== 'w' && document.type !== 'z') {
           feature.setStyle(feature.get('normalStyle'));
         }
       });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
resetStopStyles() {
const documentsSource = this.documentsLayer.getSource();
const waypointsSource = this.waypointsLayer.getSource();
documentsSource.forEachFeature((feature) => {
if (feature.values_.document.type !== 'w' && feature.values_.document.type !== 'z') {
feature.setStyle(feature.get('normalStyle'));
}
});
waypointsSource.forEachFeature((feature) => {
feature.setStyle(feature.get('normalStyle'));
});
},
resetStopStyles() {
const documentsSource = this.documentsLayer.getSource();
const waypointsSource = this.waypointsLayer.getSource();
documentsSource.forEachFeature((feature) => {
+ const document = feature.get('document');
+ if (document && document.type !== 'w' && document.type !== 'z') {
feature.setStyle(feature.get('normalStyle'));
+ }
});
waypointsSource.forEachFeature((feature) => {
feature.setStyle(feature.get('normalStyle'));
});
},
🤖 Prompt for AI Agents
In src/components/map/OlMap.vue around lines 1301 to 1314, the code accesses the
internal property feature.values_.document.type, which is fragile and may break
with OpenLayers updates. To fix this, replace the direct access to values_ with
the official OpenLayers API method feature.get('document') to retrieve the
document object, then check its type property safely. This avoids relying on
internal properties and ensures compatibility with future OpenLayers versions.

Comment on lines +96 to +99
mixins: [requireDocumentProperty],
props: {
document: Array,
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Clarify the document prop type and consider renaming

The document prop is typed as Array which is unusual for a property named "document". This could be confusing for developers. Consider either:

  1. Renaming the prop to better reflect its array nature (e.g., documents or waypoints)
  2. Adding validation or documentation to clarify what this array contains
   props: {
-    document: Array,
+    waypoints: {
+      type: Array,
+      default: () => [],
+      validator: (value) => value.every(item => item && typeof item === 'object')
+    },
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
mixins: [requireDocumentProperty],
props: {
document: Array,
},
mixins: [requireDocumentProperty],
props: {
waypoints: {
type: Array,
default: () => [],
validator: (value) => value.every(item => item && typeof item === 'object')
},
},
🤖 Prompt for AI Agents
In src/views/document/utils/boxes/TransportsBox.vue around lines 96 to 99, the
prop named "document" is typed as an Array, which is misleading given the name.
To fix this, either rename the prop to a plural form like "documents" or
"waypoints" to reflect that it is an array, or keep the name but add detailed
validation or documentation specifying the expected contents and structure of
the array to clarify its purpose.

Comment on lines +194 to +219
fetchStopsForDocuments(documents) {
transportService
.getStopareasForDocuments(documents)
.then((result) => {
documents.forEach((doc) => {
if (!result.documentResults[doc.document_id]) {
doc.public_transportation_rating = 'no service';
} else {
doc.public_transportation_rating = 'service available';
}
});

this.stops = result.stopareas.sort((a, b) => a.distance - b.distance);
this.missingTransportForWaypoint = result.missingTransportForWaypoint;
this.showAccessibilityInfo = this.stops.length > 0;
this.createStopDocuments();
})
.catch((error) => {
console.error('Erreur lors de la récupération des données :', error);
this.missingTransportForWaypoint = true;

documents.forEach((doc) => {
doc.public_transportation_rating = 'no service';
});
});
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid mutating input documents directly

The method modifies the input documents array by setting public_transportation_rating directly. This mutation can cause unexpected side effects and makes the component harder to test and reason about.

Consider creating a local copy or using a computed property to track transportation ratings:

     fetchStopsForDocuments(documents) {
+      const documentRatings = {};
       transportService
         .getStopareasForDocuments(documents)
         .then((result) => {
           documents.forEach((doc) => {
             if (!result.documentResults[doc.document_id]) {
-              doc.public_transportation_rating = 'no service';
+              documentRatings[doc.document_id] = 'no service';
             } else {
-              doc.public_transportation_rating = 'service available';
+              documentRatings[doc.document_id] = 'service available';
             }
           });
+          this.documentRatings = documentRatings;

Also, use English for console messages:

-          console.error('Erreur lors de la récupération des données :', error);
+          console.error('Error fetching transport data:', error);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fetchStopsForDocuments(documents) {
transportService
.getStopareasForDocuments(documents)
.then((result) => {
documents.forEach((doc) => {
if (!result.documentResults[doc.document_id]) {
doc.public_transportation_rating = 'no service';
} else {
doc.public_transportation_rating = 'service available';
}
});
this.stops = result.stopareas.sort((a, b) => a.distance - b.distance);
this.missingTransportForWaypoint = result.missingTransportForWaypoint;
this.showAccessibilityInfo = this.stops.length > 0;
this.createStopDocuments();
})
.catch((error) => {
console.error('Erreur lors de la récupération des données :', error);
this.missingTransportForWaypoint = true;
documents.forEach((doc) => {
doc.public_transportation_rating = 'no service';
});
});
},
fetchStopsForDocuments(documents) {
const documentRatings = {};
transportService
.getStopareasForDocuments(documents)
.then((result) => {
documents.forEach((doc) => {
if (!result.documentResults[doc.document_id]) {
documentRatings[doc.document_id] = 'no service';
} else {
documentRatings[doc.document_id] = 'service available';
}
});
this.documentRatings = documentRatings;
this.stops = result.stopareas.sort((a, b) => a.distance - b.distance);
this.missingTransportForWaypoint = result.missingTransportForWaypoint;
this.showAccessibilityInfo = this.stops.length > 0;
this.createStopDocuments();
})
.catch((error) => {
console.error('Error fetching transport data:', error);
this.missingTransportForWaypoint = true;
documents.forEach((doc) => {
doc.public_transportation_rating = 'no service';
});
});
},
🤖 Prompt for AI Agents
In src/views/document/utils/boxes/TransportsBox.vue around lines 194 to 219, the
fetchStopsForDocuments method directly mutates the input documents array by
setting public_transportation_rating on each document, which can cause side
effects. To fix this, create a local copy of the documents or maintain a
separate data structure to track transportation ratings without modifying the
original input. Also, replace the French console error message with an English
one for consistency.

Comment on lines +223 to +271
createStopDocuments() {
if (!this.stops || !this.stops.length) return;

if (this.accessWaypoints.length === 0) return;

this.stopDocuments = this.stops.reduce(
(uniqueStops, stop) => {
try {
if (!stop.coordinates || !stop.coordinates.x || !stop.coordinates.y) {
console.warn(`Stop ${stop.id} n'a pas de coordonnées valides:`, stop);
return uniqueStops;
}

const coordKey = `${stop.coordinates.x},${stop.coordinates.y}`;
if (uniqueStops.coordsMap[coordKey]) {
return uniqueStops;
}

const stopDoc = JSON.parse(JSON.stringify(this.accessWaypoints[0]));
stopDoc.document_id = stop.id;
stopDoc.type = 's';
if (stopDoc.locales && stopDoc.locales.length > 0) {
stopDoc.locales[0].title = '';
}
if (stopDoc.geometry) {
const geom = {
type: 'Point',
coordinates: [stop.coordinates.x, stop.coordinates.y],
};
stopDoc.geometry.geom = JSON.stringify(geom);
}
stopDoc.isStopPoint = true;
stopDoc.stopInfo = {
operator: stop.operator,
line: stop.line,
distance: stop.distance,
};

uniqueStops.coordsMap[coordKey] = true;
uniqueStops.docs.push(stopDoc);
return uniqueStops;
} catch (error) {
console.error(`Erreur lors de la création du document pour le stop ${stop.id}:`, error);
return uniqueStops;
}
},
{ docs: [], coordsMap: {} }
).docs;
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve deep cloning approach and use English for logs

The method uses JSON.parse(JSON.stringify()) for deep cloning which is inefficient and can fail with certain data types (dates, functions, undefined values).

Consider using a proper deep clone utility:

-            const stopDoc = JSON.parse(JSON.stringify(this.accessWaypoints[0]));
+            const stopDoc = this.$utils.deepClone(this.accessWaypoints[0]);

Or use object spread with nested properties:

-            const stopDoc = JSON.parse(JSON.stringify(this.accessWaypoints[0]));
+            const stopDoc = {
+              ...this.accessWaypoints[0],
+              geometry: this.accessWaypoints[0].geometry ? { ...this.accessWaypoints[0].geometry } : null,
+              locales: this.accessWaypoints[0].locales?.map(locale => ({ ...locale })) || [],
+            };

Also, use English for console messages:

-              console.warn(`Stop ${stop.id} n'a pas de coordonnées valides:`, stop);
+              console.warn(`Stop ${stop.id} has no valid coordinates:`, stop);
-            console.error(`Erreur lors de la création du document pour le stop ${stop.id}:`, error);
+            console.error(`Error creating document for stop ${stop.id}:`, error);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
createStopDocuments() {
if (!this.stops || !this.stops.length) return;
if (this.accessWaypoints.length === 0) return;
this.stopDocuments = this.stops.reduce(
(uniqueStops, stop) => {
try {
if (!stop.coordinates || !stop.coordinates.x || !stop.coordinates.y) {
console.warn(`Stop ${stop.id} n'a pas de coordonnées valides:`, stop);
return uniqueStops;
}
const coordKey = `${stop.coordinates.x},${stop.coordinates.y}`;
if (uniqueStops.coordsMap[coordKey]) {
return uniqueStops;
}
const stopDoc = JSON.parse(JSON.stringify(this.accessWaypoints[0]));
stopDoc.document_id = stop.id;
stopDoc.type = 's';
if (stopDoc.locales && stopDoc.locales.length > 0) {
stopDoc.locales[0].title = '';
}
if (stopDoc.geometry) {
const geom = {
type: 'Point',
coordinates: [stop.coordinates.x, stop.coordinates.y],
};
stopDoc.geometry.geom = JSON.stringify(geom);
}
stopDoc.isStopPoint = true;
stopDoc.stopInfo = {
operator: stop.operator,
line: stop.line,
distance: stop.distance,
};
uniqueStops.coordsMap[coordKey] = true;
uniqueStops.docs.push(stopDoc);
return uniqueStops;
} catch (error) {
console.error(`Erreur lors de la création du document pour le stop ${stop.id}:`, error);
return uniqueStops;
}
},
{ docs: [], coordsMap: {} }
).docs;
},
createStopDocuments() {
if (!this.stops || !this.stops.length) return;
if (this.accessWaypoints.length === 0) return;
this.stopDocuments = this.stops.reduce(
(uniqueStops, stop) => {
try {
if (!stop.coordinates || !stop.coordinates.x || !stop.coordinates.y) {
console.warn(`Stop ${stop.id} has no valid coordinates:`, stop);
return uniqueStops;
}
const coordKey = `${stop.coordinates.x},${stop.coordinates.y}`;
if (uniqueStops.coordsMap[coordKey]) {
return uniqueStops;
}
const stopDoc = this.$utils.deepClone(this.accessWaypoints[0]);
stopDoc.document_id = stop.id;
stopDoc.type = 's';
if (stopDoc.locales && stopDoc.locales.length > 0) {
stopDoc.locales[0].title = '';
}
if (stopDoc.geometry) {
const geom = {
type: 'Point',
coordinates: [stop.coordinates.x, stop.coordinates.y],
};
stopDoc.geometry.geom = JSON.stringify(geom);
}
stopDoc.isStopPoint = true;
stopDoc.stopInfo = {
operator: stop.operator,
line: stop.line,
distance: stop.distance,
};
uniqueStops.coordsMap[coordKey] = true;
uniqueStops.docs.push(stopDoc);
return uniqueStops;
} catch (error) {
console.error(`Error creating document for stop ${stop.id}:`, error);
return uniqueStops;
}
},
{ docs: [], coordsMap: {} }
).docs;
},
🤖 Prompt for AI Agents
In src/views/document/utils/boxes/TransportsBox.vue between lines 223 and 271,
replace the JSON.parse(JSON.stringify()) deep cloning with a more reliable deep
clone utility or a safer cloning method like object spread for nested properties
to handle complex data types correctly. Additionally, update all console warning
and error messages to be in English for consistency and clarity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants