import { useState } from 'react' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import api from '../utils/api' import { formatDistance, formatDuration, formatDate, formatPace, sportIcon } from '../utils/format' export default function RoutesPage() { const [selected, setSelected] = useState(null) const [showCreate, setShowCreate] = useState(false) const [newRoute, setNewRoute] = useState({ name: '', activity_id: '' }) const qc = useQueryClient() const { data: routes } = useQuery({ queryKey: ['routes'], queryFn: () => api.get('/routes/').then(r => r.data), }) const { data: routeActivities } = useQuery({ queryKey: ['route-activities', selected?.id], queryFn: () => api.get(`/routes/${selected.id}/activities`).then(r => r.data), enabled: !!selected, }) const { data: recentActivities } = useQuery({ queryKey: ['recent-activities-for-route'], queryFn: () => api.get('/routes/recent-activities').then(r => r.data), enabled: showCreate, }) const createRoute = useMutation({ mutationFn: (data) => api.post('/routes/', data).then(r => r.data), onSuccess: (route) => { qc.invalidateQueries({ queryKey: ['routes'] }) setShowCreate(false) setNewRoute({ name: '', activity_id: '' }) setSelected(route) }, }) const fastest = routeActivities?.[0] return (

Named Routes

Routes are auto-detected when you run the same path twice. You can also create them manually.

{/* Create route */} {showCreate && (

Create named route

Select an activity to use as the reference GPS track. Future activities on the same route will be linked automatically.

setNewRoute(r => ({ ...r, name: e.target.value }))} className="w-full bg-gray-800 border border-gray-700 rounded-lg px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="e.g. Morning park loop" />
{recentActivities?.length === 0 ? (

No recent activities found.

) : ( )}
)}
{/* Route list */}
{routes?.length === 0 && !showCreate && (

🗺️

No named routes yet

Routes are created automatically when you repeat a run, or create one manually above.

)} {routes?.map(route => ( ))}
{/* Route detail */} {selected && (

{selected.name}

{selected.auto_detected && ( Auto-detected )}
{fastest && (

Course record 🏆

{formatDuration(fastest.duration_s)} {formatDate(fastest.start_time)} · {formatPace(fastest.avg_speed_ms, selected.sport_type)}
)}

All runs ({routeActivities?.length ?? 0})

{routeActivities?.map((act, i) => (
{i + 1} {formatDate(act.start_time)} {formatDuration(act.duration_s)} {formatPace(act.avg_speed_ms, selected.sport_type)} {act.avg_heart_rate && ( {Math.round(act.avg_heart_rate)} bpm )} {i === 0 && ( CR )}
))}
)}
) }