From f6478a76630f8b398569f1960af297f3fd9fefe3 Mon Sep 17 00:00:00 2001
From: sebastjanartic <45803536-sebastjanartic@users.noreply.replit.com>
Date: Sat, 7 Mar 2026 15:16:12 +0000
Subject: [PATCH] Add web push notification system for user engagement and
updates
Implement a web push notification system, including service worker integration, user subscription management, and an admin interface for sending broadcast messages.
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 23852c00-4779-460a-9e0c-d09fee4b6c92
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: f585829f-898b-492f-82a5-11f4a76c87fb
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/23852c00-4779-460a-9e0c-d09fee4b6c92/ICRgny1
Replit-Helium-Checkpoint-Created: true
---
client/public/sw.js | 31 +++++
client/src/App.tsx | 2 +
client/src/components/header.tsx | 2 +
.../src/components/push-notification-bell.tsx | 126 ++++++++++++++++++
client/src/pages/admin-push.tsx | 122 +++++++++++++++++
package-lock.json | 10 ++
package.json | 1 +
replit.md | 6 +
server/routes.ts | 79 +++++++++++
server/storage.ts | 29 +++-
shared/schema.ts | 16 +++
11 files changed, 423 insertions(+), 1 deletion(-)
create mode 100644 client/public/sw.js
create mode 100644 client/src/components/push-notification-bell.tsx
create mode 100644 client/src/pages/admin-push.tsx
diff --git a/client/public/sw.js b/client/public/sw.js
new file mode 100644
index 0000000..188a153
--- /dev/null
+++ b/client/public/sw.js
@@ -0,0 +1,31 @@
+self.addEventListener("push", (event) => {
+ let data = { title: "FOLX TV", body: "Neuer Inhalt verfügbar!", url: "/" };
+ try {
+ data = event.data.json();
+ } catch (e) {}
+ event.waitUntil(
+ self.registration.showNotification(data.title, {
+ body: data.body,
+ icon: "/favicon.png",
+ badge: "/favicon.png",
+ data: { url: data.url || "/" },
+ })
+ );
+});
+
+self.addEventListener("notificationclick", (event) => {
+ event.notification.close();
+ let url = event.notification.data?.url || "/";
+ if (!url.startsWith("/") || url.startsWith("//")) url = "/";
+ event.waitUntil(
+ clients.matchAll({ type: "window", includeUncontrolled: true }).then((clientList) => {
+ for (const client of clientList) {
+ if (client.url.includes(self.location.origin) && "focus" in client) {
+ client.navigate(url);
+ return client.focus();
+ }
+ }
+ return clients.openWindow(url);
+ })
+ );
+});
diff --git a/client/src/App.tsx b/client/src/App.tsx
index 6c88d8f..f3280bd 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -19,6 +19,7 @@ import ImpressumPage from "@/pages/impressum";
import DatenschutzPage from "@/pages/datenschutz";
import KontaktPage from "@/pages/kontakt";
import AdminGalleryPage from "@/pages/admin-gallery";
+import AdminPushPage from "@/pages/admin-push";
import CookieConsent from "@/components/cookie-consent";
function ScrollToTop() {
@@ -49,6 +50,7 @@ function Router() {