Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding FCM Notifications #133

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center"><a href="http://bhansa.github.io"><img src="https://avatars0.githubusercontent.com/u/9723884?v=4" width="100px;" alt="Bharat Saraswat"/><br /><sub><b>Bharat Saraswat</b></sub></a><br /><a href="https://github.com/HydPy/hydpyconf2019/commits?author=bhansa" title="Code">💻</a> <a href="#design-bhansa" title="Design">🎨</a> <a href="#ideas-bhansa" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/HydPy/hydpyconf2019/issues?q=author%3Abhansa" title="Bug reports">🐛</a> <a href="#review-bhansa" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/HydPy/hydpyconf2019/commits?author=bhansa" title="Tests">⚠️</a> <a href="#content-bhansa" title="Content">🖋</a> <a href="#maintenance-bhansa" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://ilovefoss.wordpress.com/"><img src="https://avatars1.githubusercontent.com/u/10486343?v=4" width="100px;" alt="Ananyo Maiti"/><br /><sub><b>Ananyo Maiti</b></sub></a><br /><a href="https://github.com/HydPy/hydpyconf2019/commits?author=ananyo2012" title="Code">💻</a> <a href="#review-ananyo2012" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/HydPy/hydpyconf2019/issues?q=author%3Aananyo2012" title="Bug reports">🐛</a> <a href="#content-ananyo2012" title="Content">🖋</a> <a href="#infra-ananyo2012" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-ananyo2012" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://github.com/aditya-369"><img src="https://avatars0.githubusercontent.com/u/16273418?v=4" width="100px;" alt="aditya_369"/><br /><sub><b>aditya_369</b></sub></a><br /><a href="https://github.com/HydPy/hydpyconf2019/commits?author=aditya-369" title="Code">💻</a></td>
<td align="center"><a href="https://aarshad.com"><img src="https://avatars0.githubusercontent.com/u/8903070?&v=4" width="100px;" alt="Aarshad Devani"/><br /><sub><b>Aarshad Devani</b></sub></a><br /><a href="https://github.com/HydPy/hydpyconf2019/commits?author=aarshad786" title="Code">💻</a></td>
</tr>
</table>

Expand Down
4 changes: 4 additions & 0 deletions _includes/head.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@
<link id="theme-style" rel="stylesheet" href="{{ site.baseurl }}assets/css/main.css">
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-148993906-1"></script>
<!-- Firebase Related -->
<script src="https://www.gstatic.com/firebasejs/7.4.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.4.0/firebase-messaging.js"></script>

<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
Expand Down
1 change: 1 addition & 0 deletions _includes/scripts.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
<script src="assets/plugins/back-to-top.js"></script>
<script src="assets/plugins/jquery.scrollTo.min.js"></script>
<script src="assets/js/main.js"></script>
<script src="assets/js/notifications.js"></script>
<script>var speakers = {{ site.data.speakers | jsonify }};</script>
173 changes: 173 additions & 0 deletions assets/js/notifications.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
const publicVapidKey =
"BAK9aUUilxzljIZVaKm8gjt6MWYsXQFbhluMMCFCddHbWug4_H48Q4XtbCwBSPZ9V3wcNUGr92twrEbmGMyABKU";
const firebaseConfig = {
apiKey: "AIzaSyCZ8gbWs9FLlzw93BOj_OQzlWwd_F1N-IY",
aarshad-devani marked this conversation as resolved.
Show resolved Hide resolved
authDomain: "pyconhyd.firebaseapp.com",
databaseURL: "https://pyconhyd.firebaseio.com",
projectId: "pyconhyd",
storageBucket: "pyconhyd.appspot.com",
messagingSenderId: "254977934750",
appId: "1:254977934750:web:9f1ad0357425e5718d828f"
};
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
messaging.usePublicVapidKey(publicVapidKey);

const tokenDivId = "token_div";
const permissionDivId = "permission_div";

messaging.onTokenRefresh(() => {
messaging
.getToken()
.then(refreshedToken => {
console.log("Token refreshed.");
setTokenSentToServer(false);
sendTokenToServer(refreshedToken);
// Display new Instance ID token and clear UI of all previous messages.
resetUI();
})
.catch(err => {
console.log("Unable to retrieve refreshed token ", err);
showToken("Unable to retrieve refreshed token ", err);
});
});

messaging.onMessage(payload => {
console.log("Message received. ", payload);
// Update the UI to include the received message.
appendMessage(payload);
});

