diff --git a/client/src/App.jsx b/client/src/App.jsx index 28fadcc..3b2a9be 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -11,12 +11,15 @@ import RequestPage from "./components/RequestPage/RequestPage"; import VerifyOtp from "./components/OtpVerificationPage/verifyOtp"; import LeaderBoard from "./components/Leaderboard/LeaderBoard"; import Notifcation from "./components/NotifcationPage/Notifcation"; +import Footer from "./components/Footer"; import Settings from "./components/Settings/Setting"; +import Statistics from "./components/Statistics/Statistics"; import QuestionPage from "./components/QuestionPage/QuestionPage"; import QuestionNotifcation from "./components/QuestionPage/QuestionNotification"; import AnswerPage from "./components/QuestionPage/AnswerPage"; import MasterPage from "./MasterPage"; + function App() { return ( @@ -24,7 +27,7 @@ function App() { } /> } /> } /> - + } /> }> }/> } /> diff --git a/client/src/components/Navbar/Navbar.jsx b/client/src/components/Navbar/Navbar.jsx index c755443..82e5198 100644 --- a/client/src/components/Navbar/Navbar.jsx +++ b/client/src/components/Navbar/Navbar.jsx @@ -7,7 +7,7 @@ import axios from "axios"; import { useLocation, useNavigate } from "react-router"; import Login from "../Login/Login.jsx"; import { Link } from "react-router-dom"; - +import { IoIosStats } from "react-icons/io"; function classNames(...classes) { return classes.filter(Boolean).join(" "); } @@ -19,6 +19,7 @@ const Navbar = () => { const [requestNav, setRequestNav] = useState(false); const [questionNav, setQuestionNav] = useState(false); const [leaderBoardNav, setleaderBoardNav] = useState(false); + const [statisticsNav, setStatisticsNav] = useState(false); const [searchInput, setSearchInput] = useState(""); const navigation = [ @@ -26,6 +27,7 @@ const Navbar = () => { { name: "Request Notes", href: "/request", current: requestNav }, { name: "Ask a Question", href: "/question", current: questionNav }, { name: "Leaderboard", href: "/leaderboard", current: leaderBoardNav }, + {name : "Statistics", href: "/statistics", current:statisticsNav} ]; const navigate = useNavigate(); @@ -86,6 +88,11 @@ const Navbar = () => { setRequestNav(false); setUploadNav(false); } + else if (loc === "/statistics"){ + setStatisticsNav(true); + setRequestNav(false); + setUploadNav(false); + } }, []); return ( diff --git a/client/src/components/Statistics/Statistics.jsx b/client/src/components/Statistics/Statistics.jsx new file mode 100644 index 0000000..58d3b85 --- /dev/null +++ b/client/src/components/Statistics/Statistics.jsx @@ -0,0 +1,247 @@ +Statistics.jsx + +import React, { useContext, useState, useEffect, Fragment } from 'react' +import Navbar from '../Navbar/Navbar' +import { useNavigate } from "react-router"; +import { UserContext } from "../../Context/UserContext"; +import storage from "../../firebase/firebase"; +import { Loader } from "../Loader/Loader"; +import axios from "axios"; + +const Statistics = () => { + const { user, setUser } = useContext(UserContext); + const [subjects, setSubjects] = useState([]); + const [notes, setNotes] = useState([]); + const [users, setUsers] = useState([]); + const [loading, setLoading] = useState(true); + const [isSmallScreen, setIsSmallScreen] = useState(false); + +useEffect(() => { + const handleResize = () => { + setIsSmallScreen(window.innerWidth < 768); + }; + + handleResize(); + + window.addEventListener("resize", handleResize); + + return () => { + window.removeEventListener("resize", handleResize); + }; +}, []); +useEffect(() => { + const fetchAllData = async () => { + try { + const fetchSubjects = async () => { + const token = localStorage.getItem("token"); + const config = { + headers: { + Authorization: `Bearer ${token}`, + }, + withCredentials: true, + }; + const res = await axios.get(`${import.meta.env.VITE_BASE_URL}/subject`, config); + setSubjects(res.data); + }; + + const fetchNotes = async () => { + const token = localStorage.getItem("token"); + const config = { + headers: { + Authorization: `Bearer ${token}`, + }, + withCredentials: true, + }; + const res = await axios.get(`${import.meta.env.VITE_BASE_URL}/note`, config); + setNotes(res.data); + }; + + const fetchUsers = async () => { + const response = await axios.get(`${import.meta.env.VITE_BASE_URL}/user/leaderboard`); + if (response.status === 200) { + setUsers(response.data); + console.log(response.data); + } + }; + + await Promise.all([fetchSubjects(), fetchNotes(), fetchUsers()]); + setLoading(false); + } catch (error) { + console.error("Error fetching data", error); + setLoading(false); + } + }; + + fetchAllData(); +}, []); + + return ( +
+ {loading ? ( +

+ ) : ( +
+ +
+
+
+
+ Avatar +
+ Subjects +
+
+
+

{subjects.length}

+
+
+
+
+
+
+
+
+
+ Avatar +
+ Students +
+
+
+

{users.length}

+
+
+
+
+
+
+
+
+
+ Avatar +
+ Notes +
+
+
+

{notes.length}

+
+
+
+
+
+
+ +
+ )} + +
+ ) +} + +const smallScreenStyles = { + uidesign: { + flexDirection: "column", + }, +}; +const styles = { + cardBox: { + display: "flex", + flexWrap: "wrap", + justifyContent: "center", + }, + subject: { + "> div": { + background: "#f5f7cd" + } + }, + + student: { + "> div": { + background: "#F0F4FF" + } + }, + notes: { + "> div": { + background: "#EFF8FF" + } + }, + card: { + flex: "1 1 300px", + boxShadow: "0 4px 8px 4px rgba(0, 0, 0, 0.4)", + borderRadius: "15px", + maxWidth: "300px", + margin: "20px 10px" + }, + minicard: { + position: "relative", + bottom: "30px", + boxShadow: "0 4px 8px 0 rgba(0, 0, 0, 0.4)", + borderRadius: "15px", + paddingTop: "10px", + paddingRight: "20px", + paddingBottom: "10px", + paddingLeft: "20px", + maxWidth: "170px", + backgroundColor: "white", + margin: "auto", + textAlign: "center", + font: '17px "Fira Sans", sans-serif', + color: "grey" + }, + rectangle: { + position: "relative", + width: "300px", + height: "350px", + background: "white" + }, + rectangle2: { + display: "block", + textAlign: "center", + position: "relative", + width: "50px", + height: "50px", + background: "black" + }, + avatar: { + position: "relative", + top: "30px", + borderRadius: "50%", + width: "120px", + height: "120px", + display: "block", + marginLeft: "auto", + marginRight: "auto", + marginBottom: "50px", + boxShadow: "0 4px 8px 0 rgba(0, 0, 0, 0.2)" + }, + pseudo: { + position: "relative", + top: "10px", + textAlign: "center", + color: "#100B51", + fontSize: "25px", + fontFamily: '"Helvetica Neue", Roboto, "Segoe UI", Calibri, sans-serif' + }, + cardExcerpt: { + font: '30px "Fira Sans", sans-serif', + color: "grey" + } + }; + +export default Statistics diff --git a/server/controllers/user.controller.js b/server/controllers/user.controller.js index 6b00ac6..4f509a8 100644 --- a/server/controllers/user.controller.js +++ b/server/controllers/user.controller.js @@ -236,7 +236,26 @@ const getLeaderBoard = async (req, res) => { error: error.message, }); } -}; +} + +const getUsers=async(req,res)=>{ + try { + const users=await User.find().select('-password') + if(!users){ + return res.status(404).json({ + message:"No users found" + }) + } + res.status(200).json(users) + } catch (error) { + res.status(500).json({ + message:"Internal server error", + error:error.message + }) + } +} + + ///forget password then verify password otp then update password //user/forget-password @@ -339,6 +358,7 @@ module.exports = { verifyOtp, getLeaderBoard, sendOTPcon, + getUsers, forgetPassword, updatePassword, vefifyPasswordOtp,