Skip to content

Commit a5a7a5c

Browse files
committed
Added version system & changed grouped timetable view to only group by destination
1 parent 3756a83 commit a5a7a5c

File tree

10 files changed

+214
-89
lines changed

10 files changed

+214
-89
lines changed

smo-frontend/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,7 @@ dist-ssr
2525

2626
# Sentry Config File
2727
.env.sentry-build-plugin
28+
29+
# Auto-generated version files
30+
src/version.ts
31+
public/version.txt

smo-frontend/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"type": "module",
66
"scripts": {
77
"dev": "vite",
8-
"build": "tsc && vite build",
8+
"build": "yarn generate-version && tsc && vite build",
9+
"generate-version": "node scripts/generate-version.js",
910
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
1011
"preview": "vite preview"
1112
},
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { writeFileSync } from "node:fs";
2+
import { dirname, join } from "node:path";
3+
import { fileURLToPath } from "node:url";
4+
5+
const __filename = fileURLToPath(import.meta.url);
6+
const __dirname = dirname(__filename);
7+
8+
// Generate version number based on current date
9+
// Format: YYYY.MM.DD.HHMM
10+
const now = new Date();
11+
const year = now.getFullYear();
12+
const month = String(now.getMonth() + 1).padStart(2, "0");
13+
const day = String(now.getDate()).padStart(2, "0");
14+
const hours = String(now.getHours()).padStart(2, "0");
15+
const minutes = String(now.getMinutes()).padStart(2, "0");
16+
17+
const version = `${year}.${month}.${day}.${hours}${minutes}`;
18+
19+
// Generate version.ts file
20+
const versionTsContent = `// This file is auto-generated by scripts/generate-version.js
21+
// Do not edit manually
22+
23+
export const VERSION = "${version}";
24+
export const BUILD_DATE = "${now.toISOString()}";
25+
`;
26+
27+
// Generate version.txt file
28+
const versionTxtContent = version;
29+
30+
// Write files
31+
const srcDir = join(__dirname, "..", "src");
32+
const publicDir = join(__dirname, "..", "public");
33+
34+
try {
35+
writeFileSync(join(srcDir, "version.ts"), versionTsContent, "utf8");
36+
console.log(`✓ Generated src/version.ts with version ${version}`);
37+
38+
writeFileSync(join(publicDir, "version.txt"), versionTxtContent, "utf8");
39+
console.log(`✓ Generated public/version.txt with version ${version}`);
40+
} catch (error) {
41+
console.error("Error generating version files:", error);
42+
throw error;
43+
}