function resetUI() {
clearMessages();
showToken("loading...");
messaging
.getToken()
.then(currentToken => {
if (currentToken) {
sendTokenToServer(currentToken);
updateUIForPushEnabled(currentToken);
} else {
// Show permission request.
console.log(
"No Instance ID token available. Request permission to generate one."
);
// Show permission UI.
updateUIForPushPermissionRequired();
setTokenSentToServer(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this line required ? As per my understanding "sentToServer" should be 1 and it gets set when resetUI() is called after getting permission. Why are we setting it to 0 after that using this function call ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are resetting the variable in storage... once the permission will be received the it is set back again... this is evident in updateUIForPushPermissionRequired() where requestPermission() is called

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this line appear before updateUIForPushPermissionRequired() in that case ?

}
})
.catch(err => {
console.log("An error occurred while retrieving token. ", err);
showToken("Error retrieving Instance ID token. ", err);
setTokenSentToServer(false);
});
}

// [TODO] - write code here to show on UI, this is not exactly notification handled
function showToken(currentToken) {
// Show token in console and UI.
const tokenElement = document.querySelector("#token");
!!tokenElement && (tokenElement.textContent = currentToken);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the double ! required here ? document.querySelector returns null if element isn't found

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

converting to boolean value using !! to ensure that token exists.. This can be removed but becomes handy when debugging might be required

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah so for that shouldn't you be storing !tokenElement in a separate variable and then use it here ? That's how you can debug the variable value for boolean.

}

function sendTokenToServer(currentToken) {
if (!isTokenSentToServer()) {
console.log("Sending token to server...");
// TODO(developer): Send the current token to your server.
setTokenSentToServer(true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we are assuming here token is already sent to server ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

token can be sent to server from here.. This will be great way to send targeted notifications rather sending to everyone

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification. Can you mention same in the comment ?

} else {
console.log(
"Token already sent to server so won't send it again " +
"unless it changes"
);
}
}
function isTokenSentToServer() {
return window.localStorage.getItem("sentToServer") === "1";
}

function setTokenSentToServer(sent) {
window.localStorage.setItem("sentToServer", sent ? "1" : "0");
}

function showHideDiv(divId, show) {
const div = document.querySelector("#" + divId);
if (!!div) {
aarshad-devani marked this conversation as resolved.
Show resolved Hide resolved
if (show) {
div.style = "display: visible";
} else {
div.style = "display: none";
}
}
}

function requestPermission() {
console.log("Requesting permission...");
Notification.requestPermission().then(permission => {
if (permission === "granted") {
console.log("Notification permission granted.");
resetUI();
} else {
console.log("Unable to get permission to notify.");
}
});
}

function deleteToken() {
// Delete Instance ID token.
messaging
.getToken()
.then(currentToken => {
messaging
.deleteToken(currentToken)
.then(() => {
console.log("Token deleted.");
setTokenSentToServer(false);
// Once token is deleted update UI.
resetUI();
})
.catch(err => {
console.log("Unable to delete token. ", err);
});
})
.catch(err => {
console.log("Error retrieving Instance ID token. ", err);
showToken("Error retrieving Instance ID token. ", err);
});
}

// [TODO] - Write code to show custom UI Notification for website
function appendMessage(payload) {
// const messagesElement = document.querySelector("#messages");
// const dataHeaderELement = document.createElement("h5");
// const dataElement = document.createElement("pre");
// dataElement.style = "overflow-x:hidden;";
// dataHeaderELement.textContent = "Received message:";
// dataElement.textContent = JSON.stringify(payload, null, 2);
// messagesElement.appendChild(dataHeaderELement);
// messagesElement.appendChild(dataElement);
}

function clearMessages() {
const messagesElement = document.querySelector("#messages");
if (!!messagesElement) {
while (messagesElement.hasChildNodes()) {
messagesElement.removeChild(messagesElement.lastChild);
}
}
}

function updateUIForPushEnabled(currentToken) {
showHideDiv(tokenDivId, true);
showHideDiv(permissionDivId, false);
showToken(currentToken);
}

function updateUIForPushPermissionRequired() {
showHideDiv(tokenDivId, false);
showHideDiv(permissionDivId, true);
requestPermission();
}

resetUI();
31 changes: 31 additions & 0 deletions firebase-messaging-sw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
importScripts("https://www.gstatic.com/firebasejs/7.5.0/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/7.5.0/firebase-messaging.js");

const firebaseConfig = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is duplicate code. Can you move it to a separate script and import the messaging variable from there ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed for Firebase-messaging-sw which is basically a background listener all the messages coming in

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant is lines 4-14 in this file and line 3-32 in notification.js is duplicte. Please move these lines to separate script and import the messaging variable in both places.

apiKey: "AIzaSyCZ8gbWs9FLlzw93BOj_OQzlWwd_F1N-IY",
authDomain: "pyconhyd.firebaseapp.com",
databaseURL: "https://pyconhyd.firebaseio.com",
projectId: "pyconhyd",
storageBucket: "pyconhyd.appspot.com",
messagingSenderId: "254977934750",
appId: "1:254977934750:web:9f1ad0357425e5718d828f"
};
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
console.log(
"[firebase-messaging-sw.js] Received background message ",
payload
);
// Customize notification here
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
icon: payload.notification.image || "/favion.ico"
};

return self.registration.showNotification(
notificationTitle,
notificationOptions
);
});