All checks were successful
Deploy production / deploy (push) Successful in 2m22s
Regenerated the (not yet deployed) health migration without hair_progress.
111 lines
3.5 KiB
TypeScript
111 lines
3.5 KiB
TypeScript
import { db } from '#lib/server/db/index.js';
|
|
import {
|
|
healthAppointments,
|
|
healthBodyMeasurements,
|
|
healthMedications,
|
|
healthNutritionDaily,
|
|
healthSleep,
|
|
healthVaccinations,
|
|
healthWorkouts
|
|
} from '#lib/server/db/schema/index.js';
|
|
import { requireOwner } from '#lib/server/owner.js';
|
|
import { cleanRow, drizzleTables, TIME_ZONE, writeRows } from '#lib/server/health-import.js';
|
|
import { healthTables, isHealthTable } from '#lib/health/tables.js';
|
|
import { asc, desc, eq, gte, lt } from 'drizzle-orm';
|
|
import { fail } from '@sveltejs/kit';
|
|
import type { Actions, PageServerLoad } from './$types';
|
|
|
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
|
|
function today(): string {
|
|
return new Intl.DateTimeFormat('en-CA', { timeZone: TIME_ZONE }).format(new Date());
|
|
}
|
|
function daysAgo(day: string, n: number): string {
|
|
const d = new Date(`${day}T12:00:00Z`);
|
|
d.setUTCDate(d.getUTCDate() - n);
|
|
return d.toISOString().slice(0, 10);
|
|
}
|
|
|
|
export const load: PageServerLoad = async (event) => {
|
|
requireOwner(event);
|
|
const now = today();
|
|
const [measurements, workouts, nutrition, sleep, medications, vaccinations, upcoming, past] =
|
|
await Promise.all([
|
|
db
|
|
.select()
|
|
.from(healthBodyMeasurements)
|
|
.orderBy(asc(healthBodyMeasurements.date), asc(healthBodyMeasurements.createdAt)),
|
|
db
|
|
.select()
|
|
.from(healthWorkouts)
|
|
.orderBy(desc(healthWorkouts.date), asc(healthWorkouts.createdAt))
|
|
.limit(30),
|
|
db
|
|
.select()
|
|
.from(healthNutritionDaily)
|
|
.where(gte(healthNutritionDaily.date, daysAgo(now, 6)))
|
|
.orderBy(desc(healthNutritionDaily.date)),
|
|
db
|
|
.select()
|
|
.from(healthSleep)
|
|
.where(gte(healthSleep.date, daysAgo(now, 6)))
|
|
.orderBy(desc(healthSleep.date)),
|
|
db.select().from(healthMedications).orderBy(asc(healthMedications.name)),
|
|
db
|
|
.select()
|
|
.from(healthVaccinations)
|
|
.orderBy(desc(healthVaccinations.date), asc(healthVaccinations.vaccine)),
|
|
db
|
|
.select()
|
|
.from(healthAppointments)
|
|
.where(gte(healthAppointments.date, now))
|
|
.orderBy(asc(healthAppointments.date)),
|
|
db
|
|
.select()
|
|
.from(healthAppointments)
|
|
.where(lt(healthAppointments.date, now))
|
|
.orderBy(desc(healthAppointments.date))
|
|
.limit(10)
|
|
]);
|
|
return {
|
|
today: now,
|
|
measurements,
|
|
workouts,
|
|
nutrition,
|
|
sleep,
|
|
medications,
|
|
vaccinations,
|
|
appointments: { upcoming, past },
|
|
seo: { title: 'Health', description: 'Private health log.', index: false }
|
|
};
|
|
};
|
|
|
|
export const actions: Actions = {
|
|
save: async (event) => {
|
|
requireOwner(event);
|
|
const form = await event.request.formData();
|
|
const table = form.get('table');
|
|
if (!isHealthTable(table)) return fail(400, { message: 'Unknown table' });
|
|
const row: Record<string, unknown> = { id: form.get('id') || undefined };
|
|
for (const field of healthTables[table].fields) row[field.key] = form.get(field.key) ?? '';
|
|
const result = cleanRow(table, row);
|
|
if (!result.ok) return fail(400, { message: result.error, table });
|
|
try {
|
|
await writeRows(db, { [table]: [result.row] });
|
|
} catch (e) {
|
|
return fail(400, { message: e instanceof Error ? e.message : 'Could not save', table });
|
|
}
|
|
return { saved: table };
|
|
},
|
|
delete: async (event) => {
|
|
requireOwner(event);
|
|
const form = await event.request.formData();
|
|
const table = form.get('table');
|
|
const id = String(form.get('id') ?? '');
|
|
if (!isHealthTable(table) || !UUID.test(id)) return fail(400, { message: 'Invalid entry' });
|
|
const target = drizzleTables[table];
|
|
await db.delete(target).where(eq(target.id, id));
|
|
return { deleted: table };
|
|
}
|
|
};
|