diff --git a/src/components/medications/sections/notifications-section.tsx b/src/components/medications/sections/notifications-section.tsx
index d4a089453..07d2eccff 100644
--- a/src/components/medications/sections/notifications-section.tsx
+++ b/src/components/medications/sections/notifications-section.tsx
@@ -201,7 +201,7 @@ export function NotificationsBody({
)}
- {status && status.channels.length > 0 && (
+ {Array.isArray(status?.channels) && status.channels.length > 0 && (
", () => {
expect(html).not.toContain('data-testid="notification-status-list"');
});
+ it("renders empty state instead of crashing when data is not an array", () => {
+ // Regression: the status endpoint returns `{ channels, events }` where
+ // `events` is an object map. A shape-drifted / poisoned cache read that
+ // hands the whole object to the card must not reach `.map` on a
+ // non-array and white-screen the notifications panel.
+ useQueryMock.mockReturnValue({
+ data: { channels: [], events: {} } as unknown as MockChannel[],
+ isLoading: false,
+ });
+ const html = render();
+ expect(html).toContain("No channels configured yet");
+ expect(html).not.toContain('data-testid="notification-status-list"');
+ });
+
it("paints Active badge for a healthy channel", () => {
setChannels([
{
diff --git a/src/components/settings/mood-reminder-card.tsx b/src/components/settings/mood-reminder-card.tsx
index 7d1340400..d4d7863dd 100644
--- a/src/components/settings/mood-reminder-card.tsx
+++ b/src/components/settings/mood-reminder-card.tsx
@@ -84,7 +84,7 @@ export function MoodReminderCard({
});
const enabled = optimistic ?? profile?.moodReminderEnabled ?? false;
- const reminderHour = optimisticHour ?? prefs?.mood.reminderHour ?? 22;
+ const reminderHour = optimisticHour ?? prefs?.mood?.reminderHour ?? 22;
async function handleToggle(next: boolean) {
setOptimistic(next);
diff --git a/src/components/settings/notification-status-card.tsx b/src/components/settings/notification-status-card.tsx
index fca8276c1..b0609ac8e 100644
--- a/src/components/settings/notification-status-card.tsx
+++ b/src/components/settings/notification-status-card.tsx
@@ -119,7 +119,12 @@ export function NotificationStatusCard() {
);
}
- const channels = data ?? [];
+ // Defensive: the status endpoint returns `{ channels, events }` where
+ // `events` is an object map, not an array. A stale or shape-drifted
+ // payload (or a cache read that kept the whole object instead of the
+ // `.channels` slice) must never reach `.map` on a non-array — guard the
+ // type here rather than white-screening the whole notifications panel.
+ const channels = Array.isArray(data) ? data : [];
if (channels.length === 0) {
return (