Activity: guidelines above strip, interactive day chips
- Moved guidelines row ABOVE the 4-day strip (correct order) - 4-day strip: each chip is now tappable → opens a day-detail bottom sheet showing all logs for that day → each log row has ‹ › arrow; tap opens edit/delete action sheet → empty state tells mama to use Generate sample history to pre-fill → quick-add row at bottom (+ Feed / + Sleep / + Diaper) for fast logging Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a14d8e7043
commit
3db6fb2710
1 changed files with 108 additions and 25 deletions
|
|
@ -49,6 +49,7 @@ export default function ActivityPage() {
|
||||||
const [deleteConfirm, setDeleteConfirm] = useState(false);
|
const [deleteConfirm, setDeleteConfirm] = useState(false);
|
||||||
const [smartDefault, setSmartDefault] = useState<SmartDefault | null>(null);
|
const [smartDefault, setSmartDefault] = useState<SmartDefault | null>(null);
|
||||||
const [pendingDeleteId, setPendingDeleteId] = useState<{ id: string; type: string } | null>(null);
|
const [pendingDeleteId, setPendingDeleteId] = useState<{ id: string; type: string } | null>(null);
|
||||||
|
const [daySheetDate, setDaySheetDate] = useState<string | null>(null);
|
||||||
const childId = providerChildId ?? "";
|
const childId = providerChildId ?? "";
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -113,6 +114,7 @@ export default function ActivityPage() {
|
||||||
const dateStr = d.toDateString();
|
const dateStr = d.toDateString();
|
||||||
const dayLogs = logs.filter(l => new Date(l.loggedAt).toDateString() === dateStr);
|
const dayLogs = logs.filter(l => new Date(l.loggedAt).toDateString() === dateStr);
|
||||||
return {
|
return {
|
||||||
|
date: dateStr,
|
||||||
label: i === 0 ? "Today" : i === 1 ? "Yest." : d.toLocaleDateString("en-IN", { weekday: "short" }),
|
label: i === 0 ? "Today" : i === 1 ? "Yest." : d.toLocaleDateString("en-IN", { weekday: "short" }),
|
||||||
feed: dayLogs.filter(l => l.type === "feed").length,
|
feed: dayLogs.filter(l => l.type === "feed").length,
|
||||||
sleep: dayLogs.filter(l => l.type === "sleep").length,
|
sleep: dayLogs.filter(l => l.type === "sleep").length,
|
||||||
|
|
@ -213,31 +215,7 @@ export default function ActivityPage() {
|
||||||
|
|
||||||
{!loading && (
|
{!loading && (
|
||||||
<>
|
<>
|
||||||
{/* 4-day overview strip — oldest → newest (left → right) */}
|
{/* Collapsible guidelines card — above strip */}
|
||||||
<div className="grid grid-cols-4 gap-2 px-4 mb-3">
|
|
||||||
{[...last4Days].reverse().map(d => {
|
|
||||||
const isToday = d.label === "Today";
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={d.label}
|
|
||||||
className={`rounded-xl px-2 py-2 shadow-sm text-center ${
|
|
||||||
isToday
|
|
||||||
? "bg-rose-400 text-white"
|
|
||||||
: "bg-white dark:bg-gray-800"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<p className={`text-xs font-semibold mb-1 ${isToday ? "text-rose-100" : "text-gray-500 dark:text-gray-400"}`}>
|
|
||||||
{d.label}
|
|
||||||
</p>
|
|
||||||
<p className={`text-xs ${isToday ? "text-white" : "text-gray-600 dark:text-gray-300"}`}>🍼×{d.feed}</p>
|
|
||||||
<p className={`text-xs ${isToday ? "text-white" : "text-gray-600 dark:text-gray-300"}`}>😴×{d.sleep}</p>
|
|
||||||
<p className={`text-xs ${isToday ? "text-white" : "text-gray-600 dark:text-gray-300"}`}>🚼×{d.diaper}</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Collapsible guidelines card */}
|
|
||||||
{child && guide && showSuggested && (
|
{child && guide && showSuggested && (
|
||||||
<div className="mx-4 mb-3">
|
<div className="mx-4 mb-3">
|
||||||
<button
|
<button
|
||||||
|
|
@ -279,6 +257,29 @@ export default function ActivityPage() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* 4-day overview strip — oldest → newest, each chip tappable */}
|
||||||
|
<div className="grid grid-cols-4 gap-2 px-4 mb-3">
|
||||||
|
{[...last4Days].reverse().map(d => {
|
||||||
|
const isToday = d.label === "Today";
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={d.label}
|
||||||
|
onClick={() => setDaySheetDate(d.date)}
|
||||||
|
className={`rounded-xl px-2 py-2 shadow-sm text-center active:scale-95 transition-transform ${
|
||||||
|
isToday ? "bg-rose-400 text-white" : "bg-white dark:bg-gray-800"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<p className={`text-xs font-semibold mb-1 ${isToday ? "text-rose-100" : "text-gray-500 dark:text-gray-400"}`}>
|
||||||
|
{d.label}
|
||||||
|
</p>
|
||||||
|
<p className={`text-xs ${isToday ? "text-white" : "text-gray-600 dark:text-gray-300"}`}>🍼×{d.feed}</p>
|
||||||
|
<p className={`text-xs ${isToday ? "text-white" : "text-gray-600 dark:text-gray-300"}`}>😴×{d.sleep}</p>
|
||||||
|
<p className={`text-xs ${isToday ? "text-white" : "text-gray-600 dark:text-gray-300"}`}>🚼×{d.diaper}</p>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -441,6 +442,88 @@ export default function ActivityPage() {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Day detail sheet — tap a day chip to view & edit that day's logs */}
|
||||||
|
{daySheetDate && (() => {
|
||||||
|
const sheetLogs = logs
|
||||||
|
.filter(l => new Date(l.loggedAt).toDateString() === daySheetDate)
|
||||||
|
.sort((a, b) => new Date(b.loggedAt).getTime() - new Date(a.loggedAt).getTime());
|
||||||
|
const sheetLabel = formatDayLabel(daySheetDate);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className="fixed inset-0 bg-black/40 backdrop-blur-sm z-50"
|
||||||
|
onClick={() => setDaySheetDate(null)}
|
||||||
|
/>
|
||||||
|
<div className="fixed bottom-0 inset-x-0 z-50 bg-white dark:bg-gray-900 rounded-t-2xl shadow-xl flex flex-col max-h-[75vh]">
|
||||||
|
{/* Sheet header */}
|
||||||
|
<div className="flex items-center justify-between px-4 pt-4 pb-3 border-b border-gray-100 dark:border-gray-800">
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold text-gray-900 dark:text-white">{sheetLabel}</h3>
|
||||||
|
<p className="text-xs text-gray-400 mt-0.5">
|
||||||
|
{sheetLogs.length} log{sheetLogs.length !== 1 ? "s" : ""} · tap any entry to edit or delete
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => setDaySheetDate(null)}
|
||||||
|
className="p-2 text-gray-400 text-lg"
|
||||||
|
>✕</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Log list */}
|
||||||
|
<div className="overflow-y-auto flex-1 p-4 space-y-2">
|
||||||
|
{sheetLogs.length === 0 ? (
|
||||||
|
<div className="text-center py-10 text-gray-400">
|
||||||
|
<p className="text-3xl mb-2">📋</p>
|
||||||
|
<p className="text-sm font-medium">No logs for {sheetLabel}</p>
|
||||||
|
<p className="text-xs mt-1 text-gray-300">Use ⋯ → Generate sample history to pre-fill your schedule</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
sheetLogs.map(log => (
|
||||||
|
<button
|
||||||
|
key={log.id}
|
||||||
|
onClick={() => { setSelectedLog(log); setDeleteConfirm(false); setDaySheetDate(null); }}
|
||||||
|
className="w-full flex items-center gap-3 p-3 bg-gray-50 dark:bg-gray-800 rounded-xl text-left active:scale-[0.98] transition-transform"
|
||||||
|
>
|
||||||
|
<span className="text-2xl">{getIcon(log.type)}</span>
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<div className="font-medium capitalize">{log.type}</div>
|
||||||
|
<div className="text-sm text-gray-500 dark:text-gray-400 truncate">
|
||||||
|
{[
|
||||||
|
log.subType?.replace(/_/g, " "),
|
||||||
|
log.amount ? `${log.amount}ml` : null,
|
||||||
|
log.notes,
|
||||||
|
].filter(Boolean).join(" · ")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2 flex-shrink-0">
|
||||||
|
<span className="text-sm text-gray-400">
|
||||||
|
{new Date(log.loggedAt).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}
|
||||||
|
</span>
|
||||||
|
<span className="text-gray-300 text-lg">›</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Quick-add row */}
|
||||||
|
<div className="px-4 py-3 border-t border-gray-100 dark:border-gray-800 flex gap-2">
|
||||||
|
{(["feed", "sleep", "diaper"] as ModalLogType[]).map(t => (
|
||||||
|
<button
|
||||||
|
key={t}
|
||||||
|
onClick={() => { setDaySheetDate(null); setModalType(t); }}
|
||||||
|
className="flex-1 flex flex-col items-center gap-0.5 py-2 bg-gray-50 dark:bg-gray-800 rounded-xl text-sm"
|
||||||
|
>
|
||||||
|
<span className="text-lg">{t === "feed" ? "🍼" : t === "sleep" ? "😴" : "🚼"}</span>
|
||||||
|
<span className="text-xs text-gray-500 capitalize">+ {t}</span>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
|
||||||
<LogModal
|
<LogModal
|
||||||
type={modalType}
|
type={modalType}
|
||||||
childId={childId}
|
childId={childId}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue