Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

persist trackname and waypoints to backend #17

Merged
merged 3 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/components/merge/UploadForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ const UploadForm: React.FC = () => {
{mergedFile === null && (
<div className="my-7">
<section className="container">
<div {...getRootProps({ style })} className="text-base-content dropzone w-80 sm:w-[480px]">
<div
{...getRootProps({ style })}
className="text-base-content dropzone w-80 sm:w-[480px]"
>
<input {...getInputProps()} />
{isDragActive ? (
<>
Expand Down
16 changes: 2 additions & 14 deletions src/components/track/DownloadLink.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,15 @@
import React from 'react'
import { FiDownload } from 'react-icons/fi'
import { GeoJsonObject } from 'geojson'
import { encodeToBase64 } from '../../utils/tools'
import useLanguage from '../../hooks/useLanguage'
import { Link } from 'react-router-dom'

type DownloadLinkProps = {
trackId: string
type: string
trackname: string
optimizeWaypoints: boolean
geoJson?: GeoJsonObject | null
}

const DownloadLink: React.FC<DownloadLinkProps> = ({
trackId,
type,
trackname,
optimizeWaypoints,
geoJson,
}) => {
const DownloadLink: React.FC<DownloadLinkProps> = ({ trackId, type, optimizeWaypoints }) => {
const { getMessage } = useLanguage()
const baseUrl = import.meta.env.VITE_BACKEND_BASE_URL
const linkTo: string =
Expand All @@ -28,9 +18,7 @@ const DownloadLink: React.FC<DownloadLinkProps> = ({
trackId +
'?mode=dl&type=' +
type +
(optimizeWaypoints ? '&mode=opt' : '') +
(trackname.length > 0 ? `&name=${encodeToBase64(trackname)}` : '') +
(geoJson != null ? `&wp=${encodeToBase64(JSON.stringify(geoJson))}` : '')
(optimizeWaypoints ? '&mode=opt' : '')

return (
<>
Expand Down
2 changes: 1 addition & 1 deletion src/components/track/MarkerSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type MarkerSearchProps = {

const MarkerSearch: React.FC<MarkerSearchProps> = ({ setMarkerPositions }) => {
const [searchTerm, setSearchTerm] = useState('')
const debouncedSearchTerm = useDebounce(searchTerm, 1000)
const debouncedSearchTerm = useDebounce(searchTerm, 500)
const [results, setResults] = useState<Feature[]>([])
const dropdownDivRef = useRef<HTMLDivElement>(null)
const inputRef = useRef<HTMLInputElement>(null)
Expand Down
22 changes: 3 additions & 19 deletions src/components/track/TrackHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import DownloadLink from './DownloadLink'
import { FaCircleInfo, FaEye, FaEyeSlash, FaPenToSquare } from 'react-icons/fa6'
import ContentEditable, { ContentEditableEvent } from 'react-contenteditable'
import React, { useMemo, useRef, useState } from 'react'
import { WayPoint } from '../../@types/gps'
import { generateGeoJson, sanitizeFilename } from '../../utils/tools'
import { sanitizeFilename } from '../../utils/tools'
import useLanguage from '../../hooks/useLanguage'

type TrackHeaderProps = {
trackId: string
markerPositions: WayPoint[]
trackname: string
setTrackname: React.Dispatch<React.SetStateAction<string>>
showPolyline: boolean
Expand All @@ -17,7 +15,6 @@ type TrackHeaderProps = {

const TrackHeader: React.FC<TrackHeaderProps> = ({
trackId,
markerPositions,
trackname,
setTrackname,
showPolyline,
Expand All @@ -27,7 +24,6 @@ const TrackHeader: React.FC<TrackHeaderProps> = ({
const tracknameInputFieldRef: React.RefObject<HTMLElement> = useRef(null)
const tracknameRef = useRef('')
const { getMessage } = useLanguage()
const markerGeoJson = useMemo(() => generateGeoJson(markerPositions), [markerPositions])

useMemo(() => {
tracknameRef.current = trackname
Expand Down Expand Up @@ -73,20 +69,8 @@ const TrackHeader: React.FC<TrackHeaderProps> = ({
</div>
<div className="flex-1 flex mb-4 justify-end items-center">
<div className="flex flex-row flex-1 justify-end items-center">
<DownloadLink
trackId={trackId}
type="gpx"
trackname={trackname}
optimizeWaypoints={optimizeWaypoints}
geoJson={markerGeoJson}
/>
<DownloadLink
trackId={trackId}
type="tcx"
trackname={trackname}
optimizeWaypoints={optimizeWaypoints}
geoJson={markerGeoJson}
/>
<DownloadLink trackId={trackId} type="gpx" optimizeWaypoints={optimizeWaypoints} />
<DownloadLink trackId={trackId} type="tcx" optimizeWaypoints={optimizeWaypoints} />
</div>
<div className="ml-3 mr-5">
<input
Expand Down
41 changes: 39 additions & 2 deletions src/pages/TrackScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ 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 { sanitizeFilename } from '../utils/tools'
import { generateFeatureCollection, sanitizeFilename } from '../utils/tools'
import VisualizeTrack from '../components/track/VisualizeTrack'
import TrackHeader from '../components/track/TrackHeader'
import ResetButton from '../components/track/ResetButton'
import { useFeedbackContext } from '../hooks/useFeedbackContext'
import useLanguage from '../hooks/useLanguage'
import { useThrottle } from '@uidotdev/usehooks'

const TrackScreen = () => {
const { id: trackId } = useParams()
Expand Down Expand Up @@ -133,6 +134,43 @@ const TrackScreen = () => {
})
}, [trackId])

const throttledMarkerPositions = useThrottle(markerPositions, 500)
useEffect(() => {
if (throttledMarkerPositions !== undefined && !isLoading) {
const featureCollection = generateFeatureCollection(markerPositions)
API.put(`/tracks/${trackId}/points`, featureCollection, {
headers: {
'Content-Type': 'application/geo+json',
},
}).catch((error) => {
console.error('Failed to update waypoint', error)
})
}
}, [throttledMarkerPositions])

const throttledTrackname = useThrottle(trackname, 500)
useEffect(() => {
if (throttledTrackname !== undefined && !isLoading) {
const feature = {
type: 'Feature',
properties: {
name: throttledTrackname,
},
geometry: {
type: 'LineString',
coordinates: [],
},
}
API.patch(`/tracks/${trackId}`, feature, {
headers: {
'Content-Type': 'application/geo+json',
},
}).catch((error) => {
console.error('Failed to update waypoint', error)
})
}
}, [throttledTrackname])

return (
<>
{isLoading ? (
Expand All @@ -141,7 +179,6 @@ const TrackScreen = () => {
<div className="flex flex-col" style={{ height: '100%' }}>
<TrackHeader
trackId={trackId}
markerPositions={markerPositions}
trackname={trackname}
setTrackname={setTrackname}
showPolyline={showPolyline}
Expand Down
10 changes: 6 additions & 4 deletions src/utils/tools.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
convertOsmToPoiType,
decodeFromBase64,
encodeToBase64,
generateGeoJson,
generateFeatureCollection,
sanitizeFilename,
} from './tools'
import { WayPoint } from '../@types/gps'
Expand Down Expand Up @@ -75,7 +75,7 @@ describe('generate GeoJSON', () => {
const given: WayPoint[] = [
{
id: id1,
position: [11, 12],
position: [11, 21],
name: 'way point 1',
type: 'GENERIC',
},
Expand All @@ -86,18 +86,19 @@ describe('generate GeoJSON', () => {
type: 'FOOD',
},
]
const actual = generateGeoJson(given)
const actual = generateFeatureCollection(given)

expect(actual).toEqual({
features: [
{
geometry: {
coordinates: [12, 11],
coordinates: [21, 11],
type: 'Point',
},
properties: {
name: 'way point 1',
type: 'GENERIC',
uuid: id1,
},
type: 'Feature',
},
Expand All @@ -109,6 +110,7 @@ describe('generate GeoJSON', () => {
properties: {
name: 'way point 2',
type: 'FOOD',
uuid: id2,
},
type: 'Feature',
},
Expand Down
32 changes: 17 additions & 15 deletions src/utils/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,25 @@ export const encodeToBase64 = (input: string) => {
return btoa(binString)
}

export const generateGeoJson = (markerPositions: WayPoint[]): FeatureCollection => {
export const generateFeature = (waypoint: WayPoint): Feature => {
return {
type: 'Feature',
properties: {
name: waypoint.name,
type: waypoint.type,
uuid: waypoint.id,
},
geometry: {
type: 'Point',
coordinates: [waypoint.position[1], waypoint.position[0]],
},
} as Feature
}

export const generateFeatureCollection = (markerPositions: WayPoint[]): FeatureCollection => {
return {
type: 'FeatureCollection',
features: markerPositions.map(
(waypoint) =>
({
type: 'Feature',
properties: {
name: waypoint.name,
type: waypoint.type,
},
geometry: {
type: 'Point',
coordinates: [waypoint.position[1], waypoint.position[0]],
},
}) as Feature,
),
features: markerPositions.map((waypoint) => generateFeature(waypoint)),
}
}

Expand Down