Skip to content

feat: Smart/Origin: ffcam livraison1#4569

Open
lgourdin wants to merge 31 commits into
masterfrom
smart-origin/ffcam_livraison1
Open

feat: Smart/Origin: ffcam livraison1#4569
lgourdin wants to merge 31 commits into
masterfrom
smart-origin/ffcam_livraison1

Conversation

@lgourdin

@lgourdin lgourdin commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Details:

  • extend nearbyStopAreaSection to the following waypoint_type:
    "hut", "gite", "climbing_outdoor", "climbing_indoor", "paragliding_landing", "shelter", "bivouac", "camp_site", "access"
  • extend planATripSection to waypoint of type "access"
  • Better error management for PlanATripSection
  • Refactor of planATripSection component to ease readability

Summary by CodeRabbit

  • New Features
    • Rebuilt the public-transport trip planner with outbound/return tabs, date/time controls, transfer limits, an itinerary timeline, and a route map.
    • Added contextual display of transport/plan-a-trip panels for routes and access-type waypoints, with updated journey duration/distance and accessibility indicators.
  • Bug Fixes
    • Improved address selection synchronization so the chosen location stays consistent with its formatted display.
    • Refined missing-transport messaging and access-point handling for route vs waypoint cases.
  • Documentation
    • Expanded French translations for trip planning, itinerary guidance labels, and related user-facing errors/help text.

@github-actions github-actions Bot added the enhancement New feature or request label Jul 3, 2026
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

This PR adds a public-transport trip-planning flow, splits the planning UI into form/results/orchestration components, updates access-waypoint handling and document wiring, fixes address selection state, and expands French trip-planning translations.

Changes

Public transport trip planning refactor

Layer / File(s) Summary
Formatting utilities
src/js/plan-a-trip-utils.js
New default-exported object with helpers for time/duration formatting, transport icon/class mapping, distance, accessibility flags, route color, and section duration calculation.
Access-waypoint detection refactor
src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue, src/views/document/utils/boxes/NearbyStopsSection.vue, src/views/document/utils/boxes/TransportsBox.vue
accessWaypoints logic across boxes now branches on documentType/waypoint_type with optional chaining; TransportsBox adds an isPlanATripSectionDisplayed eligibility computed and drops its document prop; NearbyStopsSection adds a route-vs-waypoint missing-transport banner with new styles.
Route/waypoint view wiring
src/views/document/RouteView.vue, src/views/document/WaypointView.vue
RouteView now passes the full document instead of its waypoints association; WaypointView conditionally renders transport boxes via a new showTransportBox computed property.
PlanATrip form and results
src/views/document/utils/boxes/PlanATripSection/PlanATripForm.vue, src/views/document/utils/boxes/PlanATripSection/PlanATripResults.vue
New components render outbound/return trip inputs, journey lists, detailed timelines, shared helper formatting, and their supporting styles and emitted events.
PlanATrip orchestration
src/views/document/utils/boxes/PlanATripSection/PlanATripSection.vue, src/views/document/utils/boxes/PlanATripSection.vue (removed)
PlanATripSection.vue renders the trip-planning flow, coordinates outbound and return state, loads reachable waypoints, calls NavitiaService with fallback search, builds route documents, handles tab switching and time shortcuts, and formats duration display; the old monolithic component is removed.
Address fix and translations
src/components/generics/inputs/InputAddress.vue, src/translations/fr.json
selectAddress now syncs the formatted address into both localData.address and selectedAddress.address; French translations add error messages, trip-planning labels, accessibility wording, and a configuration URL key.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant PlanATripSection
  participant NavitiaService
  participant MapView

  User->>PlanATripSection: calculateRoute()
  PlanATripSection->>NavitiaService: getJourneys(datetime -15min)
  NavitiaService-->>PlanATripSection: journeys
  alt journeys match selected date
    PlanATripSection->>PlanATripSection: filter journeys, determineReturnWaypoint()
  else no match found
    PlanATripSection->>NavitiaService: fetchExtendedTimeframeJourney()
    NavitiaService-->>PlanATripSection: extended journeys
  end
  PlanATripSection->>PlanATripSection: prepareRouteDocuments()
  PlanATripSection->>MapView: render filteredDocuments
