Skip to content

Commit

Permalink
fix(backend): improve loading of tracks
Browse files Browse the repository at this point in the history
  • Loading branch information
devshred committed Jun 19, 2024
1 parent 4e631a5 commit d945a53
Show file tree
Hide file tree
Showing 4 changed files with 337 additions and 83 deletions.
102 changes: 20 additions & 82 deletions src/routes/track/-screens/TrackScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
import { useParams } from '@tanstack/react-router'
import { useEffect, useState } from 'react'
import API from '../../../services/backend/gps-backend-api'
import { FeatureCollection, LineString, Point } from 'geojson'
import { PoiType, WayPoint } from '../../../@types/gps'
import { v4 as uuidv4 } from 'uuid'
import { LatLngBoundsExpression, LatLngExpression, LatLngTuple } from 'leaflet'
import { generateFeatureCollection, sanitizeFilename } from '../../../utils/tools'
import { WayPoint } from '../../../@types/gps'
import { LatLngBoundsExpression, LatLngExpression } from 'leaflet'
import { generateFeatureCollection } from '../../../utils/tools'
import VisualizeTrack from '../-components/VisualizeTrack'
import TrackHeader from '../-components/TrackHeader'
import { useFeedbackContext } from '../../../hooks/useFeedbackContext'
import useLanguage from '../../../hooks/useLanguage'
import { useThrottle } from '@uidotdev/usehooks'
import { BsEmojiDizzy } from 'react-icons/bs'
import { FaAngleRight } from 'react-icons/fa6'
import { useFetchTrack } from '../../../services/backend/trackService'
import { Loading } from 'react-daisyui'

const TrackScreen = () => {
const { trackId } = useParams({ from: '/track/$trackId' })

const { setError } = useFeedbackContext()
const { getMessage } = useLanguage()

const [isLoading, setIsLoading] = useState(true)
const [trackname, setTrackname] = useState<string>('')
const [showPolyline, setShowPolyline] = useState(true)
const [positions, setPositions] = useState<LatLngExpression[]>([])
Expand All @@ -30,6 +27,16 @@ const TrackScreen = () => {
[0, 0],
])

const { data: trackResult, isLoading, isError } = useFetchTrack(trackId)
useEffect(() => {
if (!isLoading && !isError && trackResult) {
setMarkerPositions(trackResult.markerPositions)
setPositions(trackResult.positions)
setBounds(trackResult.bounds)
setTrackname(trackResult.trackName)
}
}, [isLoading, isError, trackResult])

