forked from trent_larson/crowd-funder-for-time-pwa
Compare commits
8 Commits
searching
...
service-wo
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b9ae96006 | |||
|
|
4dd5664462 | ||
|
|
7d6a45061d | ||
|
|
3b32c2b156 | ||
|
|
1ee6203f4c | ||
|
|
d93299c352 | ||
|
|
9aea7a576d | ||
| 714bb169fa |
@@ -72,13 +72,13 @@
|
||||
"@vue/cli-service": "~5.0.8",
|
||||
"@vue/eslint-config-typescript": "^11.0.3",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"eslint": "^8.48.0",
|
||||
"eslint": "^8.53.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"eslint-plugin-vue": "^9.17.0",
|
||||
"leaflet": "^1.9.4",
|
||||
"postcss": "^8.4.29",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier": "^3.1.0",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "~5.2.2"
|
||||
}
|
||||
|
||||
171
src/App.vue
171
src/App.vue
@@ -261,7 +261,29 @@
|
||||
|
||||
<script lang="ts">
|
||||
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
|
||||
export default class App extends Vue {
|
||||
@@ -269,45 +291,87 @@ export default class App extends Vue {
|
||||
mounted() {
|
||||
axios
|
||||
.get("https://timesafari-pwa.anomalistlabs.com/web-push/vapid")
|
||||
.then((response) => {
|
||||
.then((response: VapidResponse) => {
|
||||
this.b64 = response.data.vapidKey;
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
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> {
|
||||
// Check if Notifications are supported
|
||||
if (!("serviceWorker" in navigator && navigator.serviceWorker.controller)) {
|
||||
return Promise.reject("Service worker not available.");
|
||||
}
|
||||
|
||||
const secret = localStorage.getItem("secret");
|
||||
if (!secret) {
|
||||
return Promise.reject("No secret found.");
|
||||
}
|
||||
|
||||
return this.sendSecretToServiceWorker(secret)
|
||||
.then(() => this.checkNotificationSupport())
|
||||
.then(() => this.requestNotificationPermission())
|
||||
.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);
|
||||
});
|
||||
}
|
||||
|
||||
private checkNotificationSupport(): Promise<void> {
|
||||
if (!("Notification" in window)) {
|
||||
alert("This browser does not support notifications.");
|
||||
return Promise.reject("This browser does not support notifications.");
|
||||
}
|
||||
|
||||
// Check existing permissions
|
||||
if (Notification.permission === "granted") {
|
||||
return Promise.resolve("granted");
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// Request permission
|
||||
return new Promise((resolve, reject) => {
|
||||
const permissionResult = Notification.requestPermission((result) => {
|
||||
resolve(result);
|
||||
});
|
||||
|
||||
if (permissionResult) {
|
||||
permissionResult.then(resolve, reject);
|
||||
}
|
||||
}).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.");
|
||||
return Promise.reject("We weren't granted permission.");
|
||||
throw new Error("We weren't granted permission.");
|
||||
}
|
||||
|
||||
return permissionResult;
|
||||
return permission;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -366,34 +430,49 @@ export default class App extends Vue {
|
||||
return outputArray;
|
||||
}
|
||||
|
||||
// The subscribeToPush method
|
||||
private subscribeToPush(): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if ("serviceWorker" in navigator && "PushManager" in window) {
|
||||
const applicationServerKey = this.urlBase64ToUint8Array(this.b64);
|
||||
const options: PushSubscriptionOptions = {
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: applicationServerKey,
|
||||
};
|
||||
console.log(options);
|
||||
|
||||
navigator.serviceWorker.ready
|
||||
.then((registration) => {
|
||||
return registration.pushManager.subscribe(options);
|
||||
})
|
||||
.then((subscription) => {
|
||||
console.log("Push subscription successful:", subscription);
|
||||
resolve();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Push subscription failed:", error, options);
|
||||
reject(error);
|
||||
});
|
||||
} else {
|
||||
if (!("serviceWorker" in navigator && "PushManager" in window)) {
|
||||
const errorMsg = "Push messaging is not supported";
|
||||
console.warn(errorMsg);
|
||||
reject(new Error(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 options: PushSubscriptionOptions = {
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: applicationServerKey,
|
||||
};
|
||||
|
||||
navigator.serviceWorker.ready
|
||||
.then((registration) => {
|
||||
return registration.pushManager.subscribe(options);
|
||||
})
|
||||
.then((subscription) => {
|
||||
console.log("Push subscription successful:", subscription);
|
||||
resolve();
|
||||
})
|
||||
.catch((error) => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { register } from "register-service-worker";
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
register(`${process.env.BASE_URL}service-worker.js`, {
|
||||
register("/additional-scripts.js", {
|
||||
ready() {
|
||||
console.log(
|
||||
"App is being served from cache by a service worker.\n" +
|
||||
|
||||
@@ -1,33 +1,65 @@
|
||||
const notifications = require("./safari-notifications.js");
|
||||
/* eslint-env serviceworker */
|
||||
/* global workbox */
|
||||
importScripts(
|
||||
"https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-sw.js",
|
||||
);
|
||||
|
||||
self.addEventListener("install", (event) => {
|
||||
console.error(event);
|
||||
importScripts(
|
||||
"safari-notifications.js",
|
||||
"nacl.js",
|
||||
"noble-curves.js",
|
||||
"noble-hashes.js",
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener("push", function (event) {
|
||||
let payload;
|
||||
if (event.data) {
|
||||
payload = JSON.parse(event.data.text());
|
||||
event.waitUntil(
|
||||
(async () => {
|
||||
try {
|
||||
let payload;
|
||||
if (event.data) {
|
||||
payload = JSON.parse(event.data.text());
|
||||
}
|
||||
const message = await self.getNotificationCount();
|
||||
console.error(message);
|
||||
const title = payload ? payload.title : "Custom Title";
|
||||
const options = {
|
||||
body: message,
|
||||
icon: payload ? payload.icon : "icon.png",
|
||||
badge: payload ? payload.badge : "badge.png",
|
||||
};
|
||||
await self.registration.showNotification(title, options);
|
||||
} catch (error) {
|
||||
console.error("Error in processing the push event:", error);
|
||||
}
|
||||
})(),
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener("message", (event) => {
|
||||
if (event.data && event.data.type === "SEND_LOCAL_DATA") {
|
||||
self.secret = event.data.data;
|
||||
event.ports[0].postMessage({ success: true });
|
||||
}
|
||||
|
||||
const title = payload ? payload.title : "Custom Title";
|
||||
const options = {
|
||||
body: payload ? payload.body : "Custom body text",
|
||||
icon: payload ? payload.icon : "icon.png",
|
||||
badge: payload ? payload.badge : "badge.png",
|
||||
};
|
||||
|
||||
event.waitUntil(self.registration.showNotification(title, options));
|
||||
});
|
||||
|
||||
|
||||
self.addEventListener("message", function (event) {
|
||||
const data = event.data;
|
||||
|
||||
const result = notifications.getNotificationCount()
|
||||
|
||||
switch (data.command) {
|
||||
case "account":
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log("Unknown command:", data.command);
|
||||
}
|
||||
self.addEventListener("activate", (event) => {
|
||||
event.waitUntil(clients.claim());
|
||||
console.log("Service worker activated", event);
|
||||
});
|
||||
|
||||
self.addEventListener("fetch", (event) => {
|
||||
console.log(event.request);
|
||||
});
|
||||
|
||||
self.addEventListener("error", (event) => {
|
||||
console.error("Error in Service Worker:", event.message);
|
||||
console.error("File:", event.filename);
|
||||
console.error("Line:", event.lineno);
|
||||
console.error("Column:", event.colno);
|
||||
console.error("Error Object:", event.error);
|
||||
});
|
||||
|
||||
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST);
|
||||
|
||||
1051
sw_scripts/nacl.js
Normal file
1051
sw_scripts/nacl.js
Normal file
File diff suppressed because it is too large
Load Diff
5248
sw_scripts/noble-curves.js
Normal file
5248
sw_scripts/noble-curves.js
Normal file
File diff suppressed because it is too large
Load Diff
3068
sw_scripts/noble-hashes.js
Normal file
3068
sw_scripts/noble-hashes.js
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -11,8 +11,9 @@ module.exports = defineConfig({
|
||||
iconPaths: {
|
||||
faviconSVG: "img/icons/safari-pinned-tab.svg",
|
||||
},
|
||||
workboxPluginMode: "InjectManifest",
|
||||
workboxOptions: {
|
||||
importScripts: ["additional-scripts.js"],
|
||||
swSrc: "./sw_scripts/additional-scripts.js",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user