feat: export gear maintenance log as CSV
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user