NotifMoo JavaScript Client

Dokumentasi cara menggunakan NotifMoo via CDN untuk menerima notifikasi real‑time dari Notif.

← Kembali ke Dashboard

1. Menambahkan CDN

Tambahkan skrip berikut di bagian <head> atau sebelum </body> pada aplikasi Anda. Ganti YOUR_API_KEY dengan API key domain yang Anda buat di Dashboard.

<script src="https://cdn.jsdelivr.net/gh/pimphand/notifmoo_@main/setup.js?apikey=YOUR_API_KEY"></script>

Anda juga bisa menambahkan parameter opsional host bila ingin mengarah ke endpoint WebSocket lain:

<script src="https://cdn.jsdelivr.net/gh/pimphand/notifmoo_@main/setup.js?apikey=YOUR_API_KEY&host=wss://notification.officialconnect.id"></script>

Catatan: Origin (domain) halaman Anda harus sama dengan domain yang terdaftar di Dashboard agar API key valid.

2. Objek Global NotifMoo

Setelah skrip CDN dimuat, library akan otomatis mencoba konek ke WebSocket dan menambahkan objek global NotifMoo.

  • NotifMoo.connect(): memulai koneksi (biasanya otomatis dipanggil).
  • NotifMoo.subscribe(channel, options): subscribe ke channel tertentu.
  • NotifMoo.unsubscribe(channel): unsubscribe dari channel.
  • NotifMoo.bind(event, callback): listen event global tertentu.
  • NotifMoo.onConnect(callback): dipanggil ketika koneksi berhasil.
  • NotifMoo.onError(callback): menangkap error koneksi.

Library ini mirip dengan client Pusher: setiap pesan memiliki event, channel, dan data.

3. Contoh Sederhana

Contoh halaman HTML lengkap yang subscribe ke channel publik dan menampilkan pesan yang diterima.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>NotifMoo Demo</title>
  <script src="https://cdn.jsdelivr.net/gh/pimphand/notifmoo_@main/setup.js?apikey=YOUR_API_KEY"></script>
</head>
<body>
  <h1>NotifMoo Demo</h1>
  <pre id="log"></pre>

  <script>
    function log(line) {
      document.getElementById('log').textContent += line + '\n';
    }

    NotifMoo.onConnect(function () {
      log('Connected! socket_id=' + NotifMoo.socketId);

      // Subscribe ke channel, misalnya "public-demo"
      NotifMoo.subscribe('public-demo', {
        onMessage: function (msg) {
          log('[channel=' + msg.channel + '] event=' + msg.event + ' data=' + JSON.stringify(msg.data));
        }
      });
    });

    NotifMoo.onError(function (err) {
      log('ERROR: ' + err.message + (err.code ? ' (code=' + err.code + ')' : ''));
    });
  </script>
</body>
</html>

4. Contoh dengan Channel Per‑User

Misalkan backend Anda mengirim notifikasi ke channel seperti user.123 (123 = ID user). Berikut contoh cara subscribe dari frontend:

// Misal Anda sudah tahu userId dari session / blade / JS
const userId = 123;
const channelName = `user.${userId}`;

NotifMoo.onConnect(function () {
  NotifMoo.subscribe(channelName, {
    onMessage: function (msg) {
      console.log('New notification for user', msg);
    }
  });
});

5. Event Global

Selain onMessage per‑channel, Anda bisa menangkap semua event yang masuk dengan event global:

// Semua event (debugging)
NotifMoo.bind('*', function (payload) {
  console.log('EVENT', payload.event, 'CHANNEL', payload.channel, 'DATA', payload.data);
});

// Event khusus, misalnya "order.updated"
NotifMoo.bind('order.updated', function (payload) {
  console.log('Order updated:', payload.data);
});

6. Contoh Aplikasi Chat Sederhana

