add more stats to mobile and fix refresh stint
This commit is contained in:
@@ -56,7 +56,7 @@ function filterPublicTrainingStats(stats, visibility) {
|
||||
outlierLaps: stats.outlierLaps, strongFinishStints: stats.strongFinishStints,
|
||||
cleanFiveMinuteStints: stats.cleanFiveMinuteStints, stintCount: stats.stintCount,
|
||||
stintSummaries: stats.stintSummaries, bestThreeConsecutive: stats.bestThreeConsecutive,
|
||||
bestFiveMinuteResult: stats.bestFiveMinuteResult,
|
||||
bestFiveMinuteResult: stats.bestFiveMinuteResult, paceBuckets: stats.paceBuckets,
|
||||
});
|
||||
if (visibility.history) filtered.dailySummaries = stats.dailySummaries;
|
||||
return filtered;
|
||||
@@ -91,6 +91,8 @@ function buildPublicTrainingProfile(state, shareToken, updatedAt, sinceTimestamp
|
||||
}))
|
||||
.sort((left, right) => left.timestamp - right.timestamp);
|
||||
const stats = buildPublicTrainingStats(classLaps);
|
||||
const classMarkers = (Array.isArray(state?.training?.markers) ? state.training.markers : []).filter((marker) => classDriverIds.has(String(marker?.driverId || "")) && String(marker?.classId || "") === classId);
|
||||
stats.paceBuckets = buildPublicTrainingPaceBuckets(classLaps, classMarkers);
|
||||
const channelStats = buildPublicTimingChannelStats(state, classDriverIds);
|
||||
const classGoals = (Array.isArray(state?.training?.goals) ? state.training.goals : [])
|
||||
.filter((goal) => profileReferences.has(String(goal?.driverId || "")) && (!goal?.classId || String(goal.classId) === classId))
|
||||
@@ -217,6 +219,31 @@ function buildPublicTrainingGoal(goal, currentLaps) {
|
||||
};
|
||||
}
|
||||
|
||||
function buildPublicTrainingPaceBuckets(laps, markers, bucketMinutes = 30) {
|
||||
const bucketMs = Math.max(5, Number(bucketMinutes || 30)) * 60 * 1000;
|
||||
const buckets = new Map();
|
||||
laps.filter((lap) => !lap.excludedFromPace).forEach((lap) => {
|
||||
const date = new Date(lap.timestamp);
|
||||
const minuteBlock = bucketMs / 60000;
|
||||
const startTs = new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), Math.floor(date.getMinutes() / minuteBlock) * minuteBlock, 0, 0).getTime();
|
||||
const bucket = buckets.get(startTs) || { startTs, values: [] };
|
||||
bucket.values.push(lap.lapMs);
|
||||
buckets.set(startTs, bucket);
|
||||
});
|
||||
return [...buckets.values()].sort((left, right) => right.startTs - left.startTs).slice(0, 24).map((bucket) => {
|
||||
const sorted = [...bucket.values].sort((left, right) => left - right);
|
||||
const trim = sorted.length >= 5 ? Math.max(1, Math.floor(sorted.length * 0.1)) : 0;
|
||||
const kept = trim ? sorted.slice(trim, sorted.length - trim) : sorted;
|
||||
return {
|
||||
startTs: bucket.startTs,
|
||||
lapCount: bucket.values.length,
|
||||
paceMs: kept.length ? Math.round(kept.reduce((sum, value) => sum + value, 0) / kept.length) : 0,
|
||||
bestLapMs: bucket.values.length ? Math.min(...bucket.values) : 0,
|
||||
markerCount: markers.filter((marker) => Number(marker?.timestamp || 0) >= bucket.startTs && Number(marker?.timestamp || 0) < bucket.startTs + bucketMs).length,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function buildPublicTrainingStats(laps) {
|
||||
const paceLaps = laps.filter((lap) => !lap.excludedFromPace);
|
||||
const lapTimes = paceLaps.map((lap) => lap.lapMs);
|
||||
@@ -449,6 +476,25 @@ function getPublicBestDurationResult(stints, targetMs) {
|
||||
return best;
|
||||
}
|
||||
|
||||
function addPublicTrainingMarker(state, shareToken, input, timestamp = Date.now()) {
|
||||
const share = findPublicTrainingShare(state, shareToken);
|
||||
if (!share) return null;
|
||||
const drivers = Array.isArray(state?.drivers) ? state.drivers : [];
|
||||
const profile = getPublicDriverProfile(drivers, share.driverId);
|
||||
const classId = String(input?.classId || "");
|
||||
const classDriver = profile?.drivers.find((driver) => String(driver?.classId || "") === classId);
|
||||
if (!classDriver) return null;
|
||||
const type = ["setup", "tires", "suspension", "car", "note"].includes(String(input?.type || "")) ? String(input.type) : "car";
|
||||
const marker = {
|
||||
id: "training_marker_public_" + Math.round(timestamp) + "_" + Math.random().toString(36).slice(2, 9),
|
||||
driverId: String(classDriver.id || ""), classId, sessionId: "", timestamp: Math.round(timestamp), type,
|
||||
note: String(input?.note || "").trim().slice(0, 160), createdAt: new Date(timestamp).toISOString(),
|
||||
};
|
||||
if (!state.training || typeof state.training !== "object") state.training = {};
|
||||
state.training.markers = [...(Array.isArray(state.training.markers) ? state.training.markers : []), marker];
|
||||
return marker;
|
||||
}
|
||||
|
||||
function normalizePublicLogoDataUrl(value) {
|
||||
const logo = String(value || "").trim();
|
||||
return logo.length <= 2_000_000 && /^data:image\/(?:png|jpeg|webp);base64,/i.test(logo) ? logo : "";
|
||||
@@ -482,4 +528,5 @@ module.exports = {
|
||||
splitPublicTrainingStints,
|
||||
getPublicBestConsecutiveLaps,
|
||||
getPublicBestDurationResult,
|
||||
addPublicTrainingMarker,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user