Add a prompt to encourage users to subscribe to push notifications

Introduce a new push notification prompt banner that appears on the homepage after a delay, encouraging users to subscribe to notifications. The banner will not appear if the user is already subscribed, has previously dismissed it, or if push notifications are not supported. Refactor existing push notification logic to be more modular and reusable across components.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 23852c00-4779-460a-9e0c-d09fee4b6c92
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: cf18a9e4-eed8-448c-9c3c-694f18134403
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
This commit is contained in:
sebastjanartic
2026-03-07 15:21:17 +00:00
parent d5b8134b9d
commit 2c74322b1c
6 changed files with 99 additions and 60 deletions
@@ -0,0 +1,90 @@
import { useState, useEffect } from "react";
import { Bell, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useToast } from "@/hooks/use-toast";
import { isPushSupported, getExistingSubscription, subscribeToPush } from "@/lib/push-utils";
const DISMISS_KEY = "folx-push-prompt-dismissed";
export default function PushPromptBanner() {
const [visible, setVisible] = useState(false);
const { toast } = useToast();
useEffect(() => {
if (!isPushSupported()) return;
if (localStorage.getItem(DISMISS_KEY)) return;
if (Notification.permission === "denied") return;
const timer = setTimeout(async () => {
const sub = await getExistingSubscription();
if (!sub) setVisible(true);
}, 5000);
return () => clearTimeout(timer);
}, []);
const dismiss = () => {
setVisible(false);
localStorage.setItem(DISMISS_KEY, "1");
};
const accept = async () => {
try {
await subscribeToPush();
toast({ title: "Benachrichtigungen aktiviert", description: "Sie werden über neue Inhalte informiert." });
} catch {
if (Notification.permission === "denied") {
toast({ title: "Benachrichtigungen blockiert", description: "Bitte erlauben Sie Benachrichtigungen in Ihren Browsereinstellungen.", variant: "destructive" });
}
}
dismiss();
};
if (!visible) return null;
return (
<div className="fixed bottom-4 left-4 right-4 md:left-auto md:right-6 md:max-w-sm z-50 animate-in slide-in-from-bottom-4 fade-in duration-500" data-testid="push-prompt-banner">
<div className="bg-card border border-card-border rounded-xl shadow-2xl p-4">
<div className="flex items-start gap-3">
<div className="flex-shrink-0 w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center">
<Bell className="w-5 h-5 text-primary" />
</div>
<div className="flex-1 min-w-0">
<p className="font-semibold text-foreground text-sm" data-testid="text-push-prompt-title">
Nichts mehr verpassen!
</p>
<p className="text-xs text-muted-foreground mt-1">
Erhalten Sie Benachrichtigungen über neue Artikel und Videos von FOLX TV.
</p>
<div className="flex items-center gap-2 mt-3">
<Button
size="sm"
onClick={accept}
className="text-xs h-8"
data-testid="button-push-prompt-accept"
>
Ja, gerne!
</Button>
<Button
variant="ghost"
size="sm"
onClick={dismiss}
className="text-xs h-8 text-muted-foreground"
data-testid="button-push-prompt-dismiss"
>
Nein, danke
</Button>
</div>
</div>
<button
onClick={dismiss}
className="text-muted-foreground hover:text-foreground transition-colors"
data-testid="button-push-prompt-close"
>
<X className="w-4 h-4" />
</button>
</div>
</div>
</div>
);
}