|
@ -261,7 +261,29 @@ |
|
|
|
|
|
|
|
|
<script lang="ts"> |
|
|
<script lang="ts"> |
|
|
import { Vue, Component } from "vue-facing-decorator"; |
|
|
import { Vue, Component } from "vue-facing-decorator"; |
|
|
import axios from "axios"; |
|
|
import axios, { AxiosError } from "axios"; |
|
|
|
|
|
interface ServiceWorkerMessage { |
|
|
|
|
|
type: string; |
|
|
|
|
|
data: string; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
interface ServiceWorkerResponse { |
|
|
|
|
|
// Define the properties and their types |
|
|
|
|
|
success: boolean; |
|
|
|
|
|
message?: string; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Example interface for error |
|
|
|
|
|
interface ErrorResponse { |
|
|
|
|
|
message: string; |
|
|
|
|
|
// Other properties as needed |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
interface VapidResponse { |
|
|
|
|
|
data: { |
|
|
|
|
|
vapidKey: string; |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@Component |
|
|
@Component |
|
|
export default class App extends Vue { |
|
|
export default class App extends Vue { |
|
@ -269,45 +291,87 @@ export default class App extends Vue { |
|
|
mounted() { |
|
|
mounted() { |
|
|
axios |
|
|
axios |
|
|
.get("https://timesafari-pwa.anomalistlabs.com/web-push/vapid") |
|
|
.get("https://timesafari-pwa.anomalistlabs.com/web-push/vapid") |
|
|
.then((response) => { |
|
|
.then((response: VapidResponse) => { |
|
|
this.b64 = response.data.vapidKey; |
|
|
this.b64 = response.data.vapidKey; |
|
|
console.log(this.b64); |
|
|
console.log(this.b64); |
|
|
|
|
|
navigator.serviceWorker.addEventListener("controllerchange", () => { |
|
|
|
|
|
console.log("New service worker is now controlling the page"); |
|
|
|
|
|
}); |
|
|
}) |
|
|
}) |
|
|
.catch((error) => { |
|
|
.catch((error: AxiosError) => { |
|
|
console.error("API error", error); |
|
|
console.error("API error", error); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private sendMessageToServiceWorker( |
|
|
|
|
|
message: ServiceWorkerMessage, |
|
|
|
|
|
): Promise<unknown> { |
|
|
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
|
|
if (navigator.serviceWorker.controller) { |
|
|
|
|
|
const messageChannel = new MessageChannel(); |
|
|
|
|
|
|
|
|
|
|
|
messageChannel.port1.onmessage = (event: MessageEvent) => { |
|
|
|
|
|
if (event.data.error) { |
|
|
|
|
|
reject(event.data.error as ErrorResponse); |
|
|
|
|
|
} else { |
|
|
|
|
|
resolve(event.data as ServiceWorkerResponse); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
navigator.serviceWorker.controller.postMessage(message, [ |
|
|
|
|
|
messageChannel.port2, |
|
|
|
|
|
]); |
|
|
|
|
|
} else { |
|
|
|
|
|
reject("Service worker controller not available"); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private askPermission(): Promise<NotificationPermission> { |
|
|
private askPermission(): Promise<NotificationPermission> { |
|
|
// Check if Notifications are supported |
|
|
if (!("serviceWorker" in navigator && navigator.serviceWorker.controller)) { |
|
|
if (!("Notification" in window)) { |
|
|
return Promise.reject("Service worker not available."); |
|
|
alert("This browser does not support notifications."); |
|
|
|
|
|
return Promise.reject("This browser does not support notifications."); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Check existing permissions |
|
|
const secret = localStorage.getItem("secret"); |
|
|
if (Notification.permission === "granted") { |
|
|
if (!secret) { |
|
|
return Promise.resolve("granted"); |
|
|
return Promise.reject("No secret found."); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Request permission |
|
|
return this.sendSecretToServiceWorker(secret) |
|
|
return new Promise((resolve, reject) => { |
|
|
.then(() => this.checkNotificationSupport()) |
|
|
const permissionResult = Notification.requestPermission((result) => { |
|
|
.then(() => this.requestNotificationPermission()) |
|
|
resolve(result); |
|
|
.catch((error) => Promise.reject(error)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private sendSecretToServiceWorker(secret: string): Promise<void> { |
|
|
|
|
|
const message: ServiceWorkerMessage = { |
|
|
|
|
|
type: "SEND_LOCAL_DATA", |
|
|
|
|
|
data: secret, |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
return this.sendMessageToServiceWorker(message).then((response) => { |
|
|
|
|
|
console.log("Response from service worker:", response); |
|
|
}); |
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (permissionResult) { |
|
|
private checkNotificationSupport(): Promise<void> { |
|
|
permissionResult.then(resolve, reject); |
|
|
if (!("Notification" in window)) { |
|
|
|
|
|
alert("This browser does not support notifications."); |
|
|
|
|
|
return Promise.reject("This browser does not support notifications."); |
|
|
|
|
|
} |
|
|
|
|
|
if (Notification.permission === "granted") { |
|
|
|
|
|
return Promise.resolve(); |
|
|
|
|
|
} |
|
|
|
|
|
return Promise.resolve(); |
|
|
} |
|
|
} |
|
|
}).then((permissionResult) => { |
|
|
|
|
|
console.log("Permission result:", permissionResult); |
|
|
|
|
|
|
|
|
|
|
|
if (permissionResult !== "granted") { |
|
|
private requestNotificationPermission(): Promise<NotificationPermission> { |
|
|
|
|
|
return Notification.requestPermission().then((permission) => { |
|
|
|
|
|
if (permission !== "granted") { |
|
|
alert("We need notification permission to provide certain features."); |
|
|
alert("We need notification permission to provide certain features."); |
|
|
return Promise.reject("We weren't granted permission."); |
|
|
throw new Error("We weren't granted permission."); |
|
|
} |
|
|
} |
|
|
|
|
|
return permission; |
|
|
return permissionResult; |
|
|
|
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -366,16 +430,25 @@ export default class App extends Vue { |
|
|
return outputArray; |
|
|
return outputArray; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// The subscribeToPush method |
|
|
|
|
|
private subscribeToPush(): Promise<void> { |
|
|
private subscribeToPush(): Promise<void> { |
|
|
return new Promise<void>((resolve, reject) => { |
|
|
return new Promise<void>((resolve, reject) => { |
|
|
if ("serviceWorker" in navigator && "PushManager" in window) { |
|
|
if (!("serviceWorker" in navigator && "PushManager" in window)) { |
|
|
|
|
|
const errorMsg = "Push messaging is not supported"; |
|
|
|
|
|
console.warn(errorMsg); |
|
|
|
|
|
return reject(new Error(errorMsg)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (Notification.permission !== "granted") { |
|
|
|
|
|
const errorMsg = "Notification permission not granted"; |
|
|
|
|
|
console.warn(errorMsg); |
|
|
|
|
|
return reject(new Error(errorMsg)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
const applicationServerKey = this.urlBase64ToUint8Array(this.b64); |
|
|
const applicationServerKey = this.urlBase64ToUint8Array(this.b64); |
|
|
const options: PushSubscriptionOptions = { |
|
|
const options: PushSubscriptionOptions = { |
|
|
userVisibleOnly: true, |
|
|
userVisibleOnly: true, |
|
|
applicationServerKey: applicationServerKey, |
|
|
applicationServerKey: applicationServerKey, |
|
|
}; |
|
|
}; |
|
|
console.log(options); |
|
|
|
|
|
|
|
|
|
|
|
navigator.serviceWorker.ready |
|
|
navigator.serviceWorker.ready |
|
|
.then((registration) => { |
|
|
.then((registration) => { |
|
@ -386,14 +459,20 @@ export default class App extends Vue { |
|
|
resolve(); |
|
|
resolve(); |
|
|
}) |
|
|
}) |
|
|
.catch((error) => { |
|
|
.catch((error) => { |
|
|
console.error("Push subscription failed:", error, options); |
|
|
console.error( |
|
|
|
|
|
"Subscription or server communication failed:", |
|
|
|
|
|
error, |
|
|
|
|
|
options, |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Inform the user about the issue |
|
|
|
|
|
alert( |
|
|
|
|
|
"We encountered an issue setting up push notifications. " + |
|
|
|
|
|
"If you wish to revoke notification permissions, please do so in your browser settings.", |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
reject(error); |
|
|
reject(error); |
|
|
}); |
|
|
}); |
|
|
} else { |
|
|
|
|
|
const errorMsg = "Push messaging is not supported"; |
|
|
|
|
|
console.warn(errorMsg); |
|
|
|
|
|
reject(new Error(errorMsg)); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|