useEffect(() => {
const handleKeyPress = (event: KeyboardEvent) => {
if (
Expand Down Expand Up @@ -64,77 +71,6 @@ const TrackScreen = () => {
}
}, [])

useEffect(() => {
setIsLoading(true)
const config = {
headers: {
accept: 'application/geo+json',
},
}
API.get('/tracks/' + trackId, config)
.then((file) => {
const feat: FeatureCollection = file.data as FeatureCollection

const _markerPositions: WayPoint[] = feat.features
.filter((f) => f.geometry.type == 'Point')
.map((feat) => {
const point: Point = feat.geometry as Point
const type: PoiType = feat.properties?.type ?? 'GENERIC'

return {
id: uuidv4(),
position: [point.coordinates[0], point.coordinates[1]],
name: feat.properties?.name ?? 'unnamed',
type: type,
}
}) as WayPoint[]
setMarkerPositions(_markerPositions)

const _positions: LatLngTuple[] = feat.features
.filter((f) => f.geometry.type == 'LineString')
.flatMap((line) => (line.geometry as LineString).coordinates)
.map((position) => [position[1], position[0]]) as LatLngTuple[]
setPositions(_positions)

const lats = []
const lngs = []
for (let i = 0; i < _positions.length; i++) {
lats.push(_positions[i][0])
lngs.push(_positions[i][1])
}

const minlat = Math.min.apply(null, lats)
const maxlat = Math.max.apply(null, lats)
const minlng = Math.min.apply(null, lngs)
const maxlng = Math.max.apply(null, lngs)

const _bounds = [
[minlat, minlng],
[maxlat, maxlng],
] as LatLngBoundsExpression
setBounds(_bounds)

const lines = feat.features.filter((f) => f.geometry.type == 'LineString')
let trackName: string
if (lines?.[0]?.properties?.['name']) {
trackName = lines[0].properties['name']
} else {
trackName = 'unnamed'
}
setTrackname(sanitizeFilename(trackName))

setIsLoading(false)
})
.catch((error) => {
if (error.response?.status === 404) {
setError('error_track_not_found')
} else {
setError('error_loading_track')
}
setIsLoading(false)
})
}, [trackId])

const throttledMarkerPositions = useThrottle(markerPositions, 500)
useEffect(() => {
if (throttledMarkerPositions !== undefined && !isLoading) {
Expand Down Expand Up @@ -170,7 +106,9 @@ const TrackScreen = () => {
return (
<>
{isLoading ? (
<p>{getMessage('loading')}</p>
<div className="ml-2 md:ml-6 lg:ml-10 mt-8 text-base-content">
<Loading size="lg" />
</div>
) : positions.length > 0 && trackId !== undefined ? (
<div className="flex flex-col" style={{ height: '100%' }}>
<TrackHeader
Expand All @@ -197,15 +135,15 @@ const TrackScreen = () => {
{getMessage('track_not_found_headline')}
<BsEmojiDizzy className="ml-3" />
</h1>
<p className="mb-4 text-2xl font-light mt-8">
<div className="mb-4 text-2xl font-light mt-8">
{getMessage('track_not_found_text')}
<br />
{getMessage('not_found_back')}:
<a href="/">
<FaAngleRight className="inline" />
<div className="inline font-bold">GPS-Tools</div>
</a>
</p>
</div>
</div>
</>
)}
Expand Down
8 changes: 7 additions & 1 deletion src/services/backend/gps-backend-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ function fetchBackendVersion(): Promise<BackendVersion> {
}

export function useBackendVersion() {
return useQuery({ queryKey: ['backendVersion'], queryFn: fetchBackendVersion })
return useQuery({
queryKey: ['backendVersion'],
queryFn: fetchBackendVersion,
refetchOnWindowFocus: false,
refetchOnMount: false,
retry: 2,
})
}

export default backendApi
206 changes: 206 additions & 0 deletions src/services/backend/trackService.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import { describe, expect, it } from 'vitest'
import { LatLngTuple } from 'leaflet'
import { findBounds, findMarkerPositions, findPositions, findTrackName } from './trackService'
import { FeatureCollection } from 'geojson'

describe('process track', () => {
it('find marker positions', () => {
const featureCollection = {
features: [
{
geometry: {
coordinates: [1, 1],
type: 'Point',
},
properties: {
name: 'way point 1',
},
type: 'Feature',
},
{
geometry: {
coordinates: [
[3, 3],
[4, 4],
],
type: 'LineString',
},
properties: {},
type: 'Feature',
},
{
geometry: {
coordinates: [2, 2],
type: 'Point',
},
properties: {
id: 'someId',
name: 'way point 2',
type: 'FOOD',
},
type: 'Feature',
},
],
type: 'FeatureCollection',
} as FeatureCollection

const actual = findMarkerPositions(featureCollection)

expect(actual).toStrictEqual([
{
id: expect.any(String),
name: 'way point 1',
position: [1, 1],
type: 'GENERIC',
},
{
id: 'someId',
name: 'way point 2',
position: [2, 2],
type: 'FOOD',
},
])
})

it('find marker positions, create missing id', () => {
const featureCollection = {
features: [
{
geometry: {
coordinates: [1, 1],
type: 'Point',
},
properties: {
name: 'way point 1',
type: 'SUMMIT',
},
type: 'Feature',
},
],
type: 'FeatureCollection',
} as FeatureCollection

const actual = findMarkerPositions(featureCollection)

expect(actual).toStrictEqual([
{
id: expect.any(String),
name: 'way point 1',
position: [1, 1],
type: 'SUMMIT',
},
])
})

it('find marker positions, set default type', () => {
const featureCollection = {
features: [
{
geometry: {
coordinates: [1, 1],
type: 'Point',
},
properties: {
name: 'way point 1',
},
type: 'Feature',
},
],
type: 'FeatureCollection',
} as FeatureCollection

const actual = findMarkerPositions(featureCollection)

expect(actual).toStrictEqual([
{
id: expect.any(String),
name: 'way point 1',
position: [1, 1],
type: 'GENERIC',
},
])
})

it('find positions', () => {
const featureCollection = {
features: [
{
geometry: {
coordinates: [
[1, 1],
[2, 2],
],
type: 'LineString',
},
properties: {},
type: 'Feature',
},
{
geometry: {
coordinates: [
[3, 3],
[4, 4],
],
type: 'LineString',
},
properties: {},
type: 'Feature',
},
],
type: 'FeatureCollection',
} as FeatureCollection

const actual = findPositions(featureCollection)

expect(actual).toStrictEqual([
[1, 1],
[2, 2],
[3, 3],
[4, 4],
])
})

it('find bounds', () => {
const positions = [
[1, 3],
[3, 5],
[5, 2],
[4, 1],
[2, 4],
] as LatLngTuple[]

const actual = findBounds(positions)

expect(actual).toStrictEqual([
[1, 1],
[5, 5],
])
})

it('find track name', () => {
const trackName = 'track name'

const featureCollection = {
features: [
{
geometry: {
coordinates: [
[1, 1],
[5, 5],
],
type: 'LineString',
},
properties: {
name: trackName,
},
type: 'Feature',
},
],
type: 'FeatureCollection',
} as FeatureCollection

const actual = findTrackName(featureCollection)

expect(actual).toStrictEqual(trackName)
})
})
Loading

0 comments on commit d945a53

Please sign in to comment.