Contoh berikut adalah versi sederhana dari file demo chat-demo.html: tampilan bubble mirip WhatsApp, subscribe ke satu channel, dan mengirim pesan menggunakan HTTP API POST /api/broadcast.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>NotifMoo Chat Demo</title>
  <style>
    body { font-family: system-ui, sans-serif; margin: 0; padding: 16px; background: #f1f5f9; }
    .card { max-width: 480px; margin: 0 auto; background: #fff; border-radius: 12px; box-shadow: 0 10px 15px -3px rgba(15,23,42,0.1), 0 4px 6px -4px rgba(15,23,42,0.1); padding: 16px; }
    #messages { border: 1px solid #e2e8f0; border-radius: 8px; padding: 8px; height: 260px; overflow-y: auto; background: #f8fafc; font-size: 14px; display: flex; flex-direction: column; gap: 4px; }
    .msg-row { display: flex; margin-bottom: 4px; }
    .msg-row.msg-other { justify-content: flex-start; }
    .msg-row.msg-me { justify-content: flex-end; }
    .msg-bubble { max-width: 80%; border-radius: 12px; padding: 6px 8px; box-shadow: 0 1px 1px rgba(15,23,42,0.08); word-wrap: break-word; }
    .msg-row.msg-other .msg-bubble { background: #ffffff; }
    .msg-row.msg-me .msg-bubble { background: #dcfce7; }
    .msg-name { font-size: 10px; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase; color: #64748b; margin-bottom: 2px; }
    .msg-text { font-size: 13px; color: #0f172a; }
    .inputs { display: flex; gap: 6px; margin-top: 8px; }
    .inputs input { border-radius: 6px; border: 1px solid #cbd5f5; padding: 6px 8px; font-size: 13px; }
    .inputs input[name="name"] { width: 110px; }
    .inputs input[name="text"] { flex: 1; }
    button { border-radius: 6px; border: none; background: #4f46e5; color: #fff; padding: 6px 10px; font-size: 13px; cursor: pointer; white-space: nowrap; }
  </style>
  <!-- Ganti YOUR_API_KEY dengan API key domain Anda -->
  <script src="https://cdn.jsdelivr.net/gh/pimphand/notifmoo_@main/setup.js?apikey=YOUR_API_KEY"></script>
</head>
<body>
  <div class="card">
    <h1>NotifMoo Chat Demo</h1>
    <div class="meta" id="meta" style="font-size:11px;color:#94a3b8;margin-bottom:6px;"></div>
    <div id="messages"></div>
    <div class="inputs">
      <input id="name" name="name" placeholder="Nama Anda" />
      <input id="text" name="text" placeholder="Tulis pesan..." />
      <button id="send">Kirim</button>
    </div>
  </div>

  <script>
    function getQueryParam(key, fallback) {
      const params = new URLSearchParams(window.location.search);
      return params.get(key) || fallback;
    }

    const room = getQueryParam('room', 'chat.room1');
    const defaultName = getQueryParam('name', 'Client');

    const nameInput = document.getElementById('name');
    const textInput = document.getElementById('text');
    const sendBtn = document.getElementById('send');
    const metaEl = document.getElementById('meta');
    const messagesEl = document.getElementById('messages');

    nameInput.value = defaultName;
    metaEl.textContent = 'Channel: ' + room + ' — socket: connecting...';

    const recentKeys = [];
    function isDuplicateMessage(payload) {
      try {
        const key = JSON.stringify(payload || {});
        if (recentKeys.indexOf(key) !== -1) return true;
        recentKeys.push(key);
        if (recentKeys.length > 50) recentKeys.shift();
        return false;
      } catch (e) {
        return false;
      }
    }

    function addMessage(payload) {
      if (isDuplicateMessage(payload)) return;
      const data = (payload && payload.data) || {};
      const name = data.name || 'anon';
      const text = data.text || '';

      const row = document.createElement('div');
      const isMe = (nameInput.value || defaultName) === name;
      row.className = 'msg-row ' + (isMe ? 'msg-me' : 'msg-other');

      const bubble = document.createElement('div');
      bubble.className = 'msg-bubble';

      const nameEl = document.createElement('div');
      nameEl.className = 'msg-name';
      nameEl.textContent = name.toUpperCase();

      const textEl = document.createElement('div');
      textEl.className = 'msg-text';
      textEl.textContent = text;

      bubble.appendChild(nameEl);
      bubble.appendChild(textEl);
      row.appendChild(bubble);
      messagesEl.appendChild(row);
      messagesEl.scrollTop = messagesEl.scrollHeight;
    }

    NotifMoo.onConnect(function () {
      metaEl.textContent = 'Channel: ' + room + ' — connected, menunggu socket_id...';
      NotifMoo.subscribe(room, {
        onMessage: function (msg) { addMessage(msg); }
      });
    });

    NotifMoo.bind('connection_established', function (payload) {
      if (!payload || !payload.socket_id) return;
      metaEl.textContent = 'Channel: ' + room + ' — socket_id: ' + payload.socket_id;
    });

    NotifMoo.onError(function (err) {
      metaEl.textContent = 'ERROR: ' + err.message + (err.code ? ' (code=' + err.code + ')' : '');
    });

    sendBtn.addEventListener('click', function () {
      const name = nameInput.value || 'anon';
      const text = textInput.value;
      if (!text) return;
      textInput.value = '';

      // Kirim pesan via HTTP API resmi Notif (POST /api/broadcast)
      fetch('https://notification.officialconnect.id/api/broadcast', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-app-key': 'YOUR_APP_KEY'
        },
        body: JSON.stringify({
          channel: room,
          event: 'chat.message',
          data: { name, text }
        })
      }).catch(function (e) {
        console.error('Gagal kirim pesan', e);
      });
    });
  </script>
</body>
</html>

Ganti YOUR_API_KEY dan YOUR_APP_KEY dengan kredensial dari Dashboard. Untuk demo penuh yang bisa membuka dua jendela sekaligus dengan channel acak, gunakan tombol di bagian berikutnya (Demo Cepat).

7. Demo Cepat: Buka 2 Jendela Chat

Untuk mencoba dua client chat sekaligus, klik tombol di bawah ini. Halaman akan membuka dua jendela baru: masing‑masing menggunakan nama berbeda (Chat 1 dan Chat 2) pada satu channel yang sama, tetapi nama channel tersebut dibuat acak setiap kali tombol diklik sehingga sesi Anda terisolasi dari pengguna lain.

File yang dipakai: chat-demo.html. Parameter query ?name=Chat+1 dan ?name=Chat+2 hanya mengisi nama default di input, sedangkan parameter ?room=chat.demo.<random> dibuat acak setiap klik.