From 2ff1f278c23b9cd832cd8a6606ab22e5679d2792 Mon Sep 17 00:00:00 2001 From: Vishal Date: Mon, 26 Aug 2024 12:43:12 +0530 Subject: [PATCH 01/13] test worker on https Signed-off-by: Vishal --- public/notification-service.js | 4 ++ src/pages/Notification/index.tsx | 19 ++++++ src/pages/Notification/notification-engine.ts | 66 +++++++++++++++++++ src/router/routeMap.tsx | 2 +- tsconfig.json | 3 +- 5 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 public/notification-service.js create mode 100644 src/pages/Notification/notification-engine.ts diff --git a/public/notification-service.js b/public/notification-service.js new file mode 100644 index 0000000..b89261a --- /dev/null +++ b/public/notification-service.js @@ -0,0 +1,4 @@ +self.addEventListener("activate", async () => { + // This will be called only once when the service worker is activated. + console.log("Hello from service worker"); +}); diff --git a/src/pages/Notification/index.tsx b/src/pages/Notification/index.tsx index 2f6f1c7..c2dbb03 100644 --- a/src/pages/Notification/index.tsx +++ b/src/pages/Notification/index.tsx @@ -3,6 +3,7 @@ import { ErrorContext } from "@/contexts/error"; import API from "@/services/API"; import { INotification } from "@/types/notification"; import React, { useEffect, useState } from "react"; +import { Notification, BgService } from "./notification-engine"; interface NotificationCardProps { notif: INotification; @@ -79,6 +80,24 @@ export default function NotificationPage() { return (

Latest Updates

+ + + {notifications.map((notif) => { return ; })} diff --git a/src/pages/Notification/notification-engine.ts b/src/pages/Notification/notification-engine.ts new file mode 100644 index 0000000..ed164cc --- /dev/null +++ b/src/pages/Notification/notification-engine.ts @@ -0,0 +1,66 @@ +export class Notification { + static notify = window.Notification; + + public static isPermissionGranted() { + if (!Notification.isSupported()) { + throw new Error("Notification API is not supported"); + } + return Notification.notify.permission === "granted"; + } + + public static async requestPermission() { + if (!Notification.isSupported()) { + throw new Error("Notification API is not supported"); + } + const permission = await Notification.notify.requestPermission(); + console.log("Notification API permission", permission); + return permission; + } + + public static constructNotification( + title: string, + options: NotificationOptions, + ) { + return new Notification.notify(title, options); + } + + public static isSupported() { + return Notification.notify !== undefined; + } + + public static async displayNotification( + title: string, + options: NotificationOptions, + ) { + const permission = await Notification.requestPermission(); + if (permission === "granted") { + Notification.constructNotification(title, options); + } else { + console.error("Permission denied"); + } + } +} + +export class BgService { + static bg = window.navigator; + + public static isSupported() { + return BgService.bg !== undefined; + } + + public static async registerServiceWorker(swPath: string) { + const registration = await BgService.bg.serviceWorker.register(swPath); + console.log("Service worker registered", registration); + return registration; + } + + public static async unregisterServiceWorker() { + const registrations = await BgService.bg.serviceWorker.getRegistrations(); + registrations.forEach((registration) => registration.unregister()); + } + + public static async getRegistration() { + const registration = await BgService.bg.serviceWorker.getRegistration(); + return registration; + } +} diff --git a/src/router/routeMap.tsx b/src/router/routeMap.tsx index 39adf68..4a36f40 100644 --- a/src/router/routeMap.tsx +++ b/src/router/routeMap.tsx @@ -242,7 +242,7 @@ const routeMap: CustomRouteElement[] = [ path: "notification/", element: , icon: , - permission: [], + permission: [Permission.AccessLogs], label: "Notifications", }, ]; diff --git a/tsconfig.json b/tsconfig.json index f8e9eef..e03b018 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -31,7 +31,8 @@ } }, "include": [ - "src" + "src", + "public/notification-service.js" ], "references": [ { From 2fd4099216b6119a90c451e003cf396c4f220777 Mon Sep 17 00:00:00 2001 From: Vishal Date: Mon, 26 Aug 2024 12:44:20 +0530 Subject: [PATCH 02/13] add dev auto deploy Signed-off-by: Vishal --- .github/workflows/dev.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/dev.yml diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml new file mode 100644 index 0000000..a3e92c3 --- /dev/null +++ b/.github/workflows/dev.yml @@ -0,0 +1,36 @@ +# This is a basic workflow to help you get started with Actions + +name: Deploy on push + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the "main" branch + push: + branches: [ "dev" ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: self-hosted + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v4 + + - name: Get to work dir + run: cd $GITHUB_WORKSPACE + + - name: Install dependencies + run: npm i + + - name: Run build task + run: npm run build + + - name: Deploy to web + run: rsync -avz --delete dist/ ~/nix_frontend_dev From fda17cdb8c86c276535010d06e7bd1bfdbe7db63 Mon Sep 17 00:00:00 2001 From: Vishal Date: Mon, 26 Aug 2024 14:18:41 +0530 Subject: [PATCH 03/13] update test Signed-off-by: Vishal --- src/pages/Notification/index.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/Notification/index.tsx b/src/pages/Notification/index.tsx index c2dbb03..267df74 100644 --- a/src/pages/Notification/index.tsx +++ b/src/pages/Notification/index.tsx @@ -86,14 +86,16 @@ export default function NotificationPage() { + {notifications.map((notif) => { return ; From 3f46d15e2e9a690fb79b0324da7d9beff11957a6 Mon Sep 17 00:00:00 2001 From: Vishal Date: Mon, 26 Aug 2024 16:11:57 +0530 Subject: [PATCH 06/13] update notif code Signed-off-by: Vishal --- public/notification-service.js | 38 ++++++++++++++++++- src/pages/Notification/notification-engine.ts | 1 + 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/public/notification-service.js b/public/notification-service.js index b89261a..acda637 100644 --- a/public/notification-service.js +++ b/public/notification-service.js @@ -1,4 +1,38 @@ -self.addEventListener("activate", async () => { - // This will be called only once when the service worker is activated. +/// + +/** @type {ServiceWorkerGlobalScope} */ +const service_worker = self; + +function urlB64ToUint8Array(base64String) { + const padding = "=".repeat((4 - (base64String.length % 4)) % 4); + const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/"); + + const rawData = window.atob(base64); + const outputArray = new Uint8Array(rawData.length); + const outputData = outputArray.map((output, index) => + rawData.charCodeAt(index), + ); + + return outputData; +} + +service_worker.addEventListener("activate", async () => { console.log("Hello from service worker"); + try { + /** @type {PushSubscriptionOptionsInit} */ + const options = { + applicationServerKey: + "BCOsRaxpJeR0KyIPIg1rHx3pUtWVsGDGOxH65dDkqyU5ycF-CjPJxuqiXF4M0LpUMG_rk_YxSZX34uHbrV5umJQ", + userVisibleOnly: true, + }; + console.log("Hello from service worker second time"); + + const subscription = + await service_worker.registration.pushManager.subscribe(options); + + console.log("Subscription", subscription); + console.log(JSON.stringify(subscription)); + } catch (err) { + console.log("Error", err); + } }); diff --git a/src/pages/Notification/notification-engine.ts b/src/pages/Notification/notification-engine.ts index ed164cc..8f53a32 100644 --- a/src/pages/Notification/notification-engine.ts +++ b/src/pages/Notification/notification-engine.ts @@ -57,6 +57,7 @@ export class BgService { public static async unregisterServiceWorker() { const registrations = await BgService.bg.serviceWorker.getRegistrations(); registrations.forEach((registration) => registration.unregister()); + return registrations; } public static async getRegistration() { From 06a66d201a6591a6d8d1e0fd2e6714efa8f9099e Mon Sep 17 00:00:00 2001 From: Vishal Date: Mon, 26 Aug 2024 17:07:25 +0530 Subject: [PATCH 07/13] add save subs script Signed-off-by: Vishal --- public/notification-service.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/public/notification-service.js b/public/notification-service.js index acda637..a420201 100644 --- a/public/notification-service.js +++ b/public/notification-service.js @@ -19,7 +19,7 @@ function urlB64ToUint8Array(base64String) { service_worker.addEventListener("activate", async () => { console.log("Hello from service worker"); try { - /** @type {PushSubscriptionOptionsInit} */ + /** @type {PushSubscriptionOptions} */ const options = { applicationServerKey: "BCOsRaxpJeR0KyIPIg1rHx3pUtWVsGDGOxH65dDkqyU5ycF-CjPJxuqiXF4M0LpUMG_rk_YxSZX34uHbrV5umJQ", @@ -30,8 +30,21 @@ service_worker.addEventListener("activate", async () => { const subscription = await service_worker.registration.pushManager.subscribe(options); - console.log("Subscription", subscription); - console.log(JSON.stringify(subscription)); + let subscribe_json = subscription.toJSON(); + console.log("Subscription", subscribe_json); + + const body = JSON.stringify(subscribe_json); + + await fetch("https://team-dev.dtutimes.com/api/v1/notification/subscribe", { + method: "POST", + body, + headers: { + "Content-Type": "application/json", + }, + }) + .then((res) => res.text()) + .then(console.log) + .catch(console.error); } catch (err) { console.log("Error", err); } From c74da2dec93b9562c7286f9d40d8590bf1e1533e Mon Sep 17 00:00:00 2001 From: Vishal Date: Mon, 26 Aug 2024 17:14:53 +0530 Subject: [PATCH 08/13] added dummy push event Signed-off-by: Vishal --- public/notification-service.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/public/notification-service.js b/public/notification-service.js index a420201..6d8a725 100644 --- a/public/notification-service.js +++ b/public/notification-service.js @@ -49,3 +49,24 @@ service_worker.addEventListener("activate", async () => { console.log("Error", err); } }); + +service_worker.addEventListener("push", function (event) { + if (event.data) { + console.log(event.data.text()); + pushNotification("Hi", event.data.text(), service_worker.registration); + } else { + console.log("No data!"); + } +}); + +/** + * @param title {string} + * @param body {string} + * @param swRegistration {ServiceWorkerRegistration} + */ +const pushNotification = (title, body, swRegistration) => { + const options = { + body, + }; + swRegistration.showNotification(title, options); +}; From dcfb2d14e41a20701c1d3272b1c18303e42891e0 Mon Sep 17 00:00:00 2001 From: Vishal Date: Mon, 26 Aug 2024 18:05:32 +0530 Subject: [PATCH 09/13] undo temp change to hide console logs Signed-off-by: Vishal --- vite.config.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vite.config.ts b/vite.config.ts index 9235e3a..d2146d5 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -12,11 +12,11 @@ export default defineConfig({ }, }, esbuild: { - // drop: - // process.env.NODE_ENV == "production" - // ? ["console", "debugger"] - // : undefined, - // pure: ["console.error"], + drop: + process.env.NODE_ENV == "production" + ? ["console", "debugger"] + : undefined, + pure: ["console.error"], }, build: { rollupOptions: { From 324ca154310c48b16879b54e1da4802defe94524 Mon Sep 17 00:00:00 2001 From: Vishal Date: Mon, 26 Aug 2024 18:20:48 +0530 Subject: [PATCH 10/13] update notif engine Signed-off-by: Vishal --- src/pages/Notification/index.tsx | 48 +++++++--------- src/pages/Notification/notification-engine.ts | 56 +++++++++---------- 2 files changed, 44 insertions(+), 60 deletions(-) diff --git a/src/pages/Notification/index.tsx b/src/pages/Notification/index.tsx index b373e32..cc3f3c5 100644 --- a/src/pages/Notification/index.tsx +++ b/src/pages/Notification/index.tsx @@ -3,7 +3,11 @@ import { ErrorContext } from "@/contexts/error"; import API from "@/services/API"; import { INotification } from "@/types/notification"; import React, { useEffect, useState } from "react"; -import { Notification, BgService } from "./notification-engine"; +import { + setup_notification, + disable_notification, + setup_present, +} from "./notification-engine"; interface NotificationCardProps { notif: INotification; @@ -57,8 +61,11 @@ export default function NotificationPage() { const { setError } = React.useContext(ErrorContext); const [notifications, setNotifs] = useState(null); + const [status, setStatus] = useState(false); useEffect(() => { + setup_present().then(setStatus); + const notifications = "/notification"; API.get(notifications) .then((response) => { @@ -80,34 +87,17 @@ export default function NotificationPage() { return (

Latest Updates

- - - - +
+ {status ? ( + + ) : ( + + )} +
{notifications.map((notif) => { return ; })} diff --git a/src/pages/Notification/notification-engine.ts b/src/pages/Notification/notification-engine.ts index 8f53a32..ef73f1a 100644 --- a/src/pages/Notification/notification-engine.ts +++ b/src/pages/Notification/notification-engine.ts @@ -1,13 +1,6 @@ -export class Notification { +class Notification { static notify = window.Notification; - public static isPermissionGranted() { - if (!Notification.isSupported()) { - throw new Error("Notification API is not supported"); - } - return Notification.notify.permission === "granted"; - } - public static async requestPermission() { if (!Notification.isSupported()) { throw new Error("Notification API is not supported"); @@ -17,31 +10,12 @@ export class Notification { return permission; } - public static constructNotification( - title: string, - options: NotificationOptions, - ) { - return new Notification.notify(title, options); - } - public static isSupported() { return Notification.notify !== undefined; } - - public static async displayNotification( - title: string, - options: NotificationOptions, - ) { - const permission = await Notification.requestPermission(); - if (permission === "granted") { - Notification.constructNotification(title, options); - } else { - console.error("Permission denied"); - } - } } -export class BgService { +class BgService { static bg = window.navigator; public static isSupported() { @@ -55,13 +29,33 @@ export class BgService { } public static async unregisterServiceWorker() { - const registrations = await BgService.bg.serviceWorker.getRegistrations(); + const registrations = await BgService.getRegistrations(); registrations.forEach((registration) => registration.unregister()); return registrations; } - public static async getRegistration() { - const registration = await BgService.bg.serviceWorker.getRegistration(); + public static async getRegistrations() { + const registration = await BgService.bg.serviceWorker.getRegistrations(); + console.log("Service worker registered", registration); return registration; } } + +export async function setup_notification() { + Notification.requestPermission(); + + const worker = await BgService.registerServiceWorker( + "https://team-dev.dtutimes.com/notification-service.js", + ); + + console.log("Service worker registered", worker); +} + +export async function disable_notification() { + await BgService.unregisterServiceWorker(); +} + +export async function setup_present() { + const services = await BgService.getRegistrations(); + return services.length > 0; +} From e1e2af42cd98236c3f1ce52516fe302a49b3efbb Mon Sep 17 00:00:00 2001 From: Vishal Date: Mon, 26 Aug 2024 19:19:59 +0530 Subject: [PATCH 11/13] notification system update Signed-off-by: Vishal --- public/notification-service.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/public/notification-service.js b/public/notification-service.js index 6d8a725..69b7d16 100644 --- a/public/notification-service.js +++ b/public/notification-service.js @@ -51,9 +51,16 @@ service_worker.addEventListener("activate", async () => { }); service_worker.addEventListener("push", function (event) { - if (event.data) { - console.log(event.data.text()); - pushNotification("Hi", event.data.text(), service_worker.registration); + const data = event.data.json(); + if (data) { + pushNotification( + data.title, + { + icon: "https://dtutimes.com/favicon.ico", + body: data.body, + }, + service_worker.registration, + ); } else { console.log("No data!"); } @@ -61,12 +68,9 @@ service_worker.addEventListener("push", function (event) { /** * @param title {string} - * @param body {string} + * @param options {NotificationOptions} * @param swRegistration {ServiceWorkerRegistration} */ -const pushNotification = (title, body, swRegistration) => { - const options = { - body, - }; +const pushNotification = (title, options, swRegistration) => { swRegistration.showNotification(title, options); }; From 9df089703972cb8c0c107e07f8bd2deabf9eec6b Mon Sep 17 00:00:00 2001 From: Vishal Date: Mon, 26 Aug 2024 20:12:13 +0530 Subject: [PATCH 12/13] fix notif service Signed-off-by: Vishal --- public/notification-service.js | 24 ++++++++++++++++++- src/pages/Notification/index.tsx | 20 ++++++++++++---- src/pages/Notification/notification-engine.ts | 2 +- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/public/notification-service.js b/public/notification-service.js index 69b7d16..dd25629 100644 --- a/public/notification-service.js +++ b/public/notification-service.js @@ -35,7 +35,7 @@ service_worker.addEventListener("activate", async () => { const body = JSON.stringify(subscribe_json); - await fetch("https://team-dev.dtutimes.com/api/v1/notification/subscribe", { + await fetch("https://team.dtutimes.com/api/v1/notification/subscribe", { method: "POST", body, headers: { @@ -72,5 +72,27 @@ service_worker.addEventListener("push", function (event) { * @param swRegistration {ServiceWorkerRegistration} */ const pushNotification = (title, options, swRegistration) => { + console.log("Push Notification", title, options); swRegistration.showNotification(title, options); }; + +service_worker.addEventListener("notificationclick", (event) => { + event.notification.close(); + event.waitUntil( + service_worker.clients + .matchAll({ + type: "window", + }) + .then((clientList) => { + for (const client of clientList) { + if ( + client.url === "https://team.dtutimes.com/notification" && + "focus" in client + ) + return client.focus(); + } + if (service_worker.clients.openWindow) + return service_worker.clients.openWindow("/notification"); + }), + ); +}); diff --git a/src/pages/Notification/index.tsx b/src/pages/Notification/index.tsx index cc3f3c5..55bd708 100644 --- a/src/pages/Notification/index.tsx +++ b/src/pages/Notification/index.tsx @@ -61,7 +61,7 @@ export default function NotificationPage() { const { setError } = React.useContext(ErrorContext); const [notifications, setNotifs] = useState(null); - const [status, setStatus] = useState(false); + const [status, setStatus] = useState(null); useEffect(() => { setup_present().then(setStatus); @@ -77,7 +77,7 @@ export default function NotificationPage() { }); }, []); - if (notifications === null) + if (notifications === null || status === null) return (
@@ -89,11 +89,23 @@ export default function NotificationPage() {

Latest Updates

{status ? ( - ) : ( - )} diff --git a/src/pages/Notification/notification-engine.ts b/src/pages/Notification/notification-engine.ts index ef73f1a..3b51da7 100644 --- a/src/pages/Notification/notification-engine.ts +++ b/src/pages/Notification/notification-engine.ts @@ -45,7 +45,7 @@ export async function setup_notification() { Notification.requestPermission(); const worker = await BgService.registerServiceWorker( - "https://team-dev.dtutimes.com/notification-service.js", + "https://team.dtutimes.com/notification-service.js", ); console.log("Service worker registered", worker); From c4bdb4f1a37dbeb52beec9171076f06dbd574d92 Mon Sep 17 00:00:00 2001 From: Vishal Date: Mon, 26 Aug 2024 20:17:35 +0530 Subject: [PATCH 13/13] remove non-required perm Signed-off-by: Vishal --- src/router/routeMap.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/router/routeMap.tsx b/src/router/routeMap.tsx index 4a36f40..39adf68 100644 --- a/src/router/routeMap.tsx +++ b/src/router/routeMap.tsx @@ -242,7 +242,7 @@ const routeMap: CustomRouteElement[] = [ path: "notification/", element: , icon: , - permission: [Permission.AccessLogs], + permission: [], label: "Notifications", }, ];