020539e2e2
New pages: - /calendar — monthly grid with event dots, day detail on tap - /medications — CRUD for medication profiles (presets + custom, dose/unit/intervals/crisis mode) - /milk — milk stock management with location-based expiry, alerts, mark-as-used - /reminders — recurring medication reminder CRUD with Pushover notifications New APIs: - /api/medication-profiles — profiles CRUD + last-intakes endpoint (auto-seeds 10 presets per family) - /api/milk — milk stock CRUD with auto-calculated expiry - /api/reminders + /api/reminders/check — reminder CRUD + cron-callable check endpoint - /api/upload — multipart photo upload to public/uploads/ - /api/invite/send-email — email invitation with family invite link - /api/admin/audit — last 100 audit log entries (superadmin only) Event modal improvements: - PUMP event type (side selector + volume + timer) - MEDICATION: profile chip picker, next-dose timing status, crisis mode toggle - Photo attachment (upload + thumbnail preview) - Datetime inputs split into date + time (iOS Safari datetime-local fix) - Edit mode via initialEvent prop (pre-fills all fields, saves via PATCH) - Timer now shows h:mm:ss when >= 1 hour Timeline: - Modify button opens pre-filled edit modal per event - Photo thumbnail in expanded view Dashboard: - PUMP in quick-log - Medication status card (too-soon / available with next-dose time) Schema additions: MedicationProfile, MedcationReminder, MilkStock, AuditLog models Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
28 lines
671 B
TypeScript
28 lines
671 B
TypeScript
import { prisma } from "./prisma";
|
|
import type { Session } from "next-auth";
|
|
|
|
interface AuditOptions {
|
|
action: string;
|
|
targetId?: string;
|
|
familyId?: string;
|
|
detail?: string;
|
|
}
|
|
|
|
export async function logAudit(session: Session | null, opts: AuditOptions) {
|
|
if (!session?.user?.id) return;
|
|
try {
|
|
await prisma.auditLog.create({
|
|
data: {
|
|
userId: session.user.id,
|
|
userName: session.user.name ?? "—",
|
|
action: opts.action,
|
|
targetId: opts.targetId ?? null,
|
|
familyId: opts.familyId ?? null,
|
|
detail: opts.detail ?? null,
|
|
},
|
|
});
|
|
} catch {
|
|
// audit failure must never break the main request
|
|
}
|
|
}
|