Activity: each feed/sleep/diaper row independently tappable in 4-day strip

Each row in a day chip is now its own button. Tapping 🍼×2 on Thursday
opens a sheet scoped to feeds on Thursday only — not all logs for that day.
Sheet shows entries for that specific type, with edit/delete per entry and
a single focused "+ Add [type]" CTA at the bottom.
Rows showing ×0 render dimmed so missing entries stand out at a glance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Manohar Gupta 2026-05-24 00:26:43 +05:30
parent 3db6fb2710
commit 5297ab76ba

View file

@ -49,7 +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 [daySheetDate, setDaySheetDate] = useState<{ date: string; type: LogType } | null>(null);
const childId = providerChildId ?? ""; const childId = providerChildId ?? "";
useEffect(() => { useEffect(() => {
@ -258,25 +258,50 @@ export default function ActivityPage() {
</div> </div>
)} )}
{/* 4-day overview strip — oldest → newest, each chip tappable */} {/* 4-day overview strip — oldest → newest, each row independently tappable */}
<div className="grid grid-cols-4 gap-2 px-4 mb-3"> <div className="grid grid-cols-4 gap-2 px-4 mb-3">
{[...last4Days].reverse().map(d => { {[...last4Days].reverse().map(d => {
const isToday = d.label === "Today"; const isToday = d.label === "Today";
const rows: { type: LogType; icon: string; count: number }[] = [
{ type: "feed", icon: "🍼", count: d.feed },
{ type: "sleep", icon: "😴", count: d.sleep },
{ type: "diaper", icon: "🚼", count: d.diaper },
];
return ( return (
<button <div
key={d.label} key={d.label}
onClick={() => setDaySheetDate(d.date)} className={`rounded-xl shadow-sm overflow-hidden ${
className={`rounded-xl px-2 py-2 shadow-sm text-center active:scale-95 transition-transform ${ isToday ? "bg-rose-400" : "bg-white dark:bg-gray-800"
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"}`}> {/* Day label — non-interactive header */}
<div className={`text-xs font-semibold text-center py-1.5 ${
isToday ? "text-rose-100" : "text-gray-500 dark:text-gray-400"
}`}>
{d.label} {d.label}
</p> </div>
<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> {/* Each row is its own tap target */}
<p className={`text-xs ${isToday ? "text-white" : "text-gray-600 dark:text-gray-300"}`}>🚼×{d.diaper}</p> {rows.map((row, idx) => (
<button
key={row.type}
onClick={() => setDaySheetDate({ date: d.date, type: row.type })}
className={`w-full flex items-center justify-center py-1.5 text-xs active:opacity-60 transition-opacity ${
idx === 0
? isToday ? "border-t border-rose-300" : "border-t border-gray-100 dark:border-gray-700"
: isToday ? "border-t border-rose-300" : "border-t border-gray-100 dark:border-gray-700"
} ${
isToday
? "text-white"
: row.count === 0
? "text-gray-300 dark:text-gray-600"
: "text-gray-700 dark:text-gray-200"
}`}
>
{row.icon}×{row.count}
</button> </button>
))}
</div>
); );
})} })}
</div> </div>
@ -442,12 +467,18 @@ export default function ActivityPage() {
</> </>
)} )}
{/* Day detail sheet — tap a day chip to view & edit that day's logs */} {/* Day-type detail sheet — tap a specific row (feed/sleep/diaper) on a day chip */}
{daySheetDate && (() => { {daySheetDate && (() => {
const { date: sheetDateStr, type: sheetType } = daySheetDate;
const sheetLogs = logs const sheetLogs = logs
.filter(l => new Date(l.loggedAt).toDateString() === daySheetDate) .filter(l =>
new Date(l.loggedAt).toDateString() === sheetDateStr &&
l.type === sheetType
)
.sort((a, b) => new Date(b.loggedAt).getTime() - new Date(a.loggedAt).getTime()); .sort((a, b) => new Date(b.loggedAt).getTime() - new Date(a.loggedAt).getTime());
const sheetLabel = formatDayLabel(daySheetDate); const sheetDayLabel = formatDayLabel(sheetDateStr);
const sheetTypeIcon = getIcon(sheetType);
const sheetTypeLabel = sheetType.charAt(0).toUpperCase() + sheetType.slice(1);
return ( return (
<> <>
<div <div
@ -457,12 +488,19 @@ export default function ActivityPage() {
<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]"> <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 */} {/* 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 className="flex items-center justify-between px-4 pt-4 pb-3 border-b border-gray-100 dark:border-gray-800">
<div className="flex items-center gap-2">
<span className="text-2xl">{sheetTypeIcon}</span>
<div> <div>
<h3 className="font-semibold text-gray-900 dark:text-white">{sheetLabel}</h3> <h3 className="font-semibold text-gray-900 dark:text-white">
{sheetTypeLabel} · {sheetDayLabel}
</h3>
<p className="text-xs text-gray-400 mt-0.5"> <p className="text-xs text-gray-400 mt-0.5">
{sheetLogs.length} log{sheetLogs.length !== 1 ? "s" : ""} · tap any entry to edit or delete {sheetLogs.length === 0
? "Nothing logged — tap + to add"
: `${sheetLogs.length} entr${sheetLogs.length === 1 ? "y" : "ies"} · tap to edit or delete`}
</p> </p>
</div> </div>
</div>
<button <button
onClick={() => setDaySheetDate(null)} onClick={() => setDaySheetDate(null)}
className="p-2 text-gray-400 text-lg" className="p-2 text-gray-400 text-lg"
@ -473,9 +511,11 @@ export default function ActivityPage() {
<div className="overflow-y-auto flex-1 p-4 space-y-2"> <div className="overflow-y-auto flex-1 p-4 space-y-2">
{sheetLogs.length === 0 ? ( {sheetLogs.length === 0 ? (
<div className="text-center py-10 text-gray-400"> <div className="text-center py-10 text-gray-400">
<p className="text-3xl mb-2">📋</p> <p className="text-4xl mb-2">{sheetTypeIcon}</p>
<p className="text-sm font-medium">No logs for {sheetLabel}</p> <p className="text-sm font-medium">No {sheetType} logged for {sheetDayLabel}</p>
<p className="text-xs mt-1 text-gray-300">Use Generate sample history to pre-fill your schedule</p> <p className="text-xs mt-1 text-gray-300">
Tap + below to add one, or use Generate sample history
</p>
</div> </div>
) : ( ) : (
sheetLogs.map(log => ( sheetLogs.map(log => (
@ -484,7 +524,7 @@ export default function ActivityPage() {
onClick={() => { setSelectedLog(log); setDeleteConfirm(false); setDaySheetDate(null); }} 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" 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> <span className="text-2xl">{sheetTypeIcon}</span>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="font-medium capitalize">{log.type}</div> <div className="font-medium capitalize">{log.type}</div>
<div className="text-sm text-gray-500 dark:text-gray-400 truncate"> <div className="text-sm text-gray-500 dark:text-gray-400 truncate">
@ -506,18 +546,15 @@ export default function ActivityPage() {
)} )}
</div> </div>
{/* Quick-add row */} {/* Single add button for this specific type */}
<div className="px-4 py-3 border-t border-gray-100 dark:border-gray-800 flex gap-2"> <div className="px-4 py-3 border-t border-gray-100 dark:border-gray-800">
{(["feed", "sleep", "diaper"] as ModalLogType[]).map(t => (
<button <button
key={t} onClick={() => { setDaySheetDate(null); setModalType(sheetType as ModalLogType); }}
onClick={() => { setDaySheetDate(null); setModalType(t); }} className="w-full flex items-center justify-center gap-2 py-3 bg-rose-400 text-white rounded-xl font-medium"
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>{sheetTypeIcon}</span>
<span className="text-xs text-gray-500 capitalize">+ {t}</span> <span>+ Add {sheetTypeLabel}</span>
</button> </button>
))}
</div> </div>
</div> </div>
</> </>