From 800efeb784176b3e1ab924b45279dab44f5c5086 Mon Sep 17 00:00:00 2001 From: soheil khaledabadi Date: Sun, 27 Sep 2026 22:05:40 +0330 Subject: [PATCH] feat: show the admin-managed announcement popup when the site opens Fetch the live notice from the API so users see maintenance updates without a hardcoded toast. Co-authored-by: Cursor --- src/App.tsx | 2 + .../SiteAnnouncementModal.tsx | 128 ++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 src/components/siteAnnouncement/SiteAnnouncementModal.tsx diff --git a/src/App.tsx b/src/App.tsx index 896e312..3759805 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -23,6 +23,7 @@ import { useSelector } from "react-redux"; import { RootState } from "./redux/store"; import Page404 from "./pages/404"; import RedirectToHome from "./utils/redirect-to-home "; +import SiteAnnouncementModal from "./components/siteAnnouncement/SiteAnnouncementModal"; // import LandingLayout from "./layout/LandingLayout"; // import Landing from "./pages/landing"; @@ -40,6 +41,7 @@ const App = () => { }} /> + {/* }> }> diff --git a/src/components/siteAnnouncement/SiteAnnouncementModal.tsx b/src/components/siteAnnouncement/SiteAnnouncementModal.tsx new file mode 100644 index 0000000..5439473 --- /dev/null +++ b/src/components/siteAnnouncement/SiteAnnouncementModal.tsx @@ -0,0 +1,128 @@ +import Modal from "@mui/material/Modal"; +import { useQuery } from "@tanstack/react-query"; +import { motion } from "framer-motion"; +import { useEffect, useState } from "react"; +import { FaTelegram } from "react-icons/fa6"; +import { IoClose } from "react-icons/io5"; +import { MdCampaign } from "react-icons/md"; +import useAxios from "../../hooks/useAxios"; +import Button from "../button"; + +type SiteAnnouncement = { + enabled: boolean; + title?: string; + body?: string; + support_url?: string; + support_label?: string; + version?: string; +}; + +const STORAGE_KEY = "site_announcement_dismissed_version"; + +const SiteAnnouncementModal = () => { + const axios = useAxios(); + const [isOpen, setIsOpen] = useState(false); + + const { data } = useQuery({ + queryKey: ["site-announcement"], + queryFn: () => axios.get("/home/announcement"), + }); + + const announcement = data?.data?.result as SiteAnnouncement | undefined; + + useEffect(() => { + if (!announcement?.enabled) { + setIsOpen(false); + return; + } + + const dismissedVersion = sessionStorage.getItem(STORAGE_KEY); + if (dismissedVersion && dismissedVersion === String(announcement.version)) { + setIsOpen(false); + return; + } + + setIsOpen(true); + }, [announcement]); + + const handleClose = () => { + if (announcement?.version) { + sessionStorage.setItem(STORAGE_KEY, String(announcement.version)); + } + setIsOpen(false); + }; + + if (!announcement?.enabled) { + return null; + } + + return ( + + +
+
+
+ +
+ +

+ {announcement.body} +

+ +
+ {announcement.support_url && ( + + + )} + +
+
+
+ ); +}; + +export default SiteAnnouncementModal;