feat: export gear maintenance log as CSV

This commit is contained in:
Davide Scaini
2026-05-24 14:07:37 +02:00
parent 94cd3f7eb4
commit b827792d16
+41
View File
@@ -83,6 +83,41 @@
const GEAR_ICONS: Record<string, string> = { bike: '🚲', shoes: '👟', skis: '🎿', other: '⚙️' };
function exportGearCsv() {
const esc = (v: unknown) => `"${String(v ?? '').replace(/"/g, '""')}"`;
const rows: string[] = [
['gear_name', 'gear_type', 'gear_distance_km', 'part_name', 'part_threshold_km',
'part_distance_since_last_km', 'replacement_date', 'replacement_note'].join(',')
];
for (const item of gearItems) {
const gearKm = ((gearDistances[item.name] ?? 0) / 1000).toFixed(1);
const parts = item.parts ?? [];
if (parts.length === 0) {
rows.push([esc(item.name), esc(item.type), gearKm, '', '', '', '', ''].join(','));
continue;
}
for (const part of parts) {
const partKm = partDistanceKm(item.name, part).toFixed(1);
const reps = part.replacements.slice().reverse();
if (reps.length === 0) {
rows.push([esc(item.name), esc(item.type), gearKm, esc(part.name),
part.threshold_km ?? '', partKm, '', ''].join(','));
} else {
for (const rep of reps) {
rows.push([esc(item.name), esc(item.type), gearKm, esc(part.name),
part.threshold_km ?? '', partKm, rep.date, esc(rep.note ?? '')].join(','));
}
}
}
}
const blob = new Blob([rows.join('\n')], { type: 'text/csv' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'gear.csv';
a.click();
URL.revokeObjectURL(a.href);
}
function fmtDate(iso: string): string {
const [y, m, d] = iso.split('-');
return `${d}/${m}/${y}`;
@@ -847,6 +882,12 @@
disabled={gearAdding || !gearAddName.trim()}
class="text-xs px-3 py-1.5 rounded-lg border border-zinc-700 hover:border-zinc-500 text-zinc-400 hover:text-white transition-colors disabled:opacity-40"
>{gearAdding ? 'Adding…' : '+ Add gear'}</button>
{#if gearItems.length > 0}
<button
on:click={exportGearCsv}
class="text-xs px-3 py-1.5 rounded-lg border border-zinc-700 hover:border-zinc-500 text-zinc-400 hover:text-white transition-colors ml-auto"
>Export CSV</button>
{/if}
</div>
{/if}
</div>