Loading

Possibly related PRs

  • c2corg/c2c_ui#4381: Overlaps with trip-planning flow changes around connection limits and public-transport box visibility.
  • c2corg/c2c_ui#4504: Related to the InputAddress.vue address selection state update.

Suggested labels: bug

Poem

A rabbit hops through transit light,
With routes and waypoints tucked in tight.
One form, two results, the trips align,
French labels shimmer, clear and fine. 🐇
The address lands just where it should,
And planning journeys feels quite good.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title looks like an internal ticket label and does not clearly describe the main code changes. Use a concise, descriptive title like 'Refactor plan-a-trip and extend waypoint transport support'.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch smart-origin/ffcam_livraison1

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

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🧹 Nitpick comments (6)
src/js/plan-a-trip-utils.js (1)

20-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

getTransportIcon and getTransportClass are byte-for-byte identical.

Both functions contain the exact same mode-matching logic and always return the same string. Keeping two separate copies risks silent divergence the next time a transport mode is added/changed (icon and CSS class could end up mismatched).

♻️ Suggested consolidation
-  /** Gets icons according to the nature of the transport */
-  getTransportIcon(section) {
-    if (!section.display_informations) return '';
-
-    const mode = section.display_informations.commercial_mode?.toLowerCase() || '';
-    if (mode.includes('bus')) return 'bus';
-    if (mode.includes('tram')) return 'tram';
-    if (mode.includes('métro') || mode.includes('metro')) return 'tram';
-    if (mode.includes('train')) return 'train';
-    if (mode.includes('car')) return 'bus';
-
-    return 'bus';
-  },
-
-  /** Manage different spellings of transports */
-  getTransportClass(section) {
-    if (!section.display_informations) return '';
-
-    const mode = section.display_informations.commercial_mode?.toLowerCase() || '';
-
-    if (mode.includes('bus')) return 'bus';
-    if (mode.includes('tram')) return 'tram';
-    if (mode.includes('métro') || mode.includes('metro')) return 'tram';
-    if (mode.includes('train')) return 'train';
-    if (mode.includes('car')) return 'bus';
-
-    return 'bus';
-  },
+  /** Normalizes commercial mode into a canonical transport key, used for both icon file name and CSS class */
+  getTransportKey(section) {
+    if (!section.display_informations) return '';
+    const mode = section.display_informations.commercial_mode?.toLowerCase() || '';
+    if (mode.includes('bus') || mode.includes('car')) return 'bus';
+    if (mode.includes('tram') || mode.includes('métro') || mode.includes('metro')) return 'tram';
+    if (mode.includes('train')) return 'train';
+    return 'bus';
+  },
+  getTransportIcon(section) {
+    return this.getTransportKey(section);
+  },
+  getTransportClass(section) {
+    return this.getTransportKey(section);
+  },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/js/plan-a-trip-utils.js` around lines 20 - 47, `getTransportIcon` and
`getTransportClass` in plan-a-trip-utils.js are identical and should be
consolidated to a single source of truth. Extract the shared mode-to-value
mapping into one helper used by both functions, or have one delegate to the
other, so transport icon and CSS class logic in
`getTransportIcon`/`getTransportClass` cannot drift apart when adding or
changing modes.
src/views/document/utils/boxes/PlanATripSection/PlanATripSection.vue (2)

1125-1219: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Leftover dead CSS from the component split.

.itineraries-container/.itinerary-header/.selected are re-declared nested inside .no-itineraries-container here, but that markup was moved to PlanATripResults.vue (which has its own scoped copy of the same rules, Lines 260-303 there). Since Vue scoped styles never cross component boundaries, and this file's own template no longer renders an .itineraries-container element, this nested block is now unreachable/dead.

♻️ Suggested cleanup
       .no-itineraries-container {
         border: 1px solid lightgrey;
         position: relative;
         border-radius: 4px;
         max-width: 450px;
         .no-itineraries {
           ...
         }
-        .itineraries-container {
-          max-width: 490px;
-          flex: 1;
-          padding-right: 16px;
-          transition: background-color 0.3s ease;
-          position: relative;
-
-          .itinerary-header {
-            ...
-          }
-          .selected {
-            border-left: 4px solid `#4baf50`;
-            background-color: `#fbfaf6`;
-          }
-        }
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/views/document/utils/boxes/PlanATripSection/PlanATripSection.vue` around
lines 1125 - 1219, Remove the dead styling block from PlanATripSection.vue: the
nested `.itineraries-container`, `.itinerary-header`, and `.selected` rules
inside `.no-itineraries-container` are no longer used after the split. Keep the
`.no-itineraries-container` and `.navitia-unknown-error` styles here, and leave
the active itineraries styling in PlanATripResults.vue where the matching markup
now lives.

946-987: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Remove the dead Case 5 branch The earlier checks already return for every possible reachableWaypoints.length, so this fallback can never run. If the outbound-waypoint fallback is still needed, move it before the length > 2 return.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/views/document/utils/boxes/PlanATripSection/PlanATripSection.vue` around
lines 946 - 987, The fallback branch in determineReturnWaypoint is dead code
because all reachableWaypoints length cases already return before it can
execute. Remove the unreachable “Case 5” block, or if
outboundData.selectedWaypoint should still be reused when reachableWaypoints
contains it, move that logic earlier in determineReturnWaypoint before the
length > 2 return so it can actually run.
src/components/generics/inputs/InputAddress.vue (1)

