feat: pump tracker, photo log, milk stock, medication profiles, calendar, reminders, audit log, edit events
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>
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
export type EventType =
|
||||
| "BREASTFEED"
|
||||
| "BOTTLE"
|
||||
| "PUMP"
|
||||
| "DIAPER_WET"
|
||||
| "DIAPER_STOOL"
|
||||
| "NAP"
|
||||
@@ -41,6 +42,16 @@ export const EVENT_CONFIG: Record<
|
||||
hasDuration: false,
|
||||
hasTimer: false,
|
||||
},
|
||||
PUMP: {
|
||||
label: "Tirage",
|
||||
icon: "Milk",
|
||||
color: "#0891b2",
|
||||
colorClass: "text-cyan-600",
|
||||
bgClass: "bg-cyan-50",
|
||||
borderClass: "border-cyan-200",
|
||||
hasDuration: true,
|
||||
hasTimer: true,
|
||||
},
|
||||
DIAPER_WET: {
|
||||
label: "Couche mouillée",
|
||||
icon: "Droplets",
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
export const MEDICATION_PRESETS = [
|
||||
{ name: "Doliprane", molecule: "Paracétamol 2.4%", defaultDose: "1", unit: "mL/kg", intervalHours: 6, minIntervalHours: 4 },
|
||||
{ name: "Efferalgan", molecule: "Paracétamol 3%", defaultDose: "1", unit: "mL/kg", intervalHours: 6, minIntervalHours: 4 },
|
||||
{ name: "Advil", molecule: "Ibuprofène 20mg/mL", defaultDose: "0.5", unit: "mL/kg", intervalHours: 6, minIntervalHours: 6 },
|
||||
{ name: "Nurofen", molecule: "Ibuprofène 20mg/mL", defaultDose: "0.5", unit: "mL/kg", intervalHours: 6, minIntervalHours: 6 },
|
||||
{ name: "Motilium", molecule: "Dompéridone", defaultDose: "0.25", unit: "mL/kg", intervalHours: 8, minIntervalHours: 8 },
|
||||
{ name: "Toplexil", molecule: "Oxomémazine", defaultDose: null, unit: "mL", intervalHours: 6, minIntervalHours: 6 },
|
||||
{ name: "Smecta", molecule: "Diosmectite", defaultDose: null, unit: "sachet", intervalHours: 8, minIntervalHours: 8 },
|
||||
{ name: "Zyrtec", molecule: "Cétirizine", defaultDose: null, unit: "mL", intervalHours: 24, minIntervalHours: 24 },
|
||||
{ name: "Solupred", molecule: "Prednisolone", defaultDose: null, unit: "mg/kg", intervalHours: 24, minIntervalHours: 24 },
|
||||
{ name: "Amoxicilline", molecule: "Amoxicilline", defaultDose: null, unit: "mL", intervalHours: 8, minIntervalHours: 8 },
|
||||
] as const;
|
||||
Reference in New Issue
Block a user