diff --git a/src/app/(app)/dashboard/page.tsx b/src/app/(app)/dashboard/page.tsx
index 6265d65..d0c790f 100644
--- a/src/app/(app)/dashboard/page.tsx
+++ b/src/app/(app)/dashboard/page.tsx
@@ -70,6 +70,7 @@ function getEventSummary(event: Event): string {
if ((event.type === "NAP" || event.type === "NIGHT_SLEEP") && event.endedAt) {
return formatDuration(new Date(event.startedAt), new Date(event.endedAt));
}
+ if (event.type === "OTHER") return event.notes ? event.notes.slice(0, 50) : "";
return "";
}
diff --git a/src/app/(app)/reminders/page.tsx b/src/app/(app)/reminders/page.tsx
index 63a4eb7..908f440 100644
--- a/src/app/(app)/reminders/page.tsx
+++ b/src/app/(app)/reminders/page.tsx
@@ -3,7 +3,9 @@
import { useState } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useBaby } from "@/contexts/baby-context";
-import { Plus, Trash2, Bell, BellOff, Clock } from "lucide-react";
+import { Plus, Trash2, Bell, BellOff, Clock, CheckCircle2, RotateCcw } from "lucide-react";
+import { formatDistanceToNow } from "date-fns";
+import { fr } from "date-fns/locale";
interface Reminder {
id: string;
@@ -72,6 +74,24 @@ export default function RemindersPage() {
qc.invalidateQueries({ queryKey: ["reminders"] });
}
+ async function markTaken(id: string) {
+ await fetch(`/api/reminders/${id}`, {
+ method: "PATCH",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ lastSentAt: new Date().toISOString() }),
+ });
+ qc.invalidateQueries({ queryKey: ["reminders"] });
+ }
+
+ async function unmarkTaken(id: string) {
+ await fetch(`/api/reminders/${id}`, {
+ method: "PATCH",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ lastSentAt: null }),
+ });
+ qc.invalidateQueries({ queryKey: ["reminders"] });
+ }
+
async function deleteReminder(id: string) {
if (!confirm("Supprimer ce rappel ?")) return;
await fetch(`/api/reminders/${id}`, { method: "DELETE" });
@@ -175,8 +195,31 @@ export default function RemindersPage() {
{nextDueLabel(r)}
)}
+ {r.lastSentAt && (
+
+
+ Pris {formatDistanceToNow(new Date(r.lastSentAt), { locale: fr, addSuffix: true })}
+
+ )}
+ {r.lastSentAt ? (
+
+ ) : (
+
+ )}
+ {/* Activities */}
+
+
Activités par jour
+
Bain · Balade · Plat ventre · Autre
+
+
+
+
+ [val, "Activités"]} contentStyle={tooltipStyle} cursor={{ fill: cursorFill }} />
+
+
+
+
+
{/* Sleep */}
Sommeil par jour (heures)
diff --git a/src/app/(app)/timeline/page.tsx b/src/app/(app)/timeline/page.tsx
index 4584d8a..47dd48f 100644
--- a/src/app/(app)/timeline/page.tsx
+++ b/src/app/(app)/timeline/page.tsx
@@ -65,6 +65,7 @@ function getEventSummary(event: Event): string {
if ((event.type === "NAP" || event.type === "NIGHT_SLEEP") && event.endedAt) {
return formatDuration(new Date(event.startedAt), new Date(event.endedAt));
}
+ if (event.type === "OTHER") return event.notes ? event.notes.slice(0, 50) : "";
return "";
}
diff --git a/src/app/api/reminders/[id]/route.ts b/src/app/api/reminders/[id]/route.ts
index e16bb5e..14000ba 100644
--- a/src/app/api/reminders/[id]/route.ts
+++ b/src/app/api/reminders/[id]/route.ts
@@ -26,6 +26,7 @@ export async function PATCH(
...(body.intervalHours !== undefined ? { intervalHours: parseFloat(body.intervalHours) } : {}),
...(body.startAt !== undefined ? { startAt: new Date(body.startAt) } : {}),
...(body.enabled !== undefined ? { enabled: body.enabled } : {}),
+ ...(body.lastSentAt !== undefined ? { lastSentAt: body.lastSentAt ? new Date(body.lastSentAt) : null } : {}),
},
});
diff --git a/src/components/event-modal.tsx b/src/components/event-modal.tsx
index 7e60476..33f3a5b 100644
--- a/src/components/event-modal.tsx
+++ b/src/components/event-modal.tsx
@@ -249,8 +249,8 @@ export function EventModal({ type, babyId, onClose, onSaved, initialEvent }: Pro
async function handlePhotoChange(e: React.ChangeEvent
) {
const file = e.target.files?.[0];
if (!file) return;
- if (file.size > 5 * 1024 * 1024) {
- alert("Image trop volumineuse (max 5 Mo)");
+ if (file.size > 30 * 1024 * 1024) {
+ alert("Image trop volumineuse (max 30 Mo)");
return;
}
setPhotoUploading(true);
@@ -363,6 +363,9 @@ export function EventModal({ type, babyId, onClose, onSaved, initialEvent }: Pro
});
if (diaperBoth && (type === "DIAPER_WET" || type === "DIAPER_STOOL")) {
const secondType = type === "DIAPER_WET" ? "DIAPER_STOOL" : "DIAPER_WET";
+ const secondMeta = type === "DIAPER_WET"
+ ? { color: form.stoolColor, amount: form.stoolAmount }
+ : null;
await fetch("/api/events", {
method: "POST",
headers: { "Content-Type": "application/json" },
@@ -372,7 +375,7 @@ export function EventModal({ type, babyId, onClose, onSaved, initialEvent }: Pro
startedAt: toUTC(form.startedAt),
endedAt: null,
notes: null,
- metadata: null,
+ metadata: secondMeta,
}),
});
}
@@ -657,16 +660,47 @@ export function EventModal({ type, babyId, onClose, onSaved, initialEvent }: Pro
{/* Combined diaper toggle */}
{(type === "DIAPER_WET" || type === "DIAPER_STOOL") && !isEditing && (
-
+
+
+ {diaperBoth && type === "DIAPER_WET" && (
+
+
+
+
+ {STOOL_COLORS.map(({ value, label, bg, dot }) => (
+
+ ))}
+
+
+
+
+
+ {(["small", "medium", "large"] as const).map((amt) => (
+
+ ))}
+
+
+
+ )}
+
)}
{/* Medication — profile picker */}
diff --git a/src/components/quick-add-fab.tsx b/src/components/quick-add-fab.tsx
index fbc88ce..306b281 100644
--- a/src/components/quick-add-fab.tsx
+++ b/src/components/quick-add-fab.tsx
@@ -74,7 +74,7 @@ export function QuickAddFab() {
-
+
{QUICK_TYPES.map((type) => {
const cfg = EVENT_CONFIG[type];
return (