Compare commits
8 Commits
1c99c5ca47
...
main
Author | SHA1 | Date | |
---|---|---|---|
0a5bec6c4b
|
|||
6389406744
|
|||
41441a7803
|
|||
f0964d8fb7
|
|||
e58ad34e43
|
|||
af61173e9d
|
|||
2e5b5970a9
|
|||
ec9ac8d7ab
|
11141
package-lock.json
generated
11141
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@@ -3,25 +3,29 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.11.3",
|
"@emotion/react": "^11.13.3",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.13.0",
|
||||||
"@mui/icons-material": "^5.15.17",
|
"@mapbox/polyline": "^1.2.1",
|
||||||
"@mui/material": "^5.15.6",
|
"@mui/icons-material": "^6.1.6",
|
||||||
"@mui/x-date-pickers": "^6.19.2",
|
"@mui/material": "^6.1.6",
|
||||||
"@tanstack/query-sync-storage-persister": "^5.18.0",
|
"@mui/x-date-pickers": "^7.22.2",
|
||||||
"@tanstack/react-query": "^5.18.0",
|
"@tanstack/react-query": "^5.59.20",
|
||||||
"@tanstack/react-query-persist-client": "^5.18.0",
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
"@testing-library/jest-dom": "^5.17.0",
|
"@testing-library/react": "^16.0.1",
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/user-event": "^14.5.2",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@turf/rhumb-bearing": "^7.1.0",
|
||||||
"dayjs": "^1.11.10",
|
"@turf/rhumb-distance": "^7.1.0",
|
||||||
"react": "^18.2.0",
|
"@types/leaflet": "^1.9.14",
|
||||||
"react-dom": "^18.2.0",
|
"dayjs": "^1.11.13",
|
||||||
"react-router-dom": "^6.21.3",
|
"leaflet": "^1.9.4",
|
||||||
"react-scripts": "5.0.1",
|
"react": "^18.3.1",
|
||||||
|
"react-dom": "^18.3.1",
|
||||||
|
"react-leaflet": "^4.2.1",
|
||||||
|
"react-router-dom": "^6.28.0",
|
||||||
|
"react-scripts": "^5.0.1",
|
||||||
"react-transition-group": "^4.4.5",
|
"react-transition-group": "^4.4.5",
|
||||||
"sass": "^1.70.0",
|
"sass": "^1.80.6",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^4.2.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
@@ -2,12 +2,13 @@ import {createBrowserRouter, RouterProvider} from "react-router-dom"
|
|||||||
import Station from "./Station"
|
import Station from "./Station"
|
||||||
import {createTheme, CssBaseline, ThemeProvider, useMediaQuery} from "@mui/material"
|
import {createTheme, CssBaseline, ThemeProvider, useMediaQuery} from "@mui/material"
|
||||||
import React, {useMemo} from "react"
|
import React, {useMemo} from "react"
|
||||||
import {frFR, LocalizationProvider} from "@mui/x-date-pickers"
|
import {LocalizationProvider} from "@mui/x-date-pickers"
|
||||||
import {AdapterDayjs} from "@mui/x-date-pickers/AdapterDayjs"
|
import {AdapterDayjs} from "@mui/x-date-pickers/AdapterDayjs"
|
||||||
import 'dayjs/locale/fr'
|
import 'dayjs/locale/fr'
|
||||||
import './App.css'
|
import './App.css'
|
||||||
import {QueryClient, QueryClientProvider} from "@tanstack/react-query"
|
import {QueryClient, QueryClientProvider} from "@tanstack/react-query"
|
||||||
import Home from "./Home"
|
import Home from "./Home"
|
||||||
|
import TrainMap from "./Map"
|
||||||
import dayjs from "dayjs"
|
import dayjs from "dayjs"
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
@@ -19,6 +20,10 @@ function App() {
|
|||||||
{
|
{
|
||||||
path: "/station/:theme/:stationId",
|
path: "/station/:theme/:stationId",
|
||||||
element: <Station />
|
element: <Station />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/map",
|
||||||
|
element: <TrainMap />
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -58,7 +63,7 @@ function App() {
|
|||||||
return <>
|
return <>
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<CssBaseline />
|
<CssBaseline />
|
||||||
<LocalizationProvider dateAdapter={AdapterDayjs} localeText={frFR.components.MuiLocalizationProvider.defaultProps.localeText} adapterLocale="fr">
|
<LocalizationProvider dateAdapter={AdapterDayjs} adapterLocale="fr">
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<RouterProvider router={router} />
|
<RouterProvider router={router} />
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
|
194
src/Map.js
Normal file
194
src/Map.js
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
import "leaflet/dist/leaflet.css"
|
||||||
|
import L from 'leaflet'
|
||||||
|
import {MapContainer, Marker, TileLayer, useMapEvents} from 'react-leaflet'
|
||||||
|
import {useEffect, useMemo, useState} from "react"
|
||||||
|
import dayjs from "dayjs"
|
||||||
|
import polyline from "@mapbox/polyline"
|
||||||
|
import getDistance from '@turf/rhumb-distance'
|
||||||
|
import getBearing from '@turf/rhumb-bearing'
|
||||||
|
|
||||||
|
export default function TrainMap () {
|
||||||
|
return <>
|
||||||
|
<MapContainer center={[46.47, 2.37]} zoom={6} style={{height: "100vh"}}>
|
||||||
|
<TileLayer
|
||||||
|
attribution='Données cartographiques : © Les contributeurices <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||||
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||||
|
/>
|
||||||
|
<TileLayer
|
||||||
|
attribution="Rendu : OpenRailwayMap"
|
||||||
|
url="https://{s}.tiles.openrailwaymap.org/standard/{z}/{x}/{y}.png"></TileLayer>
|
||||||
|
|
||||||
|
<MapContent />
|
||||||
|
</MapContainer>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
function MapContent () {
|
||||||
|
const [latitude, setLatitude] = useState(46.47)
|
||||||
|
const [longitude, setLongitude] = useState(2.37)
|
||||||
|
const [zoom, setZoom] = useState(6)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch(`${process.env.REACT_APP_MOTIS_SERVER}/api/v1/map/initial`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
setLatitude(data['lat'])
|
||||||
|
setLongitude(data['lon'])
|
||||||
|
setZoom(data['zoom'])
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const map = useMapEvents({
|
||||||
|
moveend: () => {
|
||||||
|
updateTrips(map, setTrips)
|
||||||
|
},
|
||||||
|
zoomend: () => {
|
||||||
|
updateTrips(map, setTrips)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
map.flyTo([latitude, longitude], zoom)
|
||||||
|
}, [map, latitude, longitude, zoom])
|
||||||
|
|
||||||
|
const [trips, setTrips] = useState([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
updateTrips(map, setTrips)
|
||||||
|
setInterval(() => updateTrips(map, setTrips), 30000)
|
||||||
|
}, [map])
|
||||||
|
|
||||||
|
return <>
|
||||||
|
{trips.map(trip => <TripMarker trip={trip} />)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
function TripMarker ({trip}) {
|
||||||
|
const [position, setPosition] = useState([trip.from.lat, trip.from.lon])
|
||||||
|
const [heading, setHeading] = useState(0)
|
||||||
|
const style = getModeStyle(trip.mode)
|
||||||
|
|
||||||
|
const keyframes = useMemo(() => {
|
||||||
|
const keyframes = []
|
||||||
|
const departure = dayjs(trip.departure)
|
||||||
|
const arrival = dayjs(trip.arrival)
|
||||||
|
const coordinates = polyline.decode(trip.polyline)
|
||||||
|
const totalDuration = arrival.diff(departure, 'seconds')
|
||||||
|
let currDistance = 0
|
||||||
|
|
||||||
|
let totalDistance = 0
|
||||||
|
for (let i = 0; i < coordinates.length - 1; i++) {
|
||||||
|
let from = coordinates[i]
|
||||||
|
let to = coordinates[i + 1]
|
||||||
|
totalDistance += getDistance(from, to, { units: 'meters' })
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < coordinates.length - 1; i++) {
|
||||||
|
let from = coordinates[i]
|
||||||
|
let to = coordinates[i + 1]
|
||||||
|
|
||||||
|
const distance = getDistance(from, to, { units: 'meters' })
|
||||||
|
const heading = getBearing(from, to)
|
||||||
|
|
||||||
|
const r = currDistance / totalDistance
|
||||||
|
keyframes.push({ point: from, time: departure.add(r * totalDuration, 'seconds'), heading: heading })
|
||||||
|
|
||||||
|
currDistance += distance
|
||||||
|
}
|
||||||
|
keyframes.push({ point: coordinates[coordinates.length - 1], time: arrival, heading: 0 })
|
||||||
|
|
||||||
|
return keyframes
|
||||||
|
}, [trip])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
const now = dayjs()
|
||||||
|
const index = keyframes.findIndex((kf) => kf.time >= now)
|
||||||
|
if (index === -1 || index === 0)
|
||||||
|
return
|
||||||
|
|
||||||
|
const startState = keyframes[index - 1]
|
||||||
|
const endState = keyframes[index]
|
||||||
|
const r = (now.diff(startState.time)) / (endState.time.diff(startState.time))
|
||||||
|
const lat = startState.point[0] * (1 - r) + endState.point[0] * r
|
||||||
|
const lon = startState.point[1] * (1 - r) + endState.point[1] * r
|
||||||
|
setPosition([lat, lon])
|
||||||
|
setHeading(startState.heading)
|
||||||
|
}, 100)
|
||||||
|
return () => clearInterval(interval)
|
||||||
|
}, [keyframes])
|
||||||
|
const icon = L.divIcon({
|
||||||
|
html: `<svg fill="${style[1]}" fill-opacity="0.8" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
\t width="36px" height="36px" viewBox="0 0 512 512" xml:space="preserve">
|
||||||
|
<g transform="rotate(${-heading - 90}, 256, 256)">
|
||||||
|
\t<path d="M256 17.108c-75.73 0-137.122 61.392-137.122 137.122.055 23.25 6.022 46.107 11.58 56.262L256 494.892l119.982-274.244h-.063c11.27-20.324 17.188-43.18 17.202-66.418C393.122 78.5 331.73 17.108 256 17.108zm0 68.56a68.56 68.56 0 0 1 68.56 68.562A68.56 68.56 0 0 1 256 222.79a68.56 68.56 0 0 1-68.56-68.56A68.56 68.56 0 0 1 256 85.67z" />
|
||||||
|
</g>
|
||||||
|
</svg>`,
|
||||||
|
className: "",
|
||||||
|
iconSize: [36, 36],
|
||||||
|
iconAnchor: [36, 36],
|
||||||
|
})
|
||||||
|
return <Marker position={position} icon={icon} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function getModeStyle (mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case 'WALK':
|
||||||
|
case 'FLEXIBLE':
|
||||||
|
return ['walk', 'hsl(var(--foreground) / 1)', 'hsl(var(--background) / 1)']
|
||||||
|
case 'BIKE':
|
||||||
|
case 'BIKE_TO_PARK':
|
||||||
|
case 'BIKE_RENTAL':
|
||||||
|
case 'SCOOTER_RENTAL':
|
||||||
|
return ['bike', '#075985', 'white']
|
||||||
|
case 'CAR':
|
||||||
|
case 'CAR_TO_PARK':
|
||||||
|
case 'CAR_HAILING':
|
||||||
|
case 'CAR_SHARING':
|
||||||
|
case 'CAR_PICKUP':
|
||||||
|
case 'CAR_RENTAL':
|
||||||
|
return ['car', '#333', 'white']
|
||||||
|
case 'TRANSIT':
|
||||||
|
case 'BUS':
|
||||||
|
return ['bus', '#ff9800', 'white']
|
||||||
|
case 'COACH':
|
||||||
|
return ['bus', '#9ccc65', 'white']
|
||||||
|
case 'TRAM':
|
||||||
|
return ['tram', '#ff9800', 'white']
|
||||||
|
case 'METRO':
|
||||||
|
return ['sbahn', '#4caf50', 'white']
|
||||||
|
case 'SUBWAY':
|
||||||
|
return ['ubahn', '#3f51b5', 'white']
|
||||||
|
case 'FERRY':
|
||||||
|
return ['ship', '#00acc1', 'white']
|
||||||
|
case 'AIRPLANE':
|
||||||
|
return ['plane', '#90a4ae', 'white']
|
||||||
|
case 'HIGHSPEED_RAIL':
|
||||||
|
return ['train', '#9c27b0', 'white']
|
||||||
|
case 'LONG_DISTANCE':
|
||||||
|
return ['train', '#e91e63', 'white']
|
||||||
|
case 'NIGHT_RAIL':
|
||||||
|
return ['train', '#1a237e', 'white']
|
||||||
|
case 'REGIONAL_FAST_RAIL':
|
||||||
|
case 'REGIONAL_RAIL':
|
||||||
|
case 'RAIL':
|
||||||
|
return ['train', '#f44336', 'white']
|
||||||
|
}
|
||||||
|
return ['train', '#000000', 'white']
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTrips(map, setTrips) {
|
||||||
|
const bounds = map.getBounds()
|
||||||
|
const now = dayjs()
|
||||||
|
const now_plus_1_min = now.add(60000)
|
||||||
|
const query_params = new URLSearchParams({
|
||||||
|
min: `${bounds.getNorth()},${bounds.getWest()}`,
|
||||||
|
max: `${bounds.getSouth()},${bounds.getEast()}`,
|
||||||
|
zoom: map.getZoom(),
|
||||||
|
startTime: now.format(),
|
||||||
|
endTime: now_plus_1_min.format(),
|
||||||
|
}).toString()
|
||||||
|
fetch(`${process.env.REACT_APP_MOTIS_SERVER}/api/v1/map/trips?${query_params}`)
|
||||||
|
.then(data => data.json())
|
||||||
|
.then(setTrips)
|
||||||
|
}
|
@@ -1,14 +1,13 @@
|
|||||||
import {useNavigate, useParams, useSearchParams} from "react-router-dom"
|
import {useNavigate, useParams, useSearchParams} from "react-router-dom"
|
||||||
import TrainsTable from "./TrainsTable"
|
import TrainsTable from "./TrainsTable"
|
||||||
import TripsFilter from "./TripsFilter"
|
import {useEffect, useState} from "react"
|
||||||
import {useState} from "react"
|
import {Box, Checkbox, FormLabel} from "@mui/material"
|
||||||
import {Box, Button, FormLabel} from "@mui/material"
|
|
||||||
import {DateTimePicker} from "@mui/x-date-pickers"
|
import {DateTimePicker} from "@mui/x-date-pickers"
|
||||||
import dayjs from "dayjs"
|
import dayjs from "dayjs"
|
||||||
import {useQuery, useQueryClient} from "@tanstack/react-query"
|
import {useQuery, useQueryClient} from "@tanstack/react-query"
|
||||||
import AutocompleteStation from "./AutocompleteStation"
|
import AutocompleteStation from "./AutocompleteStation"
|
||||||
|
|
||||||
function DateTimeSelector({datetime, setDatetime}) {
|
function DateTimeSelector({datetime, setDatetime, realtime, setRealtime}) {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
function onStationSelected(event, station) {
|
function onStationSelected(event, station) {
|
||||||
@@ -18,15 +17,18 @@ function DateTimeSelector({datetime, setDatetime}) {
|
|||||||
|
|
||||||
return <>
|
return <>
|
||||||
<Box component="form" display="flex" alignItems="center" sx={{'& .MuiTextField-root': { m: 1, width: '25ch' },}}>
|
<Box component="form" display="flex" alignItems="center" sx={{'& .MuiTextField-root': { m: 1, width: '25ch' },}}>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
Changer la gare recherchée :
|
Changer la gare recherchée :
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<AutocompleteStation onChange={onStationSelected} />
|
<AutocompleteStation onChange={onStationSelected} />
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
Modifier la date et l'heure de recherche :
|
Modifier la date et l'heure de recherche :
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<DateTimePicker name="date" label="Date" onChange={setDatetime} value={datetime} />
|
<DateTimePicker name="date" label="Date" onChange={setDatetime} value={datetime} disabled={realtime} readOnly={realtime} />
|
||||||
<Button type="submit">Rechercher</Button>
|
<Checkbox onChange={event => setRealtime(event.target.checked)} checked={realtime} />
|
||||||
|
<FormLabel>
|
||||||
|
Temps réel
|
||||||
|
</FormLabel>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
@@ -36,7 +38,20 @@ function Station() {
|
|||||||
let {theme, stationId} = useParams()
|
let {theme, stationId} = useParams()
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
let [searchParams, setSearchParams] = useSearchParams()
|
let [searchParams, setSearchParams] = useSearchParams()
|
||||||
const [datetime, setDatetime] = useState(dayjs())
|
const [realtime, setRealtime] = useState(searchParams.get('realtime') === "1" || false)
|
||||||
|
const [datetime, setDatetime] = useState(dayjs(searchParams.get('time') || undefined))
|
||||||
|
if ((searchParams.get('realtime') === null || searchParams.get('realtime') === "0")
|
||||||
|
&& (searchParams.get('time') === null || realtime)) {
|
||||||
|
searchParams.set('realtime', "1")
|
||||||
|
searchParams.delete("time")
|
||||||
|
setRealtime(true)
|
||||||
|
window.history.replaceState({}, '', '?' + searchParams.toString())
|
||||||
|
}
|
||||||
|
else if (datetime.format() !== searchParams.get('time') && !realtime) {
|
||||||
|
searchParams.set('time', datetime.format())
|
||||||
|
searchParams.set('realtime', "0")
|
||||||
|
window.history.replaceState({}, '', '?' + searchParams.toString())
|
||||||
|
}
|
||||||
|
|
||||||
useQueryClient()
|
useQueryClient()
|
||||||
const stationQuery = useQuery({
|
const stationQuery = useQuery({
|
||||||
@@ -47,11 +62,14 @@ function Station() {
|
|||||||
})
|
})
|
||||||
const station = stationQuery.data?.stopTimes[0].place ?? {name: "Chargement…"}
|
const station = stationQuery.data?.stopTimes[0].place ?? {name: "Chargement…"}
|
||||||
|
|
||||||
if (searchParams.get("time") === undefined) {
|
useEffect(() => {
|
||||||
setInterval(() => {
|
if (realtime) {
|
||||||
setDatetime(dayjs())
|
const interval = setInterval(() => {
|
||||||
}, 5000)
|
setDatetime(dayjs())
|
||||||
}
|
}, 5000)
|
||||||
|
return () => clearInterval(interval)
|
||||||
|
}
|
||||||
|
}, [realtime])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="Station">
|
<div className="Station">
|
||||||
@@ -60,10 +78,10 @@ function Station() {
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<DateTimeSelector datetime={datetime} setDatetime={setDatetime} />
|
<DateTimeSelector datetime={datetime} setDatetime={setDatetime} realtime={realtime} setRealtime={setRealtime} />
|
||||||
<TripsFilter />
|
{/*<TripsFilter />*/}
|
||||||
<TrainsTable station={station} datetime={datetime} tableType="departures" />
|
<TrainsTable station={station} datetime={datetime} realtime={realtime} tableType="departures" />
|
||||||
<TrainsTable station={station} datetime={datetime} tableType="arrivals" />
|
<TrainsTable station={station} datetime={datetime} realtime={realtime} tableType="arrivals" />
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@@ -27,12 +27,12 @@ const StyledTableRow = styled(TableRow)(({ theme, tabletype }) => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function TrainsTable({station, datetime, tableType}) {
|
function TrainsTable({station, datetime, realtime, tableType}) {
|
||||||
return <>
|
return <>
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
<Table>
|
<Table>
|
||||||
<TrainsTableHeader tableType={tableType} />
|
<TrainsTableHeader tableType={tableType} />
|
||||||
<TrainsTableBody station={station} datetime={datetime} tableType={tableType} />
|
<TrainsTableBody station={station} datetime={datetime} realtime={realtime} tableType={tableType} />
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
</>
|
</>
|
||||||
@@ -50,7 +50,7 @@ function TrainsTableHeader({tableType}) {
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
function TrainsTableBody({station, datetime, tableType}) {
|
function TrainsTableBody({station, datetime, realtime, tableType}) {
|
||||||
const filterTime = useCallback((train) => {
|
const filterTime = useCallback((train) => {
|
||||||
if (tableType === "departures")
|
if (tableType === "departures")
|
||||||
return dayjs(train.place.departure) >= datetime
|
return dayjs(train.place.departure) >= datetime
|
||||||
@@ -59,17 +59,20 @@ function TrainsTableBody({station, datetime, tableType}) {
|
|||||||
}, [datetime, tableType])
|
}, [datetime, tableType])
|
||||||
|
|
||||||
const updateTrains = useCallback(() => {
|
const updateTrains = useCallback(() => {
|
||||||
const query_params = new URLSearchParams({
|
const params = {
|
||||||
stopId: station.stopId,
|
stopId: station.stopId,
|
||||||
arriveBy: tableType === "arrivals",
|
arriveBy: tableType === "arrivals",
|
||||||
time: datetime.format(),
|
direction: "LATER",
|
||||||
n: 20,
|
n: 20,
|
||||||
}).toString()
|
}
|
||||||
|
if (!realtime)
|
||||||
|
params['time'] = datetime.format()
|
||||||
|
const query_params = new URLSearchParams(params).toString()
|
||||||
return fetch(`${process.env.REACT_APP_MOTIS_SERVER}/api/v1/stoptimes?${query_params}`)
|
return fetch(`${process.env.REACT_APP_MOTIS_SERVER}/api/v1/stoptimes?${query_params}`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => data.stopTimes)
|
.then(data => data.stopTimes)
|
||||||
.then(data => [...data])
|
.then(data => [...data])
|
||||||
}, [station.stopId, datetime, tableType])
|
}, [station.stopId, tableType, datetime, realtime])
|
||||||
|
|
||||||
const trainsQuery = useQuery({
|
const trainsQuery = useQuery({
|
||||||
queryKey: ['trains', station.stopId, tableType],
|
queryKey: ['trains', station.stopId, tableType],
|
||||||
@@ -79,10 +82,12 @@ function TrainsTableBody({station, datetime, tableType}) {
|
|||||||
const trains = useMemo(() => trainsQuery.data ?? [], [trainsQuery.data])
|
const trains = useMemo(() => trainsQuery.data ?? [], [trainsQuery.data])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let validTrains = trains?.filter(filterTime) ?? []
|
if (realtime) {
|
||||||
if (trains?.length > 0 && validTrains.length < trains?.length)
|
let validTrains = trains?.filter(filterTime) ?? []
|
||||||
trainsQuery.refetch().then()
|
if ((trains?.length > 0 && validTrains.length < trains?.length))
|
||||||
}, [trains, filterTime, trainsQuery])
|
trainsQuery.refetch().then()
|
||||||
|
}
|
||||||
|
}, [trains, filterTime, trainsQuery, realtime])
|
||||||
|
|
||||||
const nullRef = useRef(null)
|
const nullRef = useRef(null)
|
||||||
let table_rows = trains.map((train) => <CSSTransition key={train.id} timeout={500} classNames="shrink" nodeRef={nullRef}>
|
let table_rows = trains.map((train) => <CSSTransition key={train.id} timeout={500} classNames="shrink" nodeRef={nullRef}>
|
||||||
@@ -202,9 +207,13 @@ function getTrainType(train) {
|
|||||||
default:
|
default:
|
||||||
return trainType
|
return trainType
|
||||||
}
|
}
|
||||||
case "FR-IDF-IDFM":
|
case "FR-IDFM":
|
||||||
|
const route_split = train.routeShortName.split(" ")
|
||||||
|
if (route_split[0] === "Bus")
|
||||||
|
return route_split[1]
|
||||||
|
return route_split[0]
|
||||||
case "FR-GES-CTS":
|
case "FR-GES-CTS":
|
||||||
return "A"
|
return train.routeShortName.split(" ")[1]
|
||||||
case "FR-EUROSTAR":
|
case "FR-EUROSTAR":
|
||||||
return "Eurostar"
|
return "Eurostar"
|
||||||
case "IT-FRA-TI":
|
case "IT-FRA-TI":
|
||||||
@@ -216,7 +225,6 @@ function getTrainType(train) {
|
|||||||
return "NJ"
|
return "NJ"
|
||||||
return "ÖBB"
|
return "ÖBB"
|
||||||
case "CH-ALL":
|
case "CH-ALL":
|
||||||
return "A"
|
|
||||||
default:
|
default:
|
||||||
return train.routeShortName?.split(" ")[0]
|
return train.routeShortName?.split(" ")[0]
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user