mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
HealthLog — personal health-tracking PWA with weight, blood pressure, pulse, mood tracking, medication compliance, Withings integration, doctor report PDF export, and Dracula-themed UI.
130 lines
2.8 KiB
TypeScript
130 lines
2.8 KiB
TypeScript
/**
|
|
* Export utilities — CSV, JSON, and ZIP generation.
|
|
*/
|
|
|
|
interface ExportableRecord {
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
/**
|
|
* Convert records to CSV string.
|
|
*/
|
|
export function toCSV(records: ExportableRecord[]): string {
|
|
if (records.length === 0) return "";
|
|
|
|
const headers = Object.keys(records[0]);
|
|
const lines = [headers.join(",")];
|
|
|
|
for (const record of records) {
|
|
const values = headers.map((h) => {
|
|
const val = record[h];
|
|
if (val === null || val === undefined) return "";
|
|
const str = val instanceof Date ? val.toISOString() : String(val);
|
|
// Escape CSV special characters
|
|
if (str.includes(",") || str.includes('"') || str.includes("\n")) {
|
|
return `"${str.replace(/"/g, '""')}"`;
|
|
}
|
|
return str;
|
|
});
|
|
lines.push(values.join(","));
|
|
}
|
|
|
|
return lines.join("\n");
|
|
}
|
|
|
|
/**
|
|
* Format measurements for export.
|
|
*/
|
|
export function formatMeasurementsForExport(
|
|
measurements: Array<{
|
|
type: string;
|
|
value: number;
|
|
unit: string;
|
|
measuredAt: Date;
|
|
source: string;
|
|
notes: string | null;
|
|
}>,
|
|
): ExportableRecord[] {
|
|
return measurements.map((m) => ({
|
|
type: m.type,
|
|
value: m.value,
|
|
unit: m.unit,
|
|
measuredAt: m.measuredAt.toISOString(),
|
|
source: m.source,
|
|
notes: m.notes ?? "",
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* Format medications for export.
|
|
*/
|
|
export function formatMedicationsForExport(
|
|
medications: Array<{
|
|
name: string;
|
|
dose: string;
|
|
active: boolean;
|
|
schedules: Array<{
|
|
windowStart: string;
|
|
windowEnd: string;
|
|
label: string | null;
|
|
dose: string | null;
|
|
}>;
|
|
}>,
|
|
): ExportableRecord[] {
|
|
return medications.map((m) => ({
|
|
name: m.name,
|
|
dose: m.dose,
|
|
active: m.active,
|
|
schedules: m.schedules
|
|
.map(
|
|
(s) =>
|
|
`${s.label ? s.label + ": " : ""}${s.windowStart}-${s.windowEnd}${s.dose ? " (" + s.dose + ")" : ""}`,
|
|
)
|
|
.join("; "),
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* Format intake events for export.
|
|
*/
|
|
export function formatIntakeEventsForExport(
|
|
events: Array<{
|
|
medication: { name: string };
|
|
scheduledFor: Date;
|
|
takenAt: Date | null;
|
|
skipped: boolean;
|
|
source: string;
|
|
}>,
|
|
): ExportableRecord[] {
|
|
return events.map((e) => ({
|
|
medication: e.medication.name,
|
|
scheduledFor: e.scheduledFor.toISOString(),
|
|
takenAt: e.takenAt?.toISOString() ?? "",
|
|
skipped: e.skipped,
|
|
source: e.source,
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* Format mood entries for export.
|
|
*/
|
|
export function formatMoodEntriesForExport(
|
|
entries: Array<{
|
|
date: string;
|
|
mood: string;
|
|
score: number;
|
|
tags: string | null;
|
|
source: string;
|
|
moodLoggedAt: Date;
|
|
}>,
|
|
): ExportableRecord[] {
|
|
return entries.map((e) => ({
|
|
date: e.date,
|
|
mood: e.mood,
|
|
score: e.score,
|
|
tags: e.tags ?? "",
|
|
source: e.source,
|
|
loggedAt: e.moodLoggedAt.toISOString(),
|
|
}));
|
|
}
|