fix: export/import dismissed doses and person-specific dose IDs (#45)

- Add 'dismissed' field to dose history export/import
- Add 'takenByPerson' field to handle person-suffixed dose IDs (e.g., 5-0-timestamp-Daniel)
- Update parseDoseId() to extract person suffix from dose ID
- Update buildDoseId() to include optional person suffix

This fixes import losing:
1. Which past doses were marked as taken
2. Which doses were dismissed (cleared missed)
3. Person-specific dose tracking for shared schedules
This commit is contained in:
Daniel Volz
2026-01-18 09:19:23 +01:00
committed by GitHub
parent fb0b3df794
commit 8d22669bef
+17 -7
View File
@@ -55,6 +55,8 @@ const doseHistorySchema = z.object({
scheduledTime: z.string(), // ISO datetime scheduledTime: z.string(), // ISO datetime
takenAt: z.string(), // ISO datetime takenAt: z.string(), // ISO datetime
markedBy: z.string().nullable().optional(), markedBy: z.string().nullable().optional(),
dismissed: z.boolean().default(false),
takenByPerson: z.string().nullable().optional(), // Person suffix from dose ID (e.g., "Daniel")
}); });
const shareLinkSchema = z.object({ const shareLinkSchema = z.object({
@@ -204,8 +206,8 @@ function base64ToImage(base64: string, medicationId: number): string | null {
} }
// Parse dose ID to extract medication ID and timestamp // Parse dose ID to extract medication ID and timestamp
// Format: "{medicationId}-{blisterIndex}-{timestampMs}" // Format: "{medicationId}-{blisterIndex}-{timestampMs}" or "{medicationId}-{blisterIndex}-{timestampMs}-{person}"
function parseDoseId(doseId: string): { medicationId: number; blisterIndex: number; timestampMs: number } | null { function parseDoseId(doseId: string): { medicationId: number; blisterIndex: number; timestampMs: number; person: string | null } | null {
const parts = doseId.split("-"); const parts = doseId.split("-");
if (parts.length < 3) return null; if (parts.length < 3) return null;
@@ -215,12 +217,16 @@ function parseDoseId(doseId: string): { medicationId: number; blisterIndex: numb
if (isNaN(medicationId) || isNaN(blisterIndex) || isNaN(timestampMs)) return null; if (isNaN(medicationId) || isNaN(blisterIndex) || isNaN(timestampMs)) return null;
return { medicationId, blisterIndex, timestampMs }; // Check if there's a person suffix (4th part onwards, could be multi-part name)
const person = parts.length > 3 ? parts.slice(3).join("-") : null;
return { medicationId, blisterIndex, timestampMs, person };
} }
// Build dose ID from parts // Build dose ID from parts (with optional person suffix)
function buildDoseId(medicationId: number, blisterIndex: number, timestampMs: number): string { function buildDoseId(medicationId: number, blisterIndex: number, timestampMs: number, person?: string | null): string {
return `${medicationId}-${blisterIndex}-${timestampMs}`; const base = `${medicationId}-${blisterIndex}-${timestampMs}`;
return person ? `${base}-${person}` : base;
} }
// ============================================================================= // =============================================================================
@@ -309,6 +315,8 @@ export async function exportRoutes(app: FastifyInstance) {
scheduledTime: scheduledTimeIso, scheduledTime: scheduledTimeIso,
takenAt: takenAtIso, takenAt: takenAtIso,
markedBy: dose.markedBy, markedBy: dose.markedBy,
dismissed: dose.dismissed ?? false,
takenByPerson: parsed.person,
}; };
}).filter((d): d is NonNullable<typeof d> => d !== null); }).filter((d): d is NonNullable<typeof d> => d !== null);
@@ -484,13 +492,15 @@ export async function exportRoutes(app: FastifyInstance) {
// Convert ISO timestamp back to milliseconds for dose ID // Convert ISO timestamp back to milliseconds for dose ID
const timestampMs = new Date(dose.scheduledTime).getTime(); const timestampMs = new Date(dose.scheduledTime).getTime();
const doseId = buildDoseId(newMedId, dose.scheduleIndex, timestampMs); // Rebuild dose ID with optional person suffix
const doseId = buildDoseId(newMedId, dose.scheduleIndex, timestampMs, dose.takenByPerson);
await db.insert(doseTracking).values({ await db.insert(doseTracking).values({
userId, userId,
doseId, doseId,
takenAt: new Date(dose.takenAt), takenAt: new Date(dose.takenAt),
markedBy: dose.markedBy || null, markedBy: dose.markedBy || null,
dismissed: dose.dismissed ?? false,
}); });
} }