diff --git a/client/index.html b/client/index.html index 51a367d..cc68c71 100644 --- a/client/index.html +++ b/client/index.html @@ -41,8 +41,7 @@ bottom: 0; } - .preloader-equalizer ul li { - &:nth-child(1) { + .preloader-equalizer ul li:nth-child(1) { left: 0; animation: cssload-sequence1 1.15s ease infinite 0; -o-animation: cssload-sequence1 1.15s ease infinite 0; @@ -50,7 +49,8 @@ -webkit-animation: cssload-sequence1 1.15s ease infinite 0; -moz-animation: cssload-sequence1 1.15s ease infinite 0; } - &:nth-child(2) { + + .preloader-equalizer ul li:nth-child(2) { left: 15px; animation: cssload-sequence2 1.15s ease infinite 0.12s; -o-animation: cssload-sequence2 1.15s ease infinite 0.12s; @@ -58,7 +58,8 @@ -webkit-animation: cssload-sequence2 1.15s ease infinite 0.12s; -moz-animation: cssload-sequence2 1.15s ease infinite 0.12s; } - &:nth-child(3) { + + .preloader-equalizer ul li:nth-child(3) { left: 29px; animation: cssload-sequence1 1.15s ease-in-out infinite 0.23s; -o-animation: cssload-sequence1 1.15s ease-in-out infinite 0.23s; @@ -66,7 +67,8 @@ -webkit-animation: cssload-sequence1 1.15s ease-in-out infinite 0.23s; -moz-animation: cssload-sequence1 1.15s ease-in-out infinite 0.23s; } - &:nth-child(4) { + + .preloader-equalizer ul li:nth-child(4) { left: 44px; animation: cssload-sequence2 1.15s ease-in infinite 0.35s; -o-animation: cssload-sequence2 1.15s ease-in infinite 0.35s; @@ -74,7 +76,8 @@ -webkit-animation: cssload-sequence2 1.15s ease-in infinite 0.35s; -moz-animation: cssload-sequence2 1.15s ease-in infinite 0.35s; } - &:nth-child(5) { + + .preloader-equalizer ul li:nth-child(5) { left: 58px; animation: cssload-sequence1 1.15s ease-in-out infinite 0.46s; -o-animation: cssload-sequence1 1.15s ease-in-out infinite 0.46s; @@ -82,7 +85,8 @@ -webkit-animation: cssload-sequence1 1.15s ease-in-out infinite 0.46s; -moz-animation: cssload-sequence1 1.15s ease-in-out infinite 0.46s; } - &:nth-child(6) { + + .preloader-equalizer ul li:nth-child(6) { left: 73px; animation: cssload-sequence2 1.15s ease infinite 0.58s; -o-animation: cssload-sequence2 1.15s ease infinite 0.58s; @@ -90,7 +94,6 @@ -webkit-animation: cssload-sequence2 1.15s ease infinite 0.58s; -moz-animation: cssload-sequence2 1.15s ease infinite 0.58s; } - } @keyframes cssload-sequence1 { diff --git a/client/package-lock.json b/client/package-lock.json index 872d1b0..9b947fd 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -19,6 +19,7 @@ "framer-motion": "^10.16.4", "gsap": "^3.12.5", "locomotive-scroll": "^5.0.0-beta.12", + "postcss-nesting": "^13.0.1", "react": "^18.2.0", "react-confetti": "^6.1.0", "react-cookie": "^4.1.1", @@ -4855,9 +4856,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001621", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001621.tgz", - "integrity": "sha512-+NLXZiviFFKX0fk8Piwv3PfLPGtRqJeq2TiNoUff/qB5KJgwecJTvCXDpmlyP/eCI/GUEmp/h/y5j0yckiiZrA==", + "version": "1.0.30001702", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001702.tgz", + "integrity": "sha512-LoPe/D7zioC0REI5W73PeR1e1MLCipRGq/VkovJnd6Df+QVqT+vT33OXCp8QUd7kA7RZrHWxb1B36OQKI/0gOA==", "funding": [ { "type": "opencollective", @@ -9253,6 +9254,86 @@ "postcss": "^8.2.14" } }, + "node_modules/postcss-nesting": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.1.tgz", + "integrity": "sha512-VbqqHkOBOt4Uu3G8Dm8n6lU5+9cJFxiuty9+4rcoyRPO9zZS1JIs6td49VIoix3qYqELHlJIn46Oih9SAKo+yQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/selector-resolve-nested": "^3.0.0", + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-resolve-nested": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.0.0.tgz", + "integrity": "sha512-ZoK24Yku6VJU1gS79a5PFmC8yn3wIapiKmPgun0hZgEI5AOqgH2kiPRsPz1qkGv4HL+wuDLH83yQyk6inMYrJQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-nesting/node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-selector-parser": { "version": "6.0.13", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", diff --git a/client/package.json b/client/package.json index c2a2cd6..0c228d1 100644 --- a/client/package.json +++ b/client/package.json @@ -20,6 +20,7 @@ "framer-motion": "^10.16.4", "gsap": "^3.12.5", "locomotive-scroll": "^5.0.0-beta.12", + "postcss-nesting": "^13.0.1", "react": "^18.2.0", "react-confetti": "^6.1.0", "react-cookie": "^4.1.1", diff --git a/client/postcss.config.js b/client/postcss.config.js index 2e7af2b..f5d0c25 100644 --- a/client/postcss.config.js +++ b/client/postcss.config.js @@ -1,5 +1,6 @@ export default { plugins: { + tailwindcss: {}, autoprefixer: {}, }, diff --git a/client/src/Components/Footer.jsx b/client/src/Components/Footer.jsx index 7bfee42..e56f01f 100644 --- a/client/src/Components/Footer.jsx +++ b/client/src/Components/Footer.jsx @@ -5,63 +5,64 @@ import { Link } from "react-router-dom"; export default function Footer() { return ( - + ); } diff --git a/client/src/Components/Student/StudentList.jsx b/client/src/Components/Student/StudentList.jsx index 75ce680..18ed589 100644 --- a/client/src/Components/Student/StudentList.jsx +++ b/client/src/Components/Student/StudentList.jsx @@ -59,9 +59,7 @@ const StudentList = ({ token, user }) => { }, } - // headers: { - // Authorization: `Bearer ${token}`, - // }, + ); toast.success("Student deleted successfully!"); fetchStudents(); @@ -80,18 +78,18 @@ const StudentList = ({ token, user }) => { return ( <>
-
+

Student List

-
-
+
+
{
-
- {filteredStudents.map((student) => ( - -
-

{student.name}

-

ID: {student.idNumber}

-

Email: {student.email}

-

Phone: {student.phoneNumber}

-
-
- {/* Add buttons for editing and deleting a student */} - - Edit - - - View Subjects - - -
-
- ))} +
+
+ {filteredStudents.map((student) => ( + +
+

{student.name}

+

ID: {student.idNumber}

+

Email: {student.email}

+

Phone: {student.phoneNumber}

+
+
+ + Edit + + + View Subjects + +
+
+ ))} +
+
+ {showModal && (
{ + const [isOpen, setIsOpen] = useState(false); + + const toggleMenu = () => { + setIsOpen((prev) => !prev); + }; + return ( ); }; diff --git a/client/src/Components/Subject/SubjectList.jsx b/client/src/Components/Subject/SubjectList.jsx index 92e0038..35c5b5d 100644 --- a/client/src/Components/Subject/SubjectList.jsx +++ b/client/src/Components/Subject/SubjectList.jsx @@ -84,21 +84,22 @@ const ElectiveSubjectPage = () => { }; return ( -
-
+
+ {/* Main content container */} +

Elective Subjects

-
+
- + Search Icon {
-
-
- {filteredSubjects.map((subject) => ( - -
-
-

- {subject.subjectName} -

- -

{subject.subjectCode}

-
-
-

{subject.subjectDescription}

-
-
+
+ {filteredSubjects.map((subject) => ( + +
+
+

{subject.subjectName}

+

{subject.subjectCode}

+
+
+

{subject.subjectDescription}

+
+
+
Edit View Students
-
- - ))} + + ))} +
+ {/* Modal */} {showModal && ( ); + + }; export default ElectiveSubjectPage; diff --git a/client/src/Components/SubjectNavbar.jsx b/client/src/Components/SubjectNavbar.jsx index 42f3b04..c98b119 100644 --- a/client/src/Components/SubjectNavbar.jsx +++ b/client/src/Components/SubjectNavbar.jsx @@ -1,32 +1,92 @@ -/** @format */ - -import React from "react"; +import React, { useState } from "react"; import { Link } from "react-router-dom"; -export default function SubjectNavbar() { +export default function NavBar() { + const [isOpen, setIsOpen] = useState(false); + + const toggleMenu = () => { + setIsOpen((prev) => !prev); + }; + return ( -
- ); } diff --git a/client/src/Pages/AdminPage/Admin.jsx b/client/src/Pages/AdminPage/Admin.jsx index c9f0856..880d386 100644 --- a/client/src/Pages/AdminPage/Admin.jsx +++ b/client/src/Pages/AdminPage/Admin.jsx @@ -12,71 +12,89 @@ export default function Admin() { }; return ( -
-
-
-
- + +
    +
  1. + Application Layout - - -
      +
    1. -
    2. - Application Layout - - - -
    3. -
    4. - Dashboard -
    5. -
    -
+ Dashboard + +
+
+ +
+ ); } diff --git a/client/src/Pages/AdminRoutes.jsx b/client/src/Pages/AdminRoutes.jsx index 6bc82d9..eb11cca 100644 --- a/client/src/Pages/AdminRoutes.jsx +++ b/client/src/Pages/AdminRoutes.jsx @@ -50,11 +50,11 @@ export default function AdminRoute() {
); // Show a loading state while checking user role } else { - if ((user && user.role === "admin") || "student") { + if ((user && user.role === "admin") ) { return ; } else { return ( -
+
You are not authorized to access this page
diff --git a/client/src/alan.jsx b/client/src/alan.jsx index 0746109..7c8f443 100644 --- a/client/src/alan.jsx +++ b/client/src/alan.jsx @@ -1,49 +1,53 @@ -// alan-ai-setup.js import React, { useEffect } from 'react'; const AlanAIProjectKey = "b65ec1671e0e235364a5a62bdae65be32e956eca572e1d8b807a3e2338fdd0dc/stage"; function AlanAIComponent() { useEffect(() => { - // Load Alan AI script asynchronously when the component mounts on the client side - - //extended additional design to fix the overflow of chatwrapper by fixing to 90% of the parent - const additionalStyles = ` - .alanBtn-root { - right: 46px !important; - bottom: 150px !important; - } - #alan-text-chat-wrapper{ - height: 95%; - bottom: 0px; - position: fixed; - } - ` - ; - - const styleTag = document.createElement('style'); - styleTag.innerHTML = additionalStyles; - document.head.appendChild(styleTag); - - // Initialize Alan AI and handle commands once the script is loaded - /* global alanBtn */ - var alanBtnInstance = alanBtn({ - key: AlanAIProjectKey, - onCommand: function (commandData) { - if (commandData && commandData.command === 'openURL') { - if (commandData.target === '_blank') { - window.open(commandData.url, '_newtab' + Math.floor(Math.random() * 999999)); - } else { - window.location.href = commandData.url; + // Load Alan AI script dynamically + const script = document.createElement("script"); + script.src = "https://studio.alan.app/web/lib/alan_lib.min.js"; + script.async = true; + script.onload = () => { + // Ensure alanBtn is available + if (window.alanBtn) { + window.alanBtn({ + key: AlanAIProjectKey, + onCommand: (commandData) => { + if (commandData && commandData.command === 'openURL') { + if (commandData.target === '_blank') { + window.open(commandData.url, '_newtab' + Math.floor(Math.random() * 999999)); + } else { + window.location.href = commandData.url; + } } } - } - }); - + }); + } else { + console.error("Alan AI SDK failed to load."); + } + }; + document.body.appendChild(script); + + // Additional styles to fix chat wrapper overflow + const additionalStyles = ` + .alanBtn-root { + right: 46px !important; + bottom: 150px !important; + } + #alan-text-chat-wrapper { + height: 95%; + bottom: 0px; + position: fixed; + } + `; + const styleTag = document.createElement('style'); + styleTag.innerHTML = additionalStyles; + document.head.appendChild(styleTag); + }, []); - - return
; // This div will serve as the mount point for the Alan AI button + return
; // Mount point for Alan AI button } export default AlanAIComponent; diff --git a/server/.env.example b/server/.env.example index d288088..b85b94b 100644 --- a/server/.env.example +++ b/server/.env.example @@ -1,3 +1,3 @@ -TOKEN_KEY=yourSecretKey -MONGO_URL=mongodb://127.0.0.1:27017/ElectiveHub +TOKEN_KEY=electivehub +MONGO_URL="mongodb://127.0.0.1:27017/ElectiveHub" PORT=4000 \ No newline at end of file diff --git a/server/Controllers/AuthController.js b/server/Controllers/AuthController.js index eb81d20..05adc00 100644 --- a/server/Controllers/AuthController.js +++ b/server/Controllers/AuthController.js @@ -5,8 +5,12 @@ const bcrypt = require("bcryptjs"); module.exports.Signup = async (req, res, next) => { try { const { email, password, username, createdAt,role } = req.body; - - const existingUser = await User.findOne({ email }); + // console.log(req.body); + if(!email || !password || !username){ + return res.json({message:'All fields are required'}) + } + // const existingUser = await User.findOne({ email }); + console.log(existingUser); if (existingUser) { return res.json({ message: "User already exists" }); } diff --git a/server/app.js b/server/app.js index 1b62e60..e121137 100644 --- a/server/app.js +++ b/server/app.js @@ -13,14 +13,15 @@ const FeedbackRoute = require("./Routes/FeedbackRoutes"); require("dotenv").config(); const { MONGO_URL, PORT } = process.env; - +console.log(MONGO_URL); mongoose .connect(MONGO_URL, { useNewUrlParser: true, useUnifiedTopology: true, }) - .then(() => console.log("MongoDB is connected successfully")) + .then(() => console.log("MongoDB is connected successfully")) .catch((err) => console.error(err)); + const allowedOrigins = [ "http://127.0.0.1:5173", "http://localhost:5173", @@ -28,23 +29,25 @@ const allowedOrigins = [ "https://electivehub.onrender.com", // Add more URLs as needed ]; + app.use(cookieParser()); +// Set up CORS with allowed origins and credentials app.use( cors({ - origin: allowedOrigins, - + origin: function (origin, callback) { + // Allow requests with no origin (like mobile apps or curl requests) + if (!origin) return callback(null, true); + if (allowedOrigins.indexOf(origin) !== -1) { + callback(null, true); + } else { + callback(new Error("Not allowed by CORS")); + } + }, credentials: true, }) ); -// const corsOrigin ={ -// origin:'http://127.0.0.1:5173', //or whatever port your frontend is using -// credentials:true, -// optionSuccessStatus:200 -// } -// app.use(cors(corsOrigin)); - app.use(express.json()); app.use("/auth", authRoute); @@ -55,18 +58,19 @@ app.use( ); app.use("/student", authMiddleware(["admin", "user", "student"]), StudentRoute); app.use("/subject", authMiddleware(["admin", "user", "student"]), SubjectRoute); + app.get("/yaae", authMiddleware(["admin", "user", "student"]), (req, res) => { res.json({ status: true, user: req.user }); }); + app.use("/feedback", FeedbackRoute); app.post("/subscribe-newsletter", async (req, res) => { try { const { email } = req.body; const publicationId = "64f31498352b1c82180c69aa"; // Your publication ID - console.log(email); - console.log(publicationId); - // Make the API call to subscribe to the newsletter + console.log(email, publicationId); + const response = await axios.post( "https://electivehub.hashnode.dev/api/newsletter/subscribe", { @@ -75,7 +79,7 @@ app.post("/subscribe-newsletter", async (req, res) => { } ); console.log(response); - // Handle the response from the API call + if (response.status === 200) { res .status(200) @@ -84,14 +88,15 @@ app.post("/subscribe-newsletter", async (req, res) => { res.status(500).json({ error: "Error subscribing to the newsletter" }); } } catch (error) { - console.log(error); + console.error(error); res.status(500).json({ error: "Error subscribing to the newsletter" }); } }); -app.listen(PORT, () => { - console.log(`Server is listening on port ${PORT}`); -}); app.get("/", (req, res) => { res.send("dsjdnjsd"); }); + +app.listen(PORT, () => { + console.log(`Server is listening on port ${PORT}`); +});