CLASSFUNC BLOG
We Share Our Knowledge
gửi thông báo với Reactjs and firebase
A Phi
5 Th09 2020 10:33

b1: enable service worker trong file index.js

import * as serviceWorker from './serviceWorker'
....
serviceWorker.register();

b2: tạo custom hook để đăng ký service worker

import {useEffect} from "react";

import {
    askUserPermission,
    createNotificationSubscription,
    getUserSubscription,
    isPushNotificationSupported,
    registerServiceWorker,
    subscriptionToDb
} from "../notifications/push-notifications";

const pushNotificationSupported = isPushNotificationSupported();

export default function usePushNotifications(user) {

    useEffect(() => {
        if (pushNotificationSupported && user.user_id) {
            onRegisterPubSub(user)
        }
    }, [user]);

    const onRegisterPubSub = async (user) => {
        try {
            // đăng ký calendar service worker
            await registerServiceWorker()
            // xin quyen tu user
            const consent = await askUserPermission()
            if (consent === "granted") {
                // neu dong y
                // kiem tra thong tin cu da co
                let subscription = await getUserSubscription();
                if (!subscription) {
                    subscription = await createNotificationSubscription()
                }
                await subscriptionToDb(JSON.parse(JSON.stringify(subscription)), user.user_id)
            }

        } catch (e) {
            console.log(e);
        }
    }
}

file push-notifications.js:

import {db} from '../firebaseConfig'
import {CALENDAR_COLLECTION} from "../config/constants";
import firebase from "firebase/app";

const pushServerPublicKey = "your key";

function urlBase64ToUint8Array(base64String) {
    const padding = '='.repeat((4 - base64String.length % 4) % 4);
    const base64 = (base64String + padding)
        .replace(/-/g, '+')
        .replace(/_/g, '/');

    const rawData = window.atob(base64);
    const outputArray = new Uint8Array(rawData.length);

    for (let i = 0; i < rawData.length; ++i) {
        outputArray[i] = rawData.charCodeAt(i);
    }
    return outputArray;
}


function isPushNotificationSupported() {
    return "serviceWorker" in navigator && "PushManager" in window;
}

async function askUserPermission() {
    return await Notification.requestPermission();
}


function registerServiceWorker() {
    return navigator.serviceWorker.register("/calendar-service-worker.js");
}

/**
 *
 * using the registered service worker creates a push notification subscription and returns it
 *
 */
async function createNotificationSubscription() {
    //wait for service worker installation to be ready
    const serviceWorker = await navigator.serviceWorker.ready;
    // subscribe and return the subscription
    return await serviceWorker.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(pushServerPublicKey)
    });
}


function getUserSubscription() {
    //wait for service worker installation to be ready, and then
    return navigator.serviceWorker.ready
        .then(function (serviceWorker) {
            return serviceWorker.pushManager.getSubscription();
        })
        .then(function (pushSubscription) {
            return pushSubscription;
        });
}

async function subscriptionToDb(sub, userId) {
    const userRef = db.doc(`${CALENDAR_COLLECTION}/${userId}`)
    await userRef.set({
        subscriptions: firebase.firestore.FieldValue.arrayUnion(sub)
    }, {merge: true})
}

async function subscribeUserToPush(user) {
    try {
        const registration = await navigator.serviceWorker.register('/calendar-service-worker.js')

        let sub = await registration.pushManager.getSubscription()
    } catch (e) {

    }

}

export {
    isPushNotificationSupported,
    askUserPermission,
    registerServiceWorker,
    createNotificationSubscription,
    getUserSubscription,
    subscriptionToDb,
    subscribeUserToPush
};

b3: tạo file service work trong thư mục public:

function receivePushNotification(event) {
    console.log("[Service Worker] Push Received.");
    const {image, tag, url, title, text} = event.data.json();

    const options = {
        data: url,
        body: text,
        // icon: image,
        vibrate: [200, 100, 200],
        // tag: tag,
        // image: image,
        badge: "https://calendar.geniam.com/favicon.ico",
    };
    event.waitUntil(self.registration.showNotification(title, options));
}

function openPushNotification(event) {
    event.notification.close();
    event.waitUntil(clients.openWindow(event.notification.data));
}

self.addEventListener("push", receivePushNotification);
self.addEventListener("notificationclick", openPushNotification);

b4: gọi hook vừa tạo trong file app.js

usePushNotifications(user);

xem thêm : https://github.com/nguyenphi990/reactjs-notifications