├── .gitignore ├── LICENSE ├── README.md ├── next.config.js ├── package.json ├── pages └── index.js ├── static └── js │ └── push-notification.js └── utils └── offline.js /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # next 13 | .next 14 | 15 | # misc 16 | .DS_Store 17 | .env 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 safei muslim 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # push-notifications-next-js 2 | Push Notification in Progressive Web Application(PWA) Using Firebase Messaging and Next JS 3 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin') 3 | 4 | module.exports = { 5 | webpack: (config, { dev }) => { 6 | const oldEntry = config.entry 7 | 8 | config.entry = () => 9 | oldEntry().then(entry => { 10 | entry['main.js'].push(path.resolve('/utils/offline')) 11 | return entry 12 | }) 13 | 14 | /* Enable only in Production */ 15 | if (!dev) { 16 | // Service Worker 17 | config.plugins.push( 18 | new SWPrecacheWebpackPlugin({ 19 | filename: 'sw.js', 20 | minify: false, 21 | staticFileGlobsIgnorePatterns: [/\.next\//], 22 | importScripts: ['/static/js/push-notifications.js'], 23 | staticFileGlobs: [ 24 | 'static/**/*' // Precache all static files by default 25 | ], 26 | forceDelete: true, 27 | runtimeCaching: [ 28 | // Example with different handlers 29 | { 30 | handler: 'fastest', 31 | urlPattern: /[.](png|jpg|css)/ 32 | }, 33 | { 34 | handler: 'networkFirst', 35 | urlPattern: /^http.*/ // cache all files 36 | } 37 | ] 38 | }) 39 | ) 40 | } 41 | return config 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fcm-pwa-next-js", 3 | "version": "1.0.0", 4 | "description": "push notification in pwa using firebase and next js", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "dev": "next", 9 | "build": "next build", 10 | "start": "next start" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/safeimuslim/FCM-PWA-NEXT-JS.git" 15 | }, 16 | "keywords": [ 17 | "push", 18 | "notification", 19 | "pwa", 20 | "firebase", 21 | "fcm", 22 | "next", 23 | "js" 24 | ], 25 | "author": "Safei Muslim (http://www.safeimuslim.com)", 26 | "license": "ISC", 27 | "bugs": { 28 | "url": "https://github.com/safeimuslim/FCM-PWA-NEXT-JS/issues" 29 | }, 30 | "homepage": "https://github.com/safeimuslim/FCM-PWA-NEXT-JS#readme", 31 | "dependencies": { 32 | "express": "^4.16.2", 33 | "firebase": "^4.6.1", 34 | "localforage": "^1.5.3", 35 | "next": "^4.1.4", 36 | "react": "^16.0.0", 37 | "react-dom": "^16.0.0", 38 | "webpack": "^3.8.1" 39 | }, 40 | "devDependencies": { 41 | "babel-eslint": "^7.2.3", 42 | "eslint": "^3.19.0", 43 | "sw-precache-webpack-plugin": "^0.11.4" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | export default () =>
Welcome to next.js!
2 | -------------------------------------------------------------------------------- /static/js/push-notification.js: -------------------------------------------------------------------------------- 1 | // curl -X POST --header "Authorization: key=AAAAhmWcgyI:APA91bGC7jtDxaH7tQsFH-zwjiNlwosbDPrvjuFBOlMTiyS60PbIq0aNy_I0-GwPWgVSQvQW2TesbgQdmAqvzr5dtLhE1dgfNMeGR4ijM1pidzNS_0TVifqpAI0PWN77LOSxZMOwvtem" --Header "Content-Type:application/json" https://fcm.googleapis.com/fcm/send -d "{\"to\":\"ftNQTdCWHEk:APA91bFkAp3T_8xtAPr2MWcnZOUN_2B6Uhe74oMD8xGtYgzZ9lsm7S4S6dTWY_YmnjO5Wo7auTtIkTtb0XBqQNrHoYdnbBIGYZMZQbB4gvrLUs49m9jCYveWzMpBwIhIV5QHkriomgVX\",\"data\":{\"notification\":{\"body\":\"Are you coming to our party?\",\"title\":\"This is a tester tester\",\"confirm\":\"https://developers.google.com/web/\",\"decline\":\"https://www.yahoo.com/\"}},\"priority\":10}" 2 | 3 | // Give the service worker access to Firebase Messaging. 4 | // Note that you can only use Firebase Messaging here, other Firebase libraries 5 | // are not available in the service worker. 6 | /** 7 | * import firebase 8 | * import firebase message 9 | */ 10 | 11 | importScripts('https://www.gstatic.com/firebasejs/4.6.0/firebase-app.js'); 12 | importScripts('https://www.gstatic.com/firebasejs/4.6.0/firebase-messaging.js'); 13 | 14 | /** 15 | * Initialize the Firebase app in the service worker by passing in the 16 | * [messagingSenderId] 17 | */ 18 | 19 | firebase.initializeApp({ 20 | 'messagingSenderId': '' 21 | }); 22 | 23 | /** 24 | * define message const 25 | */ 26 | 27 | const messaging = firebase.messaging(); 28 | 29 | /** 30 | * --- Installs service worker --- 31 | */ 32 | 33 | self.addEventListener('install', (event) => { 34 | console.log('Service worker installed'); 35 | }); 36 | 37 | /** 38 | * --- user click notification --- 39 | * --- get notification object --- 40 | * use event.notification.data 41 | */ 42 | 43 | self.addEventListener('notificationclick', (event) => { 44 | // Event actions derived from event.notification.data from data received 45 | var eventURL = event.notification.data; 46 | event.notification.close(); 47 | if (event.action === 'confirmAttendance') { 48 | clients.openWindow(eventURL.confirm); 49 | } else if (event.action === 'cancel') { 50 | clients.openWindow(eventURL.decline); 51 | } else { 52 | clients.openWindow(eventURL.open); 53 | } 54 | }, false); 55 | 56 | /** 57 | * --- received message(Background) --- 58 | * [CUSTOM] dont put notification element in payload 59 | * --- payload must be like this --- 60 | * payload : { 61 | * data: { 62 | * ... 63 | * notification: { 64 | * title: '' 65 | * body: '' 66 | * } 67 | * ... 68 | * } 69 | * } 70 | */ 71 | 72 | messaging.setBackgroundMessageHandler((payload) => { 73 | let data = JSON.parse(payload.data.custom_notification); 74 | let notificationTitle = data.title; 75 | let notificationOptions = { 76 | body: data.body, 77 | icon: 'https://image.flaticon.com/icons/png/128/107/107822.png', 78 | // options event 79 | actions: [ 80 | {action: 'confirmAttendance', title: '👍 Confirm attendance'}, 81 | {action: 'cancel', title: '👎 Not coming'} 82 | ], 83 | // For additional data to be sent to event listeners, needs to be set in this data {} 84 | data: {confirm: data.confirm, decline: data.decline, open: data.open} 85 | }; 86 | 87 | return self.registration.showNotification(notificationTitle, notificationOptions); 88 | }); -------------------------------------------------------------------------------- /utils/offline.js: -------------------------------------------------------------------------------- 1 | /** 2 | * import depedencies 3 | */ 4 | import * as firebase from 'firebase' 5 | import localforage from 'localforage' 6 | 7 | if (process.env.NODE_ENV === 'production' && typeof window !== 'undefined' && 'serviceWorker' in navigator) { 8 | /** 9 | * config options fcm 10 | */ 11 | const config = { 12 | apiKey: '', 13 | authDomain: '', 14 | databaseURL: '', 15 | projectId: '', 16 | storageBucket: '', 17 | messagingSenderId: '' 18 | } 19 | /** 20 | * initializaation firebase 21 | */ 22 | firebase.initializeApp(config) 23 | /** 24 | * initializaation firebase messaging 25 | */ 26 | const messaging = firebase.messaging() 27 | 28 | /** 29 | * On load register service worker 30 | */ 31 | window.addEventListener('load', () => { 32 | navigator.serviceWorker.register('sw.js').then((registration) => { 33 | /** 34 | * Successfully registers service worker 35 | */ 36 | messaging.useServiceWorker(registration) 37 | }) 38 | .then(() => { 39 | /** 40 | * request permission 41 | */ 42 | return messaging.requestPermission() 43 | }) 44 | .then(() => { 45 | /** 46 | * request token 47 | */ 48 | return messaging.getToken() 49 | }) 50 | .then((token) => { 51 | /** 52 | * save token to local storage, use when user login/register 53 | */ 54 | localforage.setItem('FCM_TOKEN', token) 55 | }) 56 | .catch((err) => { 57 | /** 58 | * failed registration 59 | */ 60 | console.log('ServiceWorker registration failed: ', err) 61 | }) 62 | }) 63 | 64 | /** 65 | * received message when web active(Foreground) 66 | */ 67 | messaging.onMessage(function (payload) { 68 | console.log('Message received. ', payload) 69 | }) 70 | } --------------------------------------------------------------------------------