Spaces:
Sleeping
Sleeping
File size: 5,751 Bytes
35527e2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
import Papa from 'papaparse';
import type { Activity } from '@/types';
import { calculateTSS } from './tssCalculator';
export function parseCSV(file: File, userFTP: number = 343): Promise<Activity[]> {
return new Promise((resolve, reject) => {
Papa.parse(file, {
header: true,
skipEmptyLines: true,
complete: (results) => {
try {
const activities = results.data.map((row: any) => {
// Parse date - Garmin format: "2025-12-02 09:19:49"
const dateStr = row['Date'] || row['Activity Date'] || row['date'];
if (!dateStr || dateStr === '--') {
return null;
}
const date = new Date(dateStr);
if (isNaN(date.getTime())) {
return null;
}
// Parse distance - Garmin format: "8.34" (in km)
let distance: number | undefined;
const distanceStr = row['Distance'] || row['distance'];
if (distanceStr && distanceStr !== '--' && distanceStr !== '0.00') {
const parsed = parseFloat(distanceStr.replace(/,/g, ''));
if (!isNaN(parsed) && parsed > 0) {
distance = parsed;
}
}
// Parse duration - Garmin format: "00:48:51" (HH:MM:SS)
let duration: number | undefined;
let durationSeconds: number | undefined;
const durationStr = row['Time'] || row['Duration'] || row['Moving Time'] || row['Elapsed Time'];
if (durationStr && durationStr !== '--') {
if (durationStr.includes(':')) {
const parts = durationStr.split(':');
const hours = parseInt(parts[0]) || 0;
const minutes = parseInt(parts[1]) || 0;
const seconds = parseFloat(parts[2]) || 0;
duration = hours * 60 + minutes + seconds / 60;
durationSeconds = hours * 3600 + minutes * 60 + seconds;
} else {
const parsed = parseFloat(durationStr);
if (!isNaN(parsed)) {
duration = parsed;
durationSeconds = parsed * 60; // Assume minutes if no colon
}
}
}
// Parse TSS - Try to calculate from power data first
let trainingStressScore: number | undefined;
// First, check if TSS is already provided in CSV
const tssStr = row['Training Stress Score®'] || row['Training Stress Score'] || row['TSS'];
if (tssStr && tssStr !== '--' && tssStr !== '0.0' && tssStr !== '0') {
const parsed = parseFloat(tssStr);
if (!isNaN(parsed) && parsed > 0) {
trainingStressScore = parsed;
}
}
// If no TSS provided, try to calculate from power data
if (!trainingStressScore && durationSeconds) {
// Parse Normalized Power (NP)
const npStr = row['Normalized Power (NP)'] || row['Normalized Power'] || row['NP'];
const normalizedPower = npStr && npStr !== '--' ? parseFloat(npStr) : undefined;
// Use FTP from CSV if available, otherwise use user-provided FTP
const ftpStr = row['FTP'] || row['Functional Threshold Power'];
const ftp = ftpStr && ftpStr !== '--' ? parseFloat(ftpStr) : userFTP;
if (normalizedPower && ftp) {
const calculatedTSS = calculateTSS({
durationSeconds,
normalizedPower,
ftp,
});
if (calculatedTSS !== undefined) {
trainingStressScore = calculatedTSS;
}
}
}
// Get activity type
const activityType = row['Activity Type'] || row['Type'] || row['Sport'];
const activity: Activity = {
date,
activityType,
distance,
duration,
trainingStressScore,
};
return activity;
}).filter((activity): activity is Activity => activity !== null);
// Sort by date
activities.sort((a, b) => a.date.getTime() - b.date.getTime());
resolve(activities);
} catch (error) {
reject(new Error('Failed to parse CSV data'));
}
},
error: (error) => {
reject(new Error(`CSV parsing error: ${error.message}`));
},
});
});
}
|