226-232: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Mutates the selected proposition object in place instead of copying it.

localData.selectedAddress = proposition followed by localData.selectedAddress.address = ... mutates the original object reference (e.g. a Photon GeoJSON feature) rather than creating a new object. If this same object reference is retained elsewhere (e.g. still present in addressPropositions, or reused by a caller), the added .address field silently pollutes it. A shallow copy avoids this risk.

💡 Suggested fix
     selectAddress(proposition) {
       this.localData.address = this.formatProposition(proposition);
-      this.localData.selectedAddress = proposition;
-      this.localData.selectedAddress.address = this.localData.address;
+      this.localData.selectedAddress = { ...proposition, address: this.localData.address };
       this.localData.coordinates = proposition.geometry.coordinates;
       this.localData.showAddressPropositions = false;
     },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/generics/inputs/InputAddress.vue` around lines 226 - 232, The
selectAddress method is mutating the incoming proposition object by assigning it
directly to localData.selectedAddress and then writing address onto it. Update
selectAddress in InputAddress.vue to create a shallow copy of proposition before
storing or enriching it, so the original GeoJSON feature/object is not polluted.
Keep the rest of the flow the same: format the address, preserve
geometry.coordinates, and still hide the propositions list.
src/views/document/utils/boxes/TransportsBox.vue (1)

105-117: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated accessWaypoints logic across three files.

This exact branching (documentType === 'waypoint' && waypoint_type === 'access'[document], else filter associations.waypoints) is copy-pasted near-verbatim in IsReachableByPublicTransportsBox.vue, NearbyStopsSection.vue, and here. Consider extracting a shared helper (e.g. a mixin or a function in plan-a-trip-utils.js) such as getAccessWaypoints(document, documentType) to avoid drift as this logic evolves (it already needed a bugfix in all three places, see the sibling comment).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/views/document/utils/boxes/TransportsBox.vue` around lines 105 - 117, The
access-waypoints branching is duplicated and should be centralized to avoid
future drift. Extract the shared logic from this component’s accessWaypoints
handling into a reusable helper such as getAccessWaypoints(document,
documentType) in plan-a-trip-utils.js (or a shared mixin/util), then update
TransportsBox.vue, IsReachableByPublicTransportsBox.vue, and
NearbyStopsSection.vue to call it instead of inlining the same waypoint/access
filter condition.
src/views/document/WaypointView.vue (1)

169-182: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider centralizing TRANSPORT_BOX_TYPES.

