diff --git a/src/components/Announcements/TabContent.tsx b/src/components/Announcements/TabContent.tsx index ce195a75..3b09319e 100644 --- a/src/components/Announcements/TabContent.tsx +++ b/src/components/Announcements/TabContent.tsx @@ -24,10 +24,13 @@ type Events = { interface TabContentProps { posts: NewsPost[] | Events[]; isEvents?: boolean; -} + onItemClick?: () => void; } -const TabContent: React.FC = ({ posts, isEvents = false }) => { +const TabContent: React.FC = ({ posts, isEvents = false, onItemClick }) => { const locale = useLocale(); + const handleClick = () => { + onItemClick?.(); + }; const formatTimeAgo = (date: string): string => { const daysAgo = Math.floor((new Date().getTime() - new Date(date).getTime()) / (1000 * 60 * 60 * 24)); @@ -52,7 +55,7 @@ const TabContent: React.FC = ({ posts, isEvents = false }) => { {posts.map((event, index) => { const eventItem = event as Events; return ( -
+

@@ -93,7 +96,7 @@ const TabContent: React.FC = ({ posts, isEvents = false }) => { const description = isEF ? post.metadata.description : post.metadata.description; const date = isEF ? post.metadata.date : post.metadata.date; return ( -

+
{isEF ? (
diff --git a/src/components/Announcements/index.tsx b/src/components/Announcements/index.tsx index 061a6294..30c005fb 100644 --- a/src/components/Announcements/index.tsx +++ b/src/components/Announcements/index.tsx @@ -5,13 +5,18 @@ import { fetchLatestEvents } from "@/hooks" interface AnnouncementsProps { handleClose: () => void; + onNotificationRead: () => void; } -const Announcements = ({ handleClose }: AnnouncementsProps) => { +const Announcements = ({ handleClose , onNotificationRead }: AnnouncementsProps) => { const [latestPosts, setLatestPosts] = useState([]) const [latestReleases, setLatestReleases] = useState([]) const [latestEvents, setLatestEvents] = useState([]) const [active, setActive] = useState("Updates") + const handleNotificationClick = () => { + onNotificationRead(); + }; + useEffect(() => { // Fetch latest news posts @@ -65,9 +70,9 @@ const Announcements = ({ handleClose }: AnnouncementsProps) => {
- {active === "Updates" && } - {active === "Events" && } - {active === "Releases" && } + {active === "Updates" && } + {active === "Events" && } + {active === "Releases" && }
diff --git a/src/components/NavBar/index.tsx b/src/components/NavBar/index.tsx index ca442957..81a41ef5 100644 --- a/src/components/NavBar/index.tsx +++ b/src/components/NavBar/index.tsx @@ -14,6 +14,7 @@ import { } from "@headlessui/react" import { FaChevronDown, FaRegBell } from "react-icons/fa" import { BsXLg, BsList } from "react-icons/bs" +import { fetchLatestEvents } from "@/hooks"; import IconSocial from "@/components/IconSocial" import LanguageSelector from "@/components/LanguageSelector" @@ -157,10 +158,56 @@ const NavBar = ({ locale }: { locale: string }) => { const [showLastSlide, setShowLastSlide] = useState(false) const [showAnnouncement, setShowAnnouncement] = useState(false) const [activeLastSlide, setActiveLastSlide] = useState(null) + const [unreadCount, setUnreadCount] = useState(0); // To prevent hydration mismatch, we'll start with no active paths const [activePaths, setActivePaths] = useState>(new Set()) const pathname = usePathname(); +useEffect(() => { + const fetchUnreadCount = async () => { + try { + const ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1000; + const now = Date.now(); + + const postsResponse = await fetch("/api/news?numPosts=4"); + const postsData = await postsResponse.json(); + + const releasesResponse = await fetch("/api/news/byTag?tag=release-notes&numPosts=4"); + const releasesData = await releasesResponse.json(); + + const eventsData = await fetchLatestEvents(); + const slicedEvents = eventsData.slice(0, 6); + + const recentPosts = (postsData.posts || []).filter( + (p: { date: string }) => now - new Date(p.date).getTime() <= ONE_WEEK_MS + ); + + const recentReleases = (releasesData.posts || []).filter( + (p: { date: string }) => now - new Date(p.date).getTime() <= ONE_WEEK_MS + ); + + const recentEvents = (slicedEvents || []).filter( + (e: { date: string }) => now - new Date(e.date).getTime() <= ONE_WEEK_MS + ); + + const totalCount = recentPosts.length + recentReleases.length + recentEvents.length; + + setUnreadCount(totalCount); + } catch (error) { + console.error("Error fetching announcement count:", error); + setUnreadCount(0); + } + }; + + fetchUnreadCount(); +}, []); + +const handleNotificationRead = () => { + setUnreadCount(prev => Math.max(0, prev - 1)); +}; + + + useEffect(() => { if (!mobileMenuOpen) { setShowLastSlide(false) @@ -201,7 +248,7 @@ const NavBar = ({ locale }: { locale: string }) => { }`} > {showAnnouncement && ( - setShowAnnouncement(false)} /> + setShowAnnouncement(false)} onNotificationRead={handleNotificationRead} /> )} {/* Container div to center the nav content */}
@@ -302,16 +349,17 @@ const NavBar = ({ locale }: { locale: string }) => {
-
setShowAnnouncement(!showAnnouncement)} - className="relative" - > - - - 1 - -
+
{setShowAnnouncement(!showAnnouncement);}} + className="relative"> + + {unreadCount > 0 && ( + + {unreadCount} + + )} +