From fc3461c377f0b8fa464095e7df3abde3658886f4 Mon Sep 17 00:00:00 2001 From: Carlos Escalante Date: Fri, 12 Jun 2026 18:07:02 -0600 Subject: [PATCH] PWA installability + working service worker (wishlist #8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit manifest.webmanifest with the existing icons, apple-touch-icon, and SW registration at startup. The old sw.js was a self-unregistering cleanup stub — meaning serviceWorker.ready never resolved and web push has been silently dead; the new worker handles push display and notification clicks, and makes the app installable. Co-Authored-By: Claude Fable 5 --- frontend/index.html | 2 ++ frontend/public/manifest.webmanifest | 29 +++++++++++++++++++ frontend/public/sw.js | 42 ++++++++++++++++++++++++++-- frontend/src/main.tsx | 7 +++++ 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 frontend/public/manifest.webmanifest diff --git a/frontend/index.html b/frontend/index.html index 440ce1e..69b6847 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -12,6 +12,8 @@ + + WealthySmart diff --git a/frontend/public/manifest.webmanifest b/frontend/public/manifest.webmanifest new file mode 100644 index 0000000..c2f9e9f --- /dev/null +++ b/frontend/public/manifest.webmanifest @@ -0,0 +1,29 @@ +{ + "name": "WealthySmart", + "short_name": "WealthySmart", + "description": "Smart personal finance management", + "start_url": "/", + "scope": "/", + "display": "standalone", + "background_color": "#0f172a", + "theme_color": "#0f172a", + "lang": "es-CR", + "icons": [ + { + "src": "/icons/icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/icons/icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "/icons/icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/frontend/public/sw.js b/frontend/public/sw.js index 5c8b7ce..3104549 100644 --- a/frontend/public/sw.js +++ b/frontend/public/sw.js @@ -1,4 +1,42 @@ +/* WealthySmart service worker: web push + PWA installability. + * (Replaces the old self-unregistering cleanup stub, which also meant + * `navigator.serviceWorker.ready` never resolved and push silently no-oped.) */ + self.addEventListener("install", () => self.skipWaiting()); -self.addEventListener("activate", async () => { - await self.registration.unregister(); + +self.addEventListener("activate", (event) => { + event.waitUntil(self.clients.claim()); +}); + +self.addEventListener("push", (event) => { + let data = { title: "WealthySmart", body: "", url: "/" }; + try { + data = { ...data, ...event.data.json() }; + } catch { + if (event.data) data.body = event.data.text(); + } + event.waitUntil( + self.registration.showNotification(data.title, { + body: data.body, + icon: "/icons/icon-192.png", + badge: "/icons/icon-192.png", + data: { url: data.url }, + }), + ); +}); + +self.addEventListener("notificationclick", (event) => { + event.notification.close(); + const url = event.notification.data?.url || "/"; + event.waitUntil( + self.clients.matchAll({ type: "window", includeUncontrolled: true }).then((clients) => { + for (const client of clients) { + if ("focus" in client) { + client.navigate(url); + return client.focus(); + } + } + return self.clients.openWindow(url); + }), + ); }); diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index c2a145c..cde6120 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -3,6 +3,13 @@ import { createRoot } from "react-dom/client"; import App from "./App"; import "./index.css"; +if ("serviceWorker" in navigator) { + // Required for both web push and PWA installability. + navigator.serviceWorker.register("/sw.js").catch((err) => { + console.warn("Service worker registration failed:", err); + }); +} + createRoot(document.getElementById("root")!).render(