Notification CenterLoading saved progress…

Notification Center

Build the bell-and-panel you see in the corner of every app: a bell button with a little unread badge, and a dropdown panel listing the notifications. The whole exercise turns on one idea — the badge is not a number you keep, it's a number you derive. Store the notifications; compute the unread count from them on every render.

What you'll build

The starter App.tsx renders the finished picture as a static mock-up — the bell with a red 3 badge and the panel open with four notifications (three unread, one read). Make it interactive:

  1. Hold the data. Keep the four notifications in useState ({ id, text, read }), plus an open boolean for the panel.
  2. Derive the badge. const unread = items.filter((n) => !n.read).length — render the badge only when unread > 0. Never store the count in its own state.
  3. Toggle the panel. Clicking the bell flips open; the panel renders only when open.
  4. Mark read / dismiss / mark all. Clicking a notification sets its read to true. Its × removes it from the list (and must not also mark it read). The Mark all read link sets every read to true.

Examples

  • Load: badge shows 3 (three unread), panel lists all four with a blue dot on the unread ones.
  • Click New comment on your post: it loses its dot and highlight, and the badge drops to 2.
  • Click Mark all read: every dot disappears and the badge vanishes entirely (unread is 0).
  • Click the × on Build #42 passed: that row is removed; the badge reflects the new unread count.

Notes

  • The badge is derived, never stored. A separate count state is the classic bug — it drifts out of sync the moment you forget to update it. Compute it from items.
  • × must stop the click. The dismiss button sits inside the clickable row, so its onClick needs e.stopPropagation() or dismissing also marks read.
  • Update immutably. map to a new array for read changes, filter for dismiss — don't mutate the objects in state in place.
  • Styling (dark panel, badge, dot) is already in styles.css; focus on the state.
Loading editor…
Loading preview…