smo-frontend/src/assets/translations.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,12 @@
251251
"GotIt": "Got it!",
252252
"TurnOff": "Turn off"
253253
},
254+
"VersionCheck": {
255+
"UpdateAvailable": "Update Available",
256+
"UpdateMessage": "A new version is available. Current: {{current}}, Latest: {{latest}}. Please refresh to get the latest version.",
257+
"RefreshNow": "Refresh Now",
258+
"RefreshDescription": "Refreshing the page will load the latest version of the application. If you experience any issues after refreshing, try clearing your browser cache."
259+
},
254260
"TrainTypes": {
255261
"Main": {
256262
"EC": "EuroCity train",
@@ -593,6 +599,12 @@
593599
"GotIt": "Verstanden!",
594600
"TurnOff": "Ausschalten"
595601
},
602+
"VersionCheck": {
603+
"UpdateAvailable": "Update verfügbar",
604+
"UpdateMessage": "Eine neue Version ist verfügbar. Aktuell: {{current}}, Neueste: {{latest}}. Bitte aktualisieren Sie, um die neueste Version zu erhalten.",
605+
"RefreshNow": "Jetzt aktualisieren",
606+
"RefreshDescription": "Das Aktualisieren der Seite lädt die neueste Version der Anwendung. Wenn Sie nach dem Aktualisieren Probleme haben, versuchen Sie, den Cache Ihres Browsers zu leeren."
607+
},
596608
"TrainTypes": {
597609
"Main": {
598610
"EC": "EuroCity-Zug",
@@ -936,6 +948,12 @@
936948
"GotIt": "Értem!",
937949
"TurnOff": "Kikapcsolás"
938950
},
951+
"VersionCheck": {
952+
"UpdateAvailable": "Frissítés elérhető",
953+
"UpdateMessage": "Új verzió érhető el. Jelenlegi: {{current}}, Legújabb: {{latest}}. Kérjük, frissítsen a legújabb verzió megszerzéséhez.",
954+
"RefreshNow": "Frissítés most",
955+
"RefreshDescription": "Az oldal frissítésével a legújabb verziót tölti be. Ha frissítés után problémái vannak, próbálja meg törölni a böngésző gyorsítótárát."
956+
},
939957
"TrainTypes": {
940958
"Main": {
941959
"EC": "EuroCity vonat",
@@ -1283,6 +1301,12 @@
12831301
"GotIt": "Anladım!",
12841302
"TurnOff": "Kapat"
12851303
},
1304+
"VersionCheck": {
1305+
"UpdateAvailable": "Güncelleme Mevcut",
1306+
"UpdateMessage": "Yeni bir sürüm mevcut. Mevcut: {{current}}, En son: {{latest}}. Lütfen en son sürümü almak için yenileyin.",
1307+
"RefreshNow": "Şimdi Yenile",
1308+
"RefreshDescription": "Sayfayı yenileyerek en son sürümü yüklersiniz. Yenileme sonrası sorun yaşarsanız, tarayıcı önbelleğinizi temizlemeyi deneyin."
1309+
},
12861310
"TrainTypes": {
12871311
"Main": {
12881312
"EC": "EuroCity treni",
@@ -1628,6 +1652,12 @@
16281652
"GotIt": "Rozumiem!",
16291653
"TurnOff": "Wyłącz"
16301654
},
1655+
"VersionCheck": {
1656+
"UpdateAvailable": "Dostępna aktualizacja",
1657+
"UpdateMessage": "Dostępna jest nowa wersja. Obecna: {{current}}, Najnowsza: {{latest}}. Odśwież stronę, aby uzyskać najnowszą wersję.",
1658+
"RefreshNow": "Odśwież teraz",
1659+
"RefreshDescription": "Odświeżenie strony załaduje najnowszą wersję aplikacji. Jeśli po odświeżeniu wystąpią jakiekolwiek problemy, spróbuj wyczyścić pamięć podręczną przeglądarki."
1660+
},
16311661
"TrainTypes": {
16321662
"Main": {
16331663
"EC": "Pociąg EuroCity",

smo-frontend/src/components/MainMap.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { goToSignal } from "../utils/geom-utils";
1616
import MapLinesContext from "../utils/map-lines-context";
1717
import SelectedRouteContext from "../utils/selected-route-context";
1818
import SelectedTrainContext from "../utils/selected-train-context";
19+
import { VERSION } from "../version";
1920
import AutoZoomHandler from "./AutoZoom";
2021
import BackgroundUpdatesNotification from "./BackgroundUpdatesNotification";
2122
import ErrorBoundary from "./ErrorBoundary";
@@ -32,6 +33,7 @@ import StatsDisplay from "./StatsDisplay";
3233
import ServerTrainListModal from "./trains/ServerTrainListModal";
3334
import RefreshableTileLayer from "./utils/RefreshableTileLayer";
3435
import ThemeToggle from "./utils/ThemeToggle";
36+
import VersionCheck from "./VersionCheck";
3537

3638
const ActiveSignalsLayer = lazy(() => import("./layers/ActiveSignalsLayer"));
3739
const MapLinesLayer = lazy(() => import("./layers/MapLinesLayer"));
@@ -95,7 +97,7 @@ const MainMap: FunctionComponent = () => {
9597
() =>
9698
[
9799
'&copy; <a href="http://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>',
98-
'<a href="https://github.com/GNimrodG/simrail-map-optimized" target="_blank">GitHub</a>',
100+
`<a href="https://github.com/GNimrodG/simrail-map-optimized" target="_blank">GitHub</a> (v${VERSION})`,
99101
// eslint-disable-next-line @typescript-eslint/no-explicit-any
100102
(window as any).feedback && `<a onclick="window.feedback()" href="#">${t("BugReport")}</a>`,
101103
`<a href="/privacy-policy.html" target="_blank">${t("PrivacyPolicy.Title")}</a>`,
@@ -132,6 +134,7 @@ const MainMap: FunctionComponent = () => {
132134
return (
133135
<>
134136
{!isConnected && <Loading />}
137+
<VersionCheck />
135138
<MapContainer
136139
ref={setMap}
137140
center={[51.015482, 19.572143]}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import Button from "@mui/joy/Button";
2+
import Sheet from "@mui/joy/Sheet";
3+
import Stack from "@mui/joy/Stack";
4+
import Typography from "@mui/joy/Typography";
5+
import { type FunctionComponent } from "react";
6+
import { useTranslation } from "react-i18next";
7+
8+
import { useVersionCheck } from "../hooks/useVersionCheck";
9+
10+
const VersionCheck: FunctionComponent = () => {
11+
const { t } = useTranslation();
12+
const { isOutdated, currentVersion, latestVersion } = useVersionCheck();
13+
14+
if (!isOutdated) {
15+
return null;
16+
}
17+
18+
const handleRefresh = () => {
19+
globalThis.location.reload();
20+
};
21+
22+
return (
23+
<Sheet
24+
sx={{
25+
position: "fixed",
26+
top: "50%",
27+
left: "50%",
28+
transform: "translate(-50%, -50%)",
29+
zIndex: 10000,
30+
p: 3,
31+
borderRadius: "md",
32+
boxShadow: "lg",
33+
maxWidth: 400,
34+
}}
35+
variant="outlined"
36+
color="warning">
37+
<Stack spacing={2}>
38+
<Typography level="h4" color="warning">
39+
{t("VersionCheck.UpdateAvailable")}
40+
</Typography>
41+
<Typography level="body-md">
42+
{t("VersionCheck.UpdateMessage", {
43+
current: currentVersion,
44+
latest: latestVersion,
45+
})}
46+
</Typography>
47+
<Button onClick={handleRefresh} color="warning">
48+
{t("VersionCheck.RefreshNow")}
49+
</Button>
50+
<Typography level="body-xs">{t("VersionCheck.RefreshDescription")}</Typography>
51+
</Stack>
52+
</Sheet>
53+
);
54+
};
55+
56+
export default VersionCheck;

smo-frontend/src/components/timetable/StationTimetableDisplay.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import Chip from "@mui/joy/Chip";
33
import Sheet from "@mui/joy/Sheet";
44
import Stack from "@mui/joy/Stack";
5+
import moment from "moment";
56
import { type FunctionComponent, useCallback, useContext, useEffect, useMemo, useState } from "react";
67
import { useTranslation } from "react-i18next";
78
import { useMap } from "react-leaflet";
@@ -23,6 +24,7 @@ import StationTimetableTableView from "./StationTimetableTableView";
2324
export interface StationTimetableDisplayProps {
2425
timetable: SimplifiedTimtableEntry[];
2526
onClose?: () => void;
27+
isCollapsed?: boolean;
2628
}
2729

2830
const BUFFER_TIME = 30 * 60 * 1000; // 30 minutes in milliseconds
@@ -64,7 +66,11 @@ function isTrainAtPrevStation(
6466
);
6567
}
6668

67-
const StationTimetableDisplay: FunctionComponent<StationTimetableDisplayProps> = ({ timetable, onClose }) => {
69+
const StationTimetableDisplay: FunctionComponent<StationTimetableDisplayProps> = ({
70+
timetable,
71+
onClose,
72+
isCollapsed,
73+
}) => {
6874
const map = useMap();
6975
const { setSelectedTrain } = useContext(SelectedTrainContext);
7076
const { t: tSettings } = useTranslation("translation", {
@@ -187,7 +193,8 @@ const StationTimetableDisplay: FunctionComponent<StationTimetableDisplayProps> =
187193
!!train?.TrainData.SignalInFront &&
188194
train.TrainData.DistanceToSignalInFront < 2000 &&
189195
localStationNames.has(findStationForSignal(train.TrainData.SignalInFront.split("@")[0])?.Name ?? "") &&
190-
train.TrainData.VDDelayedTimetableIndex >= minIndex;
196+
(train.TrainData.VDDelayedTimetableIndex >= minIndex ||
197+
indexes.includes(train.TrainData.VDDelayedTimetableIndex));
191198

192199
const isCurrentStationTheNextStation =
193200
isTrainAtPrevStation(train, entry, trainDelays) ||
@@ -224,7 +231,11 @@ const StationTimetableDisplay: FunctionComponent<StationTimetableDisplayProps> =
224231
(line, index, arr) => index === 0 || line !== arr[index - 1],
225232
);
226233

227-
const shouldLeave = isInsideStation && passedBasedOnDepartureTime && !!train && train.TrainData.Velocity < 5;
234+
const shouldLeave =
235+
isInsideStation &&
236+
isPastStation(entry, moment(currentTime).add(1, "minute").toDate()) &&
237+
!!train &&
238+
train.TrainData.SignalInFrontSpeed === 0;
228239

229240
return {
230241
entry,
@@ -307,7 +318,7 @@ const StationTimetableDisplay: FunctionComponent<StationTimetableDisplayProps> =
307318
<StationTimetableCardsView entryStates={entryStates} onPanToTrain={panToTrain} />
308319
)}
309320
{activeViewMode === "grouped" && (
310-
<StationTimetableGroupedView entryStates={entryStates} onPanToTrain={panToTrain} />
321+
<StationTimetableGroupedView entryStates={entryStates} onPanToTrain={panToTrain} isCollapsed={isCollapsed} />
311322
)}
312323
</Sheet>
313324
</Stack>

0 commit comments

Comments
 (0)