From f2cc181ecef660abb01f6f638a9199f5c25a6896 Mon Sep 17 00:00:00 2001 From: Arnaud Nelissen Date: Fri, 19 Jun 2026 11:51:41 +0200 Subject: [PATCH] feat: per-baby breastfeeding and pump feature toggles Add isBreastfed and hasPump flags to Baby model. When disabled, hide breastfeeding/pump options from quick-add FAB, dashboard counters and quick-log groups, and the milk stock nav link. Settings page gains toggle UI to configure per baby. Co-Authored-By: Claude Sonnet 4.6 --- .../migration.sql | 3 ++ prisma/schema.prisma | 4 +- src/app/(app)/dashboard/page.tsx | 44 +++++++++---------- src/app/(app)/settings/page.tsx | 25 ++++++++++- src/app/api/baby/[id]/route.ts | 4 +- src/components/nav.tsx | 3 ++ src/components/quick-add-fab.tsx | 10 ++++- src/contexts/baby-context.tsx | 2 + 8 files changed, 67 insertions(+), 28 deletions(-) create mode 100644 prisma/migrations/20260619092758_add_feeding_flags/migration.sql diff --git a/prisma/migrations/20260619092758_add_feeding_flags/migration.sql b/prisma/migrations/20260619092758_add_feeding_flags/migration.sql new file mode 100644 index 0000000..7678051 --- /dev/null +++ b/prisma/migrations/20260619092758_add_feeding_flags/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "Baby" ADD COLUMN "hasPump" BOOLEAN NOT NULL DEFAULT true, +ADD COLUMN "isBreastfed" BOOLEAN NOT NULL DEFAULT true; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index e4f90a0..2c2191e 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -149,7 +149,9 @@ model Baby { id String @id @default(cuid()) name String birthDate DateTime - gender String? + gender String? + isBreastfed Boolean @default(true) + hasPump Boolean @default(true) familyId String family Family @relation(fields: [familyId], references: [id]) events Event[] diff --git a/src/app/(app)/dashboard/page.tsx b/src/app/(app)/dashboard/page.tsx index d0c790f..d69e6fa 100644 --- a/src/app/(app)/dashboard/page.tsx +++ b/src/app/(app)/dashboard/page.tsx @@ -12,24 +12,21 @@ import { fr } from "date-fns/locale"; import { AlertTriangle, Clock, CheckCircle2, Pin, PinOff, Pencil, Check, X, Plus, FileText, ImageIcon } from "lucide-react"; import { useSession } from "next-auth/react"; -const QUICK_LOG_GROUPS: { label: string; types: EventType[] }[] = [ - { - label: "Alimentation & Soins", - types: ["BREASTFEED", "BOTTLE", "PUMP", "DIAPER_WET", "DIAPER_STOOL"], - }, - { - label: "Sommeil & Activités", - types: ["NAP", "NIGHT_SLEEP", "BATH", "WALK", "TUMMY_TIME"], - }, - { - label: "Santé", - types: ["TEMPERATURE", "MEDICATION", "SYMPTOM"], - }, - { - label: "Autre", - types: ["OTHER"], - }, -]; +function buildQuickLogGroups(isBreastfed: boolean, hasPump: boolean): { label: string; types: EventType[] }[] { + const feedTypes: EventType[] = [ + ...(isBreastfed ? (["BREASTFEED"] as EventType[]) : []), + "BOTTLE", + ...(hasPump ? (["PUMP"] as EventType[]) : []), + "DIAPER_WET", + "DIAPER_STOOL", + ]; + return [ + { label: "Alimentation & Soins", types: feedTypes }, + { label: "Sommeil & Activités", types: ["NAP", "NIGHT_SLEEP", "BATH", "WALK", "TUMMY_TIME"] }, + { label: "Santé", types: ["TEMPERATURE", "MEDICATION", "SYMPTOM"] }, + { label: "Autre", types: ["OTHER"] }, + ]; +} interface Event { id: string; @@ -434,7 +431,7 @@ export default function DashboardPage() { queryKey: ["events-feeds", selectedBaby?.id], queryFn: () => fetch(`/api/events?babyId=${selectedBaby!.id}&limit=100&type=BREASTFEED`).then((r) => r.json()), - enabled: !!selectedBaby?.id, + enabled: !!selectedBaby?.id && (selectedBaby?.isBreastfed ?? true), staleTime: 60_000, }); const { data: bottleData } = useQuery({ @@ -577,8 +574,11 @@ export default function DashboardPage() { {/* Today's summary counters */} -
- {(["BREASTFEED", "BOTTLE", "DIAPER_WET", "DIAPER_STOOL"] as EventType[]).map((t) => { +
+ {(["BREASTFEED", "BOTTLE", "DIAPER_WET", "DIAPER_STOOL"] as EventType[]).filter((t) => { + if (t === "BREASTFEED" && !selectedBaby.isBreastfed) return false; + return true; + }).map((t) => { const cfg = EVENT_CONFIG[t]; return (
@@ -673,7 +673,7 @@ export default function DashboardPage() { {/* Quick log */}
- {QUICK_LOG_GROUPS.map((group) => ( + {buildQuickLogGroups(selectedBaby.isBreastfed, selectedBaby.hasPump).map((group) => (

{group.label}

diff --git a/src/app/(app)/settings/page.tsx b/src/app/(app)/settings/page.tsx index 1373f37..4be8f92 100644 --- a/src/app/(app)/settings/page.tsx +++ b/src/app/(app)/settings/page.tsx @@ -438,7 +438,7 @@ export default function SettingsPage() { const [dateTo, setDateTo] = useState(""); const [editingBaby, setEditingBaby] = useState(false); - const [babyForm, setBabyForm] = useState({ name: "", birthDate: "", gender: "" }); + const [babyForm, setBabyForm] = useState({ name: "", birthDate: "", gender: "", isBreastfed: true, hasPump: true }); const [savingBaby, setSavingBaby] = useState(false); const [thresholds, setThresholdsState] = useState(getThresholds); @@ -563,13 +563,15 @@ export default function SettingsPage() { setExportLoading(false); } - function startEditBaby(b?: { name: string; birthDate: string; gender?: string }) { + function startEditBaby(b?: { name: string; birthDate: string; gender?: string; isBreastfed?: boolean; hasPump?: boolean }) { const src = b ?? selectedBaby; if (!src) return; setBabyForm({ name: src.name, birthDate: src.birthDate.slice(0, 10), gender: src.gender ?? "", + isBreastfed: src.isBreastfed !== false, + hasPump: src.hasPump !== false, }); setEditingBaby(true); } @@ -696,6 +698,25 @@ export default function SettingsPage() {
+
+ + {[ + { key: "isBreastfed" as const, label: "Allaitement maternel" }, + { key: "hasPump" as const, label: "Tire-lait & stock lait" }, + ].map(({ key, label }) => ( + + ))} +
- {QUICK_TYPES.map((type) => { + {quickTypes.map((type) => { const cfg = EVENT_CONFIG[type]; return (