"use client"; import { ExternalLink } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; import { useEffect, useMemo, useState } from "react"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogTitle, } from "@/components/ui/dialog"; import { useAnnouncements } from "@/hooks/use-announcements"; /** * Proactively shows important "spotlight" announcements in a blocking dialog. * * Behaviour: * - On load, the first active, audience-matched, unread spotlight announcement * is shown automatically. * - The user must explicitly acknowledge it ("Got it" or the CTA link), which * marks it as read so it never shows again. * - Closing via the X / Escape / outside-click only hides it for the current * session; it reappears on the next load until the user marks it as seen. */ export function AnnouncementSpotlight() { const { announcements, markRead } = useAnnouncements(); const [sessionDismissed, setSessionDismissed] = useState>(() => new Set()); const [ready, setReady] = useState(false); // Short delay so the spotlight doesn't flash during initial hydration/layout. useEffect(() => { const timer = setTimeout(() => setReady(true), 800); return () => clearTimeout(timer); }, []); const current = useMemo( () => announcements.find( (a) => a.spotlight && a.isImportant && !a.isRead && !sessionDismissed.has(a.id) ) ?? null, [announcements, sessionDismissed] ); if (!current) return null; const handleAcknowledge = () => { markRead(current.id); }; const handleOpenChange = (next: boolean) => { if (!next) { setSessionDismissed((prev) => { const updated = new Set(prev); updated.add(current.id); return updated; }); } }; return ( {current.image && (
{current.image.alt}
)}
{current.title} {current.description} {current.link && ( )}
); }