diff --git a/frontend/src/components/activity/LapTable.jsx b/frontend/src/components/activity/LapTable.jsx index cc0afdf..b2d6824 100644 --- a/frontend/src/components/activity/LapTable.jsx +++ b/frontend/src/components/activity/LapTable.jsx @@ -2,9 +2,28 @@ import { formatDuration, formatDistance, formatPace, formatHeartRate, formatCade const RUNNING_TYPES = new Set(['running', 'hiking', 'walking']) -export default function LapTable({ laps, sportType, lapBests }) { +// Most common lap distance (rounded to 100 m), used to tell "whole" laps from +// the short trailing fragment that auto-lapping leaves at the end of a run. +function modalDistance(laps) { + const counts = {} + for (const l of laps) { + if (l.distance_m == null) continue + const key = Math.round(l.distance_m / 100) * 100 + counts[key] = (counts[key] || 0) + 1 + } + let best = null, bestN = 0 + for (const [k, n] of Object.entries(counts)) { + if (n > bestN) { bestN = n; best = Number(k) } + } + return best +} + +export default function LapTable({ laps, sportType, lapBests, records }) { const showPower = !RUNNING_TYPES.has(sportType?.toLowerCase()) const hasBests = lapBests && Object.keys(lapBests).length > 0 + const modal = modalDistance(laps) + const prs = records || [] + const showLegend = hasBests || prs.length > 0 return (
| {lap.lap_number} | +||||||
| + + {lap.lap_number} + {isPR && 🥇} + + | {formatDistance(lap.distance_m)} | -{formatDuration(lap.duration_s)} | +{formatDuration(lap.duration_s)} | {hasBests && ({best != null ? formatDuration(best) : '--'} | )} {hasBests && (- {delta == null ? '--' : isBest ? '🏆' : `${delta > 0 ? '+' : '−'}${formatDuration(Math.abs(delta))}`} + {delta == null ? '--' : isLapBest ? 🏆 : `${delta > 0 ? '+' : '−'}${formatDuration(Math.abs(delta))}`} | )}{formatPace(lap.avg_speed_ms, sportType)} | @@ -58,6 +98,12 @@ export default function LapTable({ laps, sportType, lapBests }) { })}