This allowlist is defined inline here and conceptually related to TransportsBox.vue's isPlanATripSectionDisplayed waypoint-type checks. Extracting it to a shared constant (e.g. alongside plan-a-trip-utils.js) would reduce risk of the two lists silently diverging as waypoint types are added/removed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/views/document/WaypointView.vue` around lines 169 - 182, The
waypoint-type allowlist is duplicated inline in showTransportBox and overlaps
with TransportsBox.vue’s isPlanATripSectionDisplayed checks, so move
TRANSPORT_BOX_TYPES into a shared constant used by both places. Define it in a
common utility such as plan-a-trip-utils.js, import it in WaypointView.vue and
TransportsBox.vue, and update both checks to reference the shared source so the
lists cannot drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/js/plan-a-trip-utils.js`:
- Around line 105-125: The calculateSectionDuration helper in plan-a-trip-utils
is recomputing duration from departure_date_time and arrival_date_time, which
ignores the date and can produce negative results for overnight sections. Update
calculateSectionDuration to use section.duration directly instead of parsing the
timestamps, and keep the fallback behavior returning 0 when duration is
unavailable.

In `@src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue`:
- Around line 35-41: In IsReachableByPublicTransportsBox.vue, the
accessWaypoints lookup in the related computed logic can return undefined when
associations.waypoints is missing, which then breaks checkAccessibility() when
it reads length. Update the branch that returns the filtered waypoints so it
always yields an array, and keep the waypoint access special-case intact. Use
the existing documentType/document.waypoint_type handling and the
checkAccessibility() caller as the reference points while adding the fallback.

In `@src/views/document/utils/boxes/NearbyStopsSection.vue`:
- Around line 129-141: The fallback path in NearbyStopsSection’s access-waypoint
selection can leave accessWaypoints undefined, which then breaks the
JSON.parse(JSON.stringify(...)) clone. Update the computed logic around the
accessWaypoints assignment to default the filtered associations to an empty
array (for example with a nullish fallback) or bypass the deep clone when no
items exist, so the property remains safe when a document has no access
waypoints.

In `@src/views/document/utils/boxes/PlanATripSection/PlanATripForm.vue`:
- Around line 51-81: The return-trip destination field in PlanATripForm.vue is
using the wrong placeholder text, since the input-address bound to
currentData.fromAddress is the “To” address when activeTab is return. Update
that placeholder to a destination/arrival-oriented string instead of “Enter a
departure address,” and keep the change localized to the return-trip branch so
the outbound field remains unchanged.

In `@src/views/document/utils/boxes/PlanATripSection/PlanATripResults.vue`:
- Line 70: The fallback labels in PlanATripResults.vue are hardcoded and bypass
localization. Update the affected template expressions in the PlanATripResults
component so the fallback values for the waypoint/title and timeline labels use
$gettext instead of raw strings. Replace the untranslated "Destination" as well
as the hardcoded French "Départ" and "Arrivée" with translated fallbacks in the
same places where currentData.selectedWaypoint and the timeline label rendering
are handled.
- Around line 29-35: The transport icon markup in PlanATripResults.vue is using
the wrong alt text, with the public_transport/on_demand_transport image still
labeled as walking. Update the img element in the transport-icon block to use an
alt value that matches the transport icon being rendered, and keep the walking
alt text only in the walking-icon branch so assistive technology gets the
correct label.

In `@src/views/document/utils/boxes/PlanATripSection/PlanATripSection.vue`:
- Around line 270-272: Fix the typo in the source string used by
PlanATripSection so the unknown_error gettext key uses “occurred” instead of
“occured”; update the matching translation entry in fr.json at the same key so
the source string and translation lookup stay in sync. Use the existing
unknown_error and navitia_internal_error entries in PlanATripSection.vue to
locate the change.
- Around line 317-346: mapDocuments is doing more than computing data because it
calls prepareRouteDocuments, which schedules recenterOnDocuments via $nextTick.
Move the map recenter side effect out of the computed chain and keep
mapDocuments pure; instead trigger the recenter from a watch on
currentData.selectedRouteJourney or immediately after
calculateRoute/fetchExtendedTimeframeJourney completes. Update
prepareRouteDocuments and the $refs.mapView.recenterOnDocuments call so they are
only reached from the new side-effect path, not from the computed getter.
- Around line 906-943: Make loadReachableWaypoints in PlanATripSection handle
missing associations safely by defaulting accessPoints to an empty array instead
of allowing this.document?.associations?.waypoints?.filter(...) to produce
undefined, so the for...of over accessPoints never crashes. Also wrap the
transportService.isReachable/PROMISE.all flow in try/catch or equivalent error
handling, and ensure loadingReachable is reset to false in a finally block so a
failed reachability check does not leave the UI stuck loading.
- Around line 477-528: The `fetchExtendedTimeframeJourney` fallback in
`PlanATripSection.vue` is currently triggered for every failure in the
`try/catch`, even for non-retryable Navitia errors. Update the `catch` in the
journey fetch flow to only call `fetchExtendedTimeframeJourney` for retryable
cases, and skip it for `auth_error`, `invalid_param`, `navitia_internal_error`,
or other unknown/non-recoverable errors. Use the existing `queryError` parsing
from `error?.response?.data?.errors?.[0]?.description` and the journey-fetch
methods (`getJourneys`, `fetchExtendedTimeframeJourney`) to gate the fallback
instead of unconditionally retrying.

In `@src/views/document/utils/boxes/TransportsBox.vue`:
- Around line 105-117: The waypoint filtering logic in TransportsBox.vue can
still leave accessWaypoints undefined when document.associations.waypoints is
missing, which then breaks the JSON.parse(JSON.stringify(...)) copy step. Update
the accessWaypoints assignment in the TransportsBox component to default the
filtered result to an empty array using nullish coalescing, so the later
accessPointsCopy clone always receives an array.

---

Nitpick comments:
In `@src/components/generics/inputs/InputAddress.vue`:
- Around line 226-232: The selectAddress method is mutating the incoming
proposition object by assigning it directly to localData.selectedAddress and
then writing address onto it. Update selectAddress in InputAddress.vue to create
a shallow copy of proposition before storing or enriching it, so the original
GeoJSON feature/object is not polluted. Keep the rest of the flow the same:
format the address, preserve geometry.coordinates, and still hide the
propositions list.

In `@src/js/plan-a-trip-utils.js`:
- Around line 20-47: `getTransportIcon` and `getTransportClass` in
plan-a-trip-utils.js are identical and should be consolidated to a single source
of truth. Extract the shared mode-to-value mapping into one helper used by both
functions, or have one delegate to the other, so transport icon and CSS class
logic in `getTransportIcon`/`getTransportClass` cannot drift apart when adding
or changing modes.

In `@src/views/document/utils/boxes/PlanATripSection/PlanATripSection.vue`:
- Around line 1125-1219: Remove the dead styling block from
PlanATripSection.vue: the nested `.itineraries-container`, `.itinerary-header`,
and `.selected` rules inside `.no-itineraries-container` are no longer used
after the split. Keep the `.no-itineraries-container` and
`.navitia-unknown-error` styles here, and leave the active itineraries styling
in PlanATripResults.vue where the matching markup now lives.
- Around line 946-987: The fallback branch in determineReturnWaypoint is dead
code because all reachableWaypoints length cases already return before it can
execute. Remove the unreachable “Case 5” block, or if
outboundData.selectedWaypoint should still be reused when reachableWaypoints
contains it, move that logic earlier in determineReturnWaypoint before the
length > 2 return so it can actually run.

In `@src/views/document/utils/boxes/TransportsBox.vue`:
- Around line 105-117: The access-waypoints branching is duplicated and should
be centralized to avoid future drift. Extract the shared logic from this
component’s accessWaypoints handling into a reusable helper such as
getAccessWaypoints(document, documentType) in plan-a-trip-utils.js (or a shared
mixin/util), then update TransportsBox.vue,
IsReachableByPublicTransportsBox.vue, and NearbyStopsSection.vue to call it
instead of inlining the same waypoint/access filter condition.

In `@src/views/document/WaypointView.vue`:
- Around line 169-182: The waypoint-type allowlist is duplicated inline in
showTransportBox and overlaps with TransportsBox.vue’s
isPlanATripSectionDisplayed checks, so move TRANSPORT_BOX_TYPES into a shared
constant used by both places. Define it in a common utility such as
plan-a-trip-utils.js, import it in WaypointView.vue and TransportsBox.vue, and
update both checks to reference the shared source so the lists cannot drift.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2db78652-89b3-4626-99b4-b6ac7f1b9d92

📥 Commits

Reviewing files that changed from the base of the PR and between 95f02bc and 06d6acf.

⛔ Files ignored due to path filters (1)
  • src/assets/img/boxes/navitia_api_error.svg is excluded by !**/*.svg
📒 Files selected for processing (12)
  • src/components/generics/inputs/InputAddress.vue
  • src/js/plan-a-trip-utils.js
  • src/translations/fr.json
  • src/views/document/RouteView.vue
  • src/views/document/WaypointView.vue
  • src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue
  • src/views/document/utils/boxes/NearbyStopsSection.vue
  • src/views/document/utils/boxes/PlanATripSection.vue
  • src/views/document/utils/boxes/PlanATripSection/PlanATripForm.vue
  • src/views/document/utils/boxes/PlanATripSection/PlanATripResults.vue
  • src/views/document/utils/boxes/PlanATripSection/PlanATripSection.vue
  • src/views/document/utils/boxes/TransportsBox.vue
💤 Files with no reviewable changes (1)
  • src/views/document/utils/boxes/PlanATripSection.vue

Comment thread src/js/plan-a-trip-utils.js Outdated
Comment thread src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue
Comment thread src/views/document/utils/boxes/NearbyStopsSection.vue
Comment thread src/views/document/utils/boxes/PlanATripSection/PlanATripForm.vue
Comment on lines +270 to +272
// internal server error
unknown_error: this.$gettext('An unknown error occured.'),
navitia_internal_error: this.$gettext('Public transport data is currently unavailable.'),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Typo: "occured" → "occurred".

this.$gettext('An unknown error occured.') has a spelling error. Since translation lookups match on the exact source string, this needs to be fixed here and the corresponding key updated in src/translations/fr.json (Line 63) to keep the translation matching.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/views/document/utils/boxes/PlanATripSection/PlanATripSection.vue` around
lines 270 - 272, Fix the typo in the source string used by PlanATripSection so
the unknown_error gettext key uses “occurred” instead of “occured”; update the
matching translation entry in fr.json at the same key so the source string and
translation lookup stay in sync. Use the existing unknown_error and
navitia_internal_error entries in PlanATripSection.vue to locate the change.

