Real-time Notifications — Realtime

Real-time Notifications Notification system: in-app toast, bell icon counter, push notification ke device. Tiga channel berbeda, satu trigger. Architecture Even

Real-time Notifications

Notification system: in-app toast, bell icon counter, push notification ke device. Tiga channel berbeda, satu trigger.

Architecture

Event → Notification Service → DB (persist)
                              → WebSocket/SSE (in-app)
                              → Push API (browser push)
                              → FCM/APNS (mobile push)

In-app Notifications

// Server: emit saat notification dibuat
async function createNotification(userId, data) {
  const notification = await db.notifications.create({
    data: { userId, ...data, read: false },
  });

  // Push via WebSocket
  io.to(`user:${userId}`).emit("notification:new", notification);

  return notification;
}

// Client: React hook
function useNotifications() {
  const [notifications, setNotifications] = useState([]);
  const [unreadCount, setUnreadCount] = useState(0);

  useEffect(() => {
    socket.on("notification:new", (notif) => {
      setNotifications(prev => [notif, ...prev]);
      setUnreadCount(prev => prev + 1);
      showToast(notif.message); // toast popup
    });
  }, []);

  const markRead = async (id) => {
    await fetch(`/api/notifications/${id}/read`, { method: "POST" });
    setNotifications(prev =>
      prev.map(n => n.id === id ? { ...n, read: true } : n)
    );
    setUnreadCount(prev => prev - 1);
  };

  return { notifications, unreadCount, markRead };
}

Browser Push Notifications

// Request permission
const permission = await Notification.requestPermission();

if (permission === "granted") {
  // Register service worker for push
  const registration = await navigator.serviceWorker.register("/sw.js");
  const subscription = await registration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: VAPID_PUBLIC_KEY,
  });

  // Send subscription to server
  await fetch("/api/push/subscribe", {
    method: "POST",
    body: JSON.stringify(subscription),
  });
}

// Service Worker (sw.js)
self.addEventListener("push", (event) => {
  const data = event.data.json();
  self.registration.showNotification(data.title, {
    body: data.body,
    icon: "/icon-192.png",
  });
});

Notification Preferences

Yang akan kamu pelajari