diff --git a/django_project/frontend/src/Routes.tsx b/django_project/frontend/src/Routes.tsx index b19b65fa..702a96ad 100644 --- a/django_project/frontend/src/Routes.tsx +++ b/django_project/frontend/src/Routes.tsx @@ -10,6 +10,7 @@ const NotFound = React.lazy(() => import("./pages/NotFound")); const ProfileInformationPage = React.lazy(() => import("./pages/Profile")); const OrganisationInformation = React.lazy(() => import("./pages/OrganisationInformation")); const AnalysisResults = React.lazy(() => import("./pages/AnalysisResults")); +const NotificationsPage = React.lazy(() => import("./pages/Notifications")); const UploadedResourcesPage = React.lazy(() => import("./pages/UploadedResources")); const ProjectRoutes = () => { @@ -33,6 +34,10 @@ const ProjectRoutes = () => { path: "/analysis-results", element: , }, + { + path: "/notifications", + element: , + }, ]); return ( diff --git a/django_project/frontend/src/components/SideBar/index.tsx b/django_project/frontend/src/components/SideBar/index.tsx index c02163a8..2b1923f2 100644 --- a/django_project/frontend/src/components/SideBar/index.tsx +++ b/django_project/frontend/src/components/SideBar/index.tsx @@ -12,9 +12,9 @@ import React from "react"; import { MenuItem, Menu } from "react-pro-sidebar"; import { HamburgerIcon } from "@chakra-ui/icons"; import { useLocation, useNavigate } from "react-router-dom"; -import { AppDispatch, RootState } from '../../store'; -import { logoutUser } from '../../store/authSlice'; -import { useDispatch } from 'react-redux'; +import { AppDispatch } from '../../store'; +import { useDispatch } from "react-redux"; +import { logoutUser } from "../../store/authSlice"; interface Props extends ChakraProps { className?: string; @@ -22,16 +22,16 @@ interface Props extends ChakraProps { export default function Sidebar(props: Props) { const { isOpen, onOpen, onClose } = useDisclosure(); + const dispatch = useDispatch(); const location = useLocation(); const navigate = useNavigate(); const isActive = (path: string) => location.pathname === path; - const dispatch = useDispatch(); const handleLogout = () => { - dispatch(logoutUser()); - onClose(); - navigate('/'); - }; + dispatch(logoutUser()); + onClose(); + navigate('/'); + }; return ( <> @@ -80,20 +80,23 @@ export default function Sidebar(props: Props) { Organisation Information navigate('/dashboard')}>My Dashboard - navigate('/uploaded-resources')} - > - Uploaded Resources - navigate('/analysis-results')}> Analysis Results + navigate('/uploaded-resources')}> + Uploaded Resources + navigate('/support')}>Support - navigate('/notifications')}>Notifications - navigate('/sign-out')}>Sign Out + navigate('/notifications')}> + Notifications + + handleLogout()}>Sign Out @@ -170,23 +173,23 @@ export default function Sidebar(props: Props) { Organisation Information { navigate('/dashboard'); onClose(); }}>My Dashboard - { - navigate('/uploaded-resources'); - onClose(); - }} - > - Uploaded Resources - { navigate('/analysis-results'); onClose(); }}> Analysis Results + { navigate('/uploaded-resources'); onClose(); }}> + Uploaded Resources + { navigate('/support'); onClose(); }}>Support - { navigate('/notifications'); onClose(); }}>Notifications - handleLogout()}>Sign Out + { navigate('/notifications'); onClose(); }}> + Notifications + + { navigate('/sign-out'); onClose(); }}>Sign Out diff --git a/django_project/frontend/src/pages/Notifications/index.tsx b/django_project/frontend/src/pages/Notifications/index.tsx new file mode 100644 index 00000000..038ec14f --- /dev/null +++ b/django_project/frontend/src/pages/Notifications/index.tsx @@ -0,0 +1,133 @@ +import React, { useState, useEffect } from "react"; +import Helmet from "react-helmet"; +import { + Box, + Heading, + Flex, + Tabs, + TabList, + TabPanels, + Tab, + TabPanel, + Text, + IconButton, +} from "@chakra-ui/react"; +import { FaCog } from "react-icons/fa"; // Importing the gear icon +import Header from "../../components/Header"; +import Sidebar from "../../components/SideBar"; +import NotificationsTab from "./notificationsTab"; +import "../../styles/index.css"; +import SystemTab from "./systemTab"; + +export default function Notifications() { + const [selectedTab, setSelectedTab] = useState("all"); + + const handleSettingsClick = () => { + // You can handle the settings button click here (e.g., open a modal or navigate to settings page) + alert("Settings clicked"); + }; + + return ( + <> + + Notifications + + + +
+ + + {/* Sidebar */} + + + {/* Main Content */} + + + Notifications + + + {/* Tabs */} + + setSelectedTab( + index === 0 + ? "all" + : index === 1 + ? "personal" + : index === 2 + ? "organisations" + : "system" + ) + } + > + + + All + + + Personal + + + Organisations + + + System + + + {/* Gear Icon on the extreme right */} + } + aria-label="Settings" + onClick={handleSettingsClick} + size="lg" + variant="ghost" + colorScheme="green" + ml="auto" + /> + + + + + + + + No data available for Personal notifications. + + + No data available for Organisations notifications. + + + + + + + + + + + ); +} diff --git a/django_project/frontend/src/pages/Notifications/notificationsTab.tsx b/django_project/frontend/src/pages/Notifications/notificationsTab.tsx new file mode 100644 index 00000000..2ec24ac3 --- /dev/null +++ b/django_project/frontend/src/pages/Notifications/notificationsTab.tsx @@ -0,0 +1,78 @@ +import React, { useState, useEffect } from "react"; +import { + Box, + Heading, + Text, + Badge, +} from "@chakra-ui/react"; +import "../../styles/index.css"; + +export default function NotificationsTab() { + const [allNotifications, setAllNotifications] = useState([]); + + useEffect(() => { + // Simulate fetching data for "All" notifications + const fetchNotificationsData = () => { + + setAllNotifications([]); + }; + + fetchNotificationsData(); + }, []); + + return ( + <> + + {allNotifications.map((notification) => ( + + {/* Badge - Custom styled */} + + {notification.badge} + + + {/* Title */} + + {notification.title} + + + {/* Description */} + + {notification.description} + + + {/* Timestamp */} + + {notification.timestamp} + + + ))} + + + ); +} diff --git a/django_project/frontend/src/pages/Notifications/systemTab.tsx b/django_project/frontend/src/pages/Notifications/systemTab.tsx new file mode 100644 index 00000000..2ff339de --- /dev/null +++ b/django_project/frontend/src/pages/Notifications/systemTab.tsx @@ -0,0 +1,232 @@ +import React, { useState, useEffect } from "react"; +import { + Box, + Heading, + Text, + Badge, + Table, + Checkbox, + Flex, + IconButton, + Input, + Select, + Switch, + Tbody, + Td, + Th, + Thead, + Tr, +} from "@chakra-ui/react"; +import "../../styles/index.css"; +import { FaArrowLeft, FaArrowRight } from "react-icons/fa"; + +export default function SystemTab() { + const [thresholdValue, setThresholdValue] = useState(0.05); + const [allNotifications, setAllNotifications] = useState([]); + const [personalNotifications, setPersonalNotifications] = useState([]); + const [organisationsNotifications, setOrganisationsNotifications] = useState([]); + const [systemNotifications, setSystemNotifications] = useState([]); + + // Dummy Data for all notifications + useEffect(() => { + const fetchNotificationsData = async () => { + + setAllNotifications([]); + + // You can also set other notifications as needed + setPersonalNotifications([]); + setOrganisationsNotifications([]); + setSystemNotifications([]); + }; + + fetchNotificationsData(); + }, []); + + const handleToggleChange = (event: React.ChangeEvent, id: number, field: string) => { + if (field === "alert") { + const updatedData = allNotifications.map((item) => + item.id === id ? { ...item, alert: event.target.checked } : item + ); + setAllNotifications(updatedData); + } else if (field === "anomalyDetectionAlert") { + const updatedData = allNotifications.map((item) => + item.id === id ? { ...item, anomalyDetectionAlert: event.target.checked } : item + ); + setAllNotifications(updatedData); + } + }; + + const handleCheckboxChange = (e: React.ChangeEvent, type: string, id: number) => { + const updatedData = allNotifications.map((item) => + item.id === id + ? { + ...item, + [type]: e.target.checked, + } + : item + ); + setAllNotifications(updatedData); + }; + + const handleArrowChange = (direction: string) => { + if (direction === "increase") { + setThresholdValue((prev) => prev + 0.01); + } else { + setThresholdValue((prev) => prev - 0.01); + } + }; + + return ( + <> + + + + + + + + + + + + + + {allNotifications.map((notification) => ( + + + + + + + + + + ))} + +
IndicatorsAlertsAlert TriggerThreshold ValueAnomaly Detection AlertEmailPlatform
{notification.indicator} + handleToggleChange(e, notification.id, "alert")} + sx={{ + "& .chakra-switch__track": { + backgroundColor: "gray.300", + _checked: { + backgroundColor: "#91e05e", + }, + }, + "& .chakra-switch__thumb": { + backgroundColor: "white", + _checked: { + backgroundColor: "white", + }, + }, + }} + /> + + + + + } + onClick={() => handleArrowChange("decrease")} + size="sm" + variant="ghost" + aria-label="Decrease threshold" + /> + + } + onClick={() => handleArrowChange("increase")} + size="sm" + variant="ghost" + aria-label="Increase threshold" + /> + + + handleToggleChange(e, notification.id, "anomalyDetectionAlert")} + sx={{ + "& .chakra-switch__track": { + backgroundColor: "gray.300", + _checked: { + backgroundColor: "#91e05e", + }, + }, + "& .chakra-switch__thumb": { + backgroundColor: "white", + _checked: { + backgroundColor: "white", + }, + }, + }} + /> + + handleCheckboxChange(e, "email", notification.id)} + size="lg" + sx={{ + "& .chakra-checkbox__control": { + backgroundColor: "transparent", + borderColor: "gray.400", + borderRadius: "50%", + width: "30px", + height: "30px", + }, + "& .chakra-checkbox__control[data-checked='true']": { + backgroundColor: "#91e05e", + borderColor: "#91e05e", + }, + }} + /> + + handleCheckboxChange(e, "platform", notification.id)} + size="lg" + sx={{ + "& .chakra-checkbox__control": { + backgroundColor: "transparent", + borderColor: "gray.400", + borderRadius: "50%", + width: "30px", + height: "30px", + }, + "& .chakra-checkbox__control[data-checked='true']": { + backgroundColor: "#91e05e", + borderColor: "#91e05e", + }, + }} + /> +
+ + ); +}