frontend: global km/mi distance-unit toggle across dashboard, activities, routes, records
Build and push images / validate (push) Successful in 3s
Build and push images / build-backend (push) Successful in 5s
Build and push images / build-worker (push) Successful in 5s
Build and push images / build-frontend (push) Successful in 9s

This commit is contained in:
2026-06-18 13:01:25 +01:00
parent e61c77842f
commit a50d13179c
13 changed files with 186 additions and 57 deletions
+11 -8
View File
@@ -4,9 +4,10 @@ import { useQuery } from '@tanstack/react-query'
import { format } from 'date-fns'
import api from '../utils/api'
import {
formatDuration, formatDistance, formatPace, formatHeartRate,
formatDate, sportIcon, sportColor,
formatDuration, formatDistance, formatPace, formatHeartRate, formatElevation,
formatDate, sportIcon, sportColor, convertKm, distanceUnitLabel,
} from '../utils/format'
import { useUnit } from '../hooks/useUnits'
const SPORTS = ['all', 'running', 'cycling', 'hiking', 'walking']
@@ -15,6 +16,8 @@ export default function ActivitiesPage() {
const navigate = useNavigate()
const [sport, setSport] = useState('all')
const [page, setPage] = useState(1)
const unit = useUnit()
const distLabel = distanceUnitLabel(unit)
const fromParam = searchParams.get('from')
const toParam = searchParams.get('to')
@@ -56,10 +59,10 @@ export default function ActivitiesPage() {
{ytdStats && (
<div className="flex flex-wrap gap-x-4 gap-y-1 mb-4 text-sm">
{ytdStats.running_km > 0 && (
<span className="text-blue-400">🏃 {ytdStats.running_km.toFixed(0)} km this year</span>
<span className="text-blue-400">🏃 {convertKm(ytdStats.running_km, unit).toFixed(0)} {distLabel} this year</span>
)}
{ytdStats.cycling_km > 0 && (
<span className="text-orange-400">🚴 {ytdStats.cycling_km.toFixed(0)} km this year</span>
<span className="text-orange-400">🚴 {convertKm(ytdStats.cycling_km, unit).toFixed(0)} {distLabel} this year</span>
)}
</div>
)}
@@ -118,14 +121,14 @@ export default function ActivitiesPage() {
<p className="text-xs text-gray-500 mt-0.5">{formatDate(activity.start_time)}</p>
{/* Compact metrics line — the full metrics column is hidden below sm */}
<p className="sm:hidden text-xs text-gray-400 mt-0.5 truncate">
{formatDistance(activity.distance_m)} · {formatDuration(activity.duration_s)} · {formatPace(activity.avg_speed_ms, activity.sport_type)}
{formatDistance(activity.distance_m, unit)} · {formatDuration(activity.duration_s)} · {formatPace(activity.avg_speed_ms, activity.sport_type, unit)}
</p>
</div>
{/* Metrics */}
<div className="hidden sm:flex items-center gap-6 text-sm">
<div className="text-right">
<p className="text-gray-200 font-medium">{formatDistance(activity.distance_m)}</p>
<p className="text-gray-200 font-medium">{formatDistance(activity.distance_m, unit)}</p>
<p className="text-xs text-gray-600">distance</p>
</div>
<div className="text-right">
@@ -133,7 +136,7 @@ export default function ActivitiesPage() {
<p className="text-xs text-gray-600">time</p>
</div>
<div className="text-right">
<p className="text-gray-200 font-medium">{formatPace(activity.avg_speed_ms, activity.sport_type)}</p>
<p className="text-gray-200 font-medium">{formatPace(activity.avg_speed_ms, activity.sport_type, unit)}</p>
<p className="text-xs text-gray-600">pace</p>
</div>
<div className="text-right">
@@ -142,7 +145,7 @@ export default function ActivitiesPage() {
</div>
<div className="text-right">
<p className="text-gray-200 font-medium">
{activity.elevation_gain_m ? `${Math.round(activity.elevation_gain_m)}m` : '--'}
{activity.elevation_gain_m ? `${formatElevation(activity.elevation_gain_m, unit)}` : '--'}
</p>
<p className="text-xs text-gray-600">elev</p>
</div>