Comment thread src/views/document/utils/boxes/TransportsBox.vue

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/js/plan-a-trip-utils.js (2)

9-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated duration-formatting logic between formatDuration and formatJourneyDuration.

Both compute hours/minutes from seconds with near-identical logic, differing only in display format ("X h Y min" vs "XhYY"). Consider extracting a shared hours/minutes helper to avoid divergence if the formatting rules need to change later.

Also applies to: 92-103

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/js/plan-a-trip-utils.js` around lines 9 - 18, The duration formatting
logic is duplicated between formatDuration and formatJourneyDuration, so extract
the shared hours/minutes calculation into a helper and have both methods reuse
it. Keep the formatting differences in each method, but centralize the
seconds-to-hours/minutes conversion to avoid future divergence. Use the existing
formatDuration and formatJourneyDuration symbols to locate the duplicated block
and update both callers to rely on the new shared helper.

20-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

getTransportIcon and getTransportClass are identical implementations.

Both functions have the exact same body and will always return the same value for any given section. If the icon key and CSS class are meant to be able to diverge (e.g. more granular classes later), this coupling will silently break; if they're truly meant to be identical, consolidate into one function to avoid future drift.

Also note both fall back to 'bus' for any unmatched commercial_mode (e.g. Navitia's Boat, Ferry, Funicular, Air, Taxi physical modes), which will mislabel those transport types as bus icons/classes.

♻️ Suggested consolidation
-  /** Gets icons according to the nature of the transport */
-  getTransportIcon(section) {
-    if (!section.display_informations) return '';
-
-    const mode = section.display_informations.commercial_mode?.toLowerCase() || '';
-    if (mode.includes('bus')) return 'bus';
-    if (mode.includes('tram')) return 'tram';
-    if (mode.includes('métro') || mode.includes('metro')) return 'tram';
-    if (mode.includes('train')) return 'train';
-    if (mode.includes('car')) return 'bus';
-
-    return 'bus';
-  },
-
-  /** Manage different spellings of transports */
-  getTransportClass(section) {
-    if (!section.display_informations) return '';
-
-    const mode = section.display_informations.commercial_mode?.toLowerCase() || '';
-
-    if (mode.includes('bus')) return 'bus';
-    if (mode.includes('tram')) return 'tram';
-    if (mode.includes('métro') || mode.includes('metro')) return 'tram';
-    if (mode.includes('train')) return 'train';
-    if (mode.includes('car')) return 'bus';
-
-    return 'bus';
-  },
+  /** Gets icons and CSS class according to the nature of the transport */
+  getTransportIcon(section) {
+    if (!section.display_informations) return '';
+
+    const mode = section.display_informations.commercial_mode?.toLowerCase() || '';
+    if (mode.includes('bus')) return 'bus';
+    if (mode.includes('tram')) return 'tram';
+    if (mode.includes('métro') || mode.includes('metro')) return 'tram';
+    if (mode.includes('train')) return 'train';
+    if (mode.includes('car')) return 'bus';
+
+    return 'bus';
+  },
+
+  /** Alias kept for template compatibility */
+  getTransportClass(section) {
+    return this.getTransportIcon(section);
+  },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/js/plan-a-trip-utils.js` around lines 20 - 47, getTransportIcon and
getTransportClass currently duplicate the same transport-mapping logic, so
either consolidate the shared behavior into a single helper used by both methods
or clearly separate them if icon and CSS class mappings need to diverge later.
Update the mapping in plan-a-trip-utils.js around
getTransportIcon/getTransportClass to avoid drift, and expand the fallback
handling so unmatched commercial_mode values are not mislabeled as bus; add
explicit cases for other Navitia modes like Boat, Ferry, Funicular, Air, and
Taxi (or a safe default) in the shared transport resolution logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/js/plan-a-trip-utils.js`:
- Around line 9-18: The duration formatting logic is duplicated between
formatDuration and formatJourneyDuration, so extract the shared hours/minutes
calculation into a helper and have both methods reuse it. Keep the formatting
differences in each method, but centralize the seconds-to-hours/minutes
conversion to avoid future divergence. Use the existing formatDuration and
formatJourneyDuration symbols to locate the duplicated block and update both
callers to rely on the new shared helper.
- Around line 20-47: getTransportIcon and getTransportClass currently duplicate
the same transport-mapping logic, so either consolidate the shared behavior into
a single helper used by both methods or clearly separate them if icon and CSS
class mappings need to diverge later. Update the mapping in plan-a-trip-utils.js
around getTransportIcon/getTransportClass to avoid drift, and expand the
fallback handling so unmatched commercial_mode values are not mislabeled as bus;
add explicit cases for other Navitia modes like Boat, Ferry, Funicular, Air, and
Taxi (or a safe default) in the shared transport resolution logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b4580ce3-ba09-4add-a6dd-b56bf71c9dbc

📥 Commits

Reviewing files that changed from the base of the PR and between 06d6acf and e5ff119.

📒 Files selected for processing (8)
  • src/js/plan-a-trip-utils.js
  • src/translations/fr.json
  • src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue
  • src/views/document/utils/boxes/NearbyStopsSection.vue
  • src/views/document/utils/boxes/PlanATripSection/PlanATripForm.vue
  • src/views/document/utils/boxes/PlanATripSection/PlanATripResults.vue
  • src/views/document/utils/boxes/PlanATripSection/PlanATripSection.vue
  • src/views/document/utils/boxes/TransportsBox.vue
✅ Files skipped from review due to trivial changes (1)
  • src/translations/fr.json
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/views/document/utils/boxes/PlanATripSection/PlanATripForm.vue
  • src/views/document/utils/boxes/IsReachableByPublicTransportsBox.vue
  • src/views/document/utils/boxes/PlanATripSection/PlanATripResults.vue
  • src/views/document/utils/boxes/TransportsBox.vue
  • src/views/document/utils/boxes/NearbyStopsSection.vue
  • src/views/document/utils/boxes/PlanATripSection/PlanATripSection.vue

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant