Skip to content

Show how long trains have been stopped#139

Merged
Julian-Louis merged 1 commit into
simrail:mainfrom
Over441:Countdown-stop-train
Jul 5, 2026
Merged

Show how long trains have been stopped#139
Julian-Louis merged 1 commit into
simrail:mainfrom
Over441:Countdown-stop-train

Conversation

@Over441

@Over441 Over441 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Track and display how long trains have been stopped. Add getTrainStopKey helper and stoppedTrainsSince state in Map to record a timestamp when a train's velocity reaches zero, update it on fetch, and pass the data down to TrainsList, TrainMarker and SelectedTrainPopup. TrainText now accepts stoppedSince, computes a live-updating stopped duration (formatStoppedDuration) and shows it when the train is stationary. Minor prop and typing updates applied to components.

Summary by CodeRabbit

  • New Features
    • Train details now show how long a train has been stopped.
    • Stopped trains are tracked individually, so the duration stays accurate as the map updates.
    • Train markers, selected-train popups, and the train list now display stop-duration information consistently.

Track and display how long trains have been stopped. Add getTrainStopKey helper and stoppedTrainsSince state in Map to record a timestamp when a train's velocity reaches zero, update it on fetch, and pass the data down to TrainsList, TrainMarker and SelectedTrainPopup. TrainText now accepts stoppedSince, computes a live-updating stopped duration (formatStoppedDuration) and shows it when the train is stationary. Minor prop and typing updates applied to components.
@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds stopped-train duration tracking. Map.tsx computes per-train stop timestamps keyed by train id or TrainNoLocal, storing them in state. This value is propagated through TrainsList and TrainMarker to SelectedTrainPopup and TrainText, which formats and displays elapsed stopped duration with a live-updating timer.

Changes

Stopped train duration feature

Layer / File(s) Summary
Compute and store stopped-train timestamps
packages/map/components/Map.tsx
Adds getTrainStopKey helper and stoppedTrainsSince state populated during train fetch based on rounded velocity 0; passes the value to SelectedTrainPopup and TrainsList.
Propagate stoppedSince through list, marker, popup
packages/map/components/TrainsList.tsx, packages/map/components/Markers/TrainMarker.tsx, packages/map/components/SelectedTrainPopup.tsx
Extends TrainsList props/rendering with stoppedTrainsSince and getTrainStopKey; adds optional stoppedSince to TrainMarkerProps and SelectedTrainPopupProps, forwarding the value to TrainText.
Render formatted stop duration
packages/map/components/TrainText.tsx
Adds stoppedSince prop, formatStoppedDuration helper, a currentTime state with a 1s interval effect, and updates the stopped-state message to show elapsed duration.

Estimated code review effort: 2 (Simple) | ~15 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Map
  participant TrainsList
  participant TrainMarker
  participant SelectedTrainPopup
  participant TrainText

  Map->>Map: getTrains fetch, compute stoppedTrainsSince
  Map->>TrainsList: trains, stoppedTrainsSince
  TrainsList->>TrainMarker: stoppedSince (per train)
  TrainMarker->>TrainText: stoppedSince
  Map->>SelectedTrainPopup: stoppedSince (selected train)
  SelectedTrainPopup->>TrainText: stoppedSince
  TrainText->>TrainText: compute stoppedSeconds, render formatted duration
Loading

Related PRs: None identified.

Suggested labels: enhancement

Suggested reviewers: None identified.

🐰 A train stands still, the clock ticks on,
Seconds to minutes, then hours drawn,
A key derived from id or line,
Whispers through props, a duration sign,
Stopped, but tracked — the map hums fine.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: displaying how long trains have been stopped.
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 unit tests (beta)
  • Create PR with unit tests

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: 2

🤖 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 `@packages/map/components/Map.tsx`:
- Around line 46-47: The train stop key logic is duplicated in Map.tsx and
TrainsList.tsx, which can cause the stoppedTrainsSince lookup to drift if one
copy changes. Extract the shared getTrainStopKey helper into a common utility
module and import it from both Map and TrainsList so the key used to build and
read the stoppedTrainsSince map stays consistent.
- Around line 83-109: The stopped-train tracking in getTrains currently rebuilds
stoppedTrainsSince only from the latest trainsData, so a train can lose its
original stop timestamp if it is briefly missing or its key changes. Update the
stopped-train merge logic inside setStoppedTrainsSince to preserve the existing
timestamp for any train that was already stopped and is still considered
stopped, and only remove/reset entries when the train is seen moving again. Use
getTrainStopKey, trainsData, and previousStoppedTrainsSince to keep the identity
stable across polls.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8ae57de6-d3c0-4e7e-9269-38c8010e956f

📥 Commits

Reviewing files that changed from the base of the PR and between edca613 and 89c5c73.

📒 Files selected for processing (5)
  • packages/map/components/Map.tsx
  • packages/map/components/Markers/TrainMarker.tsx
  • packages/map/components/SelectedTrainPopup.tsx
  • packages/map/components/TrainText.tsx
  • packages/map/components/TrainsList.tsx

Comment on lines +46 to +47
const getTrainStopKey = (train: Train) => train.id ?? train.TrainNoLocal;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Duplicate getTrainStopKey implementation across files.

The exact same helper is redefined independently in packages/map/components/TrainsList.tsx (const getTrainStopKey = (train: Train) => train.id ?? train.TrainNoLocal;). Since TrainsList looks up entries in the stoppedTrainsSince map produced here using its own copy of this key function, any future edit to one copy without the other will silently desynchronize the lookup key and break the stopped-duration feature.

Extract this into a shared module (e.g. packages/map/utils/trains.ts) and import it in both files.

♻️ Proposed fix
+// packages/map/utils/trains.ts
+import type { Train } from "`@simrail/types`";
+
+export const getTrainStopKey = (train: Train) => train.id ?? train.TrainNoLocal;
-const getTrainStopKey = (train: Train) => train.id ?? train.TrainNoLocal;
+import { getTrainStopKey } from "../utils/trains";
🤖 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 `@packages/map/components/Map.tsx` around lines 46 - 47, The train stop key
logic is duplicated in Map.tsx and TrainsList.tsx, which can cause the
stoppedTrainsSince lookup to drift if one copy changes. Extract the shared
getTrainStopKey helper into a common utility module and import it from both Map
and TrainsList so the key used to build and read the stoppedTrainsSince map
stays consistent.

Comment on lines +83 to +109
const [stoppedTrainsSince, setStoppedTrainsSince] = useState<
Record<string, number>
>({});

const getTrains = useCallback(() => {
fetch(`https://panel.simrail.eu:8084/trains-open?serverCode=${serverId}`)
.then((res) => res.json())
.then((fetchedTrains) => {
setTrains(fetchedTrains.data);
const trainsData: Train[] = fetchedTrains.data;

setStoppedTrainsSince((previousStoppedTrainsSince) => {
const nextStoppedTrainsSince: Record<string, number> = {};

for (const train of trainsData) {
const trainKey = getTrainStopKey(train);
const isStopped = Math.round(train.TrainData.Velocity) === 0;

if (isStopped) {
nextStoppedTrainsSince[trainKey] =
previousStoppedTrainsSince[trainKey] ?? Date.now();
}
}

return nextStoppedTrainsSince;
});

setTrains(trainsData);

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Map.tsx slice =="
sed -n '1,220p' packages/map/components/Map.tsx

echo
echo "== Search getTrainStopKey =="
rg -n "getTrainStopKey|stoppedTrainsSince|setStoppedTrainsSince|TrainNoLocal|TrainData\.Velocity" packages/map -S

Repository: simrail/map-v2

Length of output: 8148


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Train type definition =="
rg -n "export type Train|type Train|interface Train" -S .

echo
echo "== stoppedSince consumers =="
sed -n '1,140p' packages/map/components/TrainsList.tsx
echo
sed -n '1,220p' packages/map/components/SelectedTrainPopup.tsx

Repository: simrail/map-v2

Length of output: 2626


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Search for Train id field usage in repo =="
rg -n "\.id\b|TrainNoLocal|ControlledBySteamID|TrainData" packages -S

echo
echo "== Look for local type re-exports or docs around `@simrail/types` =="
rg -n "`@simrail/types`|Train =" packages -S

Repository: simrail/map-v2

Length of output: 6209


Preserve stopped timestamps across a missed pollnextStoppedTrainsSince rebuilds from only trainsData, so a still-stopped train loses its elapsed time if one response omits it or if its key switches between id and TrainNoLocal. Keep the previous timestamp until the train is seen moving.

🤖 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 `@packages/map/components/Map.tsx` around lines 83 - 109, The stopped-train
tracking in getTrains currently rebuilds stoppedTrainsSince only from the latest
trainsData, so a train can lose its original stop timestamp if it is briefly
missing or its key changes. Update the stopped-train merge logic inside
setStoppedTrainsSince to preserve the existing timestamp for any train that was
already stopped and is still considered stopped, and only remove/reset entries
when the train is seen moving again. Use getTrainStopKey, trainsData, and
previousStoppedTrainsSince to keep the identity stable across polls.

@Julian-Louis Julian-Louis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you !

@Julian-Louis Julian-Louis merged commit d73d53c into simrail:main Jul 5, 2026
2 checks passed
@Over441 Over441 deleted the Countdown-stop-train branch July 6, 2026 11:28
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.

2 participants