feat: maintenance banner, activities log, pinned note, event templates, weekly summary cron

Maintenance mode banner:
- App layout reads SystemConfig maintenance_mode at server render time
- Amber sticky banner for regular users, dimmed indicator for superadmin

Baby activities (3 new event types):
- BATH (Bath icon, sky, timer+duration)
- WALK / Balade (Footprints icon, lime)
- TUMMY_TIME (Baby icon, amber)
- Added to EventType enum, EVENT_CONFIG, event-icon.tsx, dashboard quick-log

Pinned family note:
- Shared across all family members, shown at top of dashboard
- Inline edit with author + timestamp; /api/family/pinned-note GET/PATCH
- pinnedNote + pinnedNoteUpdatedAt + pinnedNoteAuthor fields on Family model

Event templates:
- Named quick-log presets per family (type + label + metadata)
- Dashboard row: tap to open pre-filled EventModal; hover ✕ to delete
- Dropdown to create new template; /api/event-templates GET/POST + /[id] PATCH/DELETE
- EventTemplate model in schema

Weekly summary cron:
- POST /api/cron/weekly-summary — auth via Bearer cron_secret (SystemConfig or env)
- Per family, per baby: feeds count, sleep total+avg, diaper count, latest weight
- Sends Pushover to all family members with pushoverUserKey
- Optional body.familyId to target one family

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-13 15:08:54 +02:00
parent 020539e2e2
commit 42c580d7e2
10 changed files with 570 additions and 15 deletions
+27 -1
View File
@@ -3,16 +3,42 @@ import { redirect } from "next/navigation";
import { SidebarNav, BottomNav } from "@/components/nav";
import { BabyProvider } from "@/contexts/baby-context";
import { QuickAddFab } from "@/components/quick-add-fab";
import { prisma } from "@/lib/prisma";
import { AlertTriangle } from "lucide-react";
async function getMaintenanceMode(): Promise<boolean> {
try {
const row = await prisma.systemConfig.findUnique({ where: { key: "maintenance_mode" } });
return row?.value === "true";
} catch {
return false;
}
}
export default async function AppLayout({ children }: { children: React.ReactNode }) {
const session = await auth();
if (!session?.user) redirect("/auth/login");
const maintenance = await getMaintenanceMode();
const isSuperAdmin = (session.user as { isSuperAdmin?: boolean })?.isSuperAdmin;
return (
<BabyProvider>
<div className="min-h-screen bg-slate-50 dark:bg-slate-900">
{maintenance && (
<div className={`fixed top-0 left-0 right-0 z-[100] px-4 py-2.5 flex items-center gap-2 justify-center text-sm font-medium shadow-md ${
isSuperAdmin
? "bg-amber-400/90 text-amber-900 text-xs py-1.5"
: "bg-amber-500 text-white"
}`}>
<AlertTriangle className="w-4 h-4 flex-shrink-0" />
{isSuperAdmin
? "Mode maintenance actif (visible des utilisateurs)"
: "Maintenance en cours — certaines fonctionnalités peuvent être indisponibles"}
</div>
)}
<SidebarNav />
<main className="app-main min-h-screen">
<main className={`app-main min-h-screen${maintenance ? " pt-10" : ""}`}>
{children}
</main>
<BottomNav />