mirror of
https://github.com/Retrospring/retrospring.git
synced 2024-11-20 14:19:53 +01:00
Add JS for subscribing to and receiving push notifications
This commit is contained in:
parent
8b98c278da
commit
2da4767623
9 changed files with 125 additions and 0 deletions
|
@ -15,6 +15,7 @@ import initModeration from 'retrospring/features/moderation';
|
||||||
import initMemes from 'retrospring/features/memes';
|
import initMemes from 'retrospring/features/memes';
|
||||||
import initLocales from 'retrospring/features/locales';
|
import initLocales from 'retrospring/features/locales';
|
||||||
import initFront from 'retrospring/features/front';
|
import initFront from 'retrospring/features/front';
|
||||||
|
import initWebpush from 'retrospring/features/webpush';
|
||||||
|
|
||||||
start();
|
start();
|
||||||
document.addEventListener('DOMContentLoaded', initAnswerbox);
|
document.addEventListener('DOMContentLoaded', initAnswerbox);
|
||||||
|
@ -28,6 +29,7 @@ document.addEventListener('DOMContentLoaded', initModeration);
|
||||||
document.addEventListener('DOMContentLoaded', initMemes);
|
document.addEventListener('DOMContentLoaded', initMemes);
|
||||||
document.addEventListener('turbo:load', initLocales);
|
document.addEventListener('turbo:load', initLocales);
|
||||||
document.addEventListener('turbo:load', initFront);
|
document.addEventListener('turbo:load', initFront);
|
||||||
|
document.addEventListener('DOMContentLoaded', initWebpush);
|
||||||
|
|
||||||
window['Stimulus'] = Application.start();
|
window['Stimulus'] = Application.start();
|
||||||
const context = require.context('../retrospring/controllers', true, /\.ts$/);
|
const context = require.context('../retrospring/controllers', true, /\.ts$/);
|
||||||
|
|
7
app/javascript/retrospring/features/webpush/dismiss.ts
Normal file
7
app/javascript/retrospring/features/webpush/dismiss.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export function dismissHandler (event: Event): void {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const sender: HTMLButtonElement = event.target as HTMLButtonElement;
|
||||||
|
sender.closest<HTMLDivElement>('.push-settings').classList.add('d-none');
|
||||||
|
localStorage.setItem('dismiss-push-settings-prompt', 'true');
|
||||||
|
}
|
59
app/javascript/retrospring/features/webpush/enable.ts
Normal file
59
app/javascript/retrospring/features/webpush/enable.ts
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import { get, post } from '@rails/request.js';
|
||||||
|
import I18n from "retrospring/i18n";
|
||||||
|
import { showNotification } from "utilities/notifications";
|
||||||
|
|
||||||
|
export function enableHandler (event: Event): void {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
try {
|
||||||
|
installServiceWorker()
|
||||||
|
.then(subscribe)
|
||||||
|
.then(async subscription => {
|
||||||
|
return Notification.requestPermission().then(permission => {
|
||||||
|
if (permission != "granted") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
post('/ajax/web_push', {
|
||||||
|
body: {
|
||||||
|
subscription
|
||||||
|
},
|
||||||
|
contentType: 'application/json'
|
||||||
|
}).then(async response => {
|
||||||
|
const data = await response.json;
|
||||||
|
|
||||||
|
if (data.success) {
|
||||||
|
new Notification(I18n.translate("frontend.push_notifications.subscribe.success.title"), {
|
||||||
|
body: I18n.translate("frontend.push_notifications.subscribe.success.body")
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
new Notification(I18n.translate("frontend.push_notifications.fail.title"), {
|
||||||
|
body: I18n.translate("frontend.push_notifications.fail.body")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to set up push notifications", error);
|
||||||
|
showNotification(I18n.translate("frontend.push_notifications.setup_fail"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function installServiceWorker(): Promise<ServiceWorkerRegistration> {
|
||||||
|
return navigator.serviceWorker.register("/service_worker.js", { scope: "/" });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getServerKey(): Promise<Buffer> {
|
||||||
|
const response = await get("/ajax/webpush/key");
|
||||||
|
const data = await response.json;
|
||||||
|
return Buffer.from(data.key, 'base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function subscribe(registration: ServiceWorkerRegistration): Promise<PushSubscription> {
|
||||||
|
const key = await getServerKey();
|
||||||
|
return await registration.pushManager.subscribe({
|
||||||
|
userVisibleOnly: true,
|
||||||
|
applicationServerKey: key
|
||||||
|
});
|
||||||
|
}
|
28
app/javascript/retrospring/features/webpush/index.ts
Normal file
28
app/javascript/retrospring/features/webpush/index.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import registerEvents from 'retrospring/utilities/registerEvents';
|
||||||
|
import { enableHandler } from './enable';
|
||||||
|
import { dismissHandler } from "./dismiss";
|
||||||
|
|
||||||
|
export default (): void => {
|
||||||
|
const swCapable = 'serviceWorker' in navigator;
|
||||||
|
if (swCapable) {
|
||||||
|
document.body.classList.add('cap-service-worker');
|
||||||
|
}
|
||||||
|
|
||||||
|
const notificationCapable = 'Notification' in window;
|
||||||
|
if (notificationCapable) {
|
||||||
|
document.body.classList.add('cap-notification');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swCapable && notificationCapable) {
|
||||||
|
navigator.serviceWorker.getRegistration().then(registration => {
|
||||||
|
if (!registration && localStorage.getItem('dismiss-push-settings-prompt') == null) {
|
||||||
|
document.querySelector('.push-settings').classList.remove('d-none');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
registerEvents([
|
||||||
|
{type: 'click', target: '[data-action="push-enable"]', handler: enableHandler, global: true},
|
||||||
|
{type: 'click', target: '[data-action="push-dismiss"]', handler: dismissHandler, global: true},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
5
app/views/inbox/_push_settings.haml
Normal file
5
app/views/inbox/_push_settings.haml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.card.push-settings.d-none
|
||||||
|
.card-body
|
||||||
|
= t(".description")
|
||||||
|
%button.btn.btn-primary{ data: { action: "push-enable" } }= t("voc.y")
|
||||||
|
%button.btn{ data: { action: "push-dismiss" } }= t("voc.n")
|
|
@ -2,6 +2,7 @@
|
||||||
.row
|
.row
|
||||||
.col-sm-10.col-md-10.col-lg-9.mx-auto
|
.col-sm-10.col-md-10.col-lg-9.mx-auto
|
||||||
= render 'inbox/actions', delete_id: @delete_id, disabled: @disabled, inbox_count: @inbox_count
|
= render 'inbox/actions', delete_id: @delete_id, disabled: @disabled, inbox_count: @inbox_count
|
||||||
|
= render 'inbox/push_settings'
|
||||||
= render 'layouts/messages'
|
= render 'layouts/messages'
|
||||||
= yield
|
= yield
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,15 @@ en:
|
||||||
confirm:
|
confirm:
|
||||||
title: "Are you sure?"
|
title: "Are you sure?"
|
||||||
text: "This will mute this user for everyone."
|
text: "This will mute this user for everyone."
|
||||||
|
push_notifications:
|
||||||
|
subscribe:
|
||||||
|
success:
|
||||||
|
title: Push notifications enabled!
|
||||||
|
body: You will now receive push notifications for new questions on this device.
|
||||||
|
fail:
|
||||||
|
title: Failed to subscribe to push notifications
|
||||||
|
body: Please try again later
|
||||||
|
setup_fail: Failed to set up push notifications. Please try again later.
|
||||||
report:
|
report:
|
||||||
confirm:
|
confirm:
|
||||||
title: "Are you sure you want to report this %{type}?"
|
title: "Are you sure you want to report this %{type}?"
|
||||||
|
|
|
@ -231,6 +231,8 @@ en:
|
||||||
share:
|
share:
|
||||||
heading: "Share"
|
heading: "Share"
|
||||||
button: "Share on %{service}"
|
button: "Share on %{service}"
|
||||||
|
push_settings:
|
||||||
|
description: "Want to receive push notifications for new questions on your device?"
|
||||||
layouts:
|
layouts:
|
||||||
feedback:
|
feedback:
|
||||||
heading: "Feedback"
|
heading: "Feedback"
|
||||||
|
|
12
public/service_worker.js
Normal file
12
public/service_worker.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
self.addEventListener('push', function (event) {
|
||||||
|
if (event.data) {
|
||||||
|
const notification = event.data.json();
|
||||||
|
console.log(event.data);
|
||||||
|
|
||||||
|
event.waitUntil(self.registration.showNotification(notification.title, {
|
||||||
|
body: notification.body
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
console.error("Push event received, but it didn't contain any data.", event);
|
||||||
|
}
|
||||||
|
});
|
Loading…
Reference in a new issue