diff --git a/Frontend/src/App.tsx b/Frontend/src/App.tsx index 233de5e..02d41ca 100644 --- a/Frontend/src/App.tsx +++ b/Frontend/src/App.tsx @@ -1,13 +1,11 @@ -import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"; -import { useEffect, useState } from "react"; // Import useEffect +// App.tsx +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import { useEffect, useState } from "react"; import { useDisclosure } from "@chakra-ui/react"; -import { GoogleLogin } from "@react-oauth/google"; -import jwt_decode from "jwt-decode"; import axios from "axios"; import StudentHome from "./Pages/StudentHome"; import Admin from "./Pages/Admin/Admin"; -import AdminWrapper from "./Pages/Admin/AdminWrapper"; import AdminHome1 from "./Pages/Admin/AdminHome1"; import AdminHome2 from "./Pages/Admin/AdminHome2"; import AdminHome3 from "./Pages/Admin/AdminHome3"; @@ -18,29 +16,36 @@ import LoginModal from "./components/LoginModal"; import { DUserTokenInterface } from "./models/TokenMoodel"; import { PreviousRequest } from "./models/PreviousRequest"; -// import Yes from "./Pages/Yes"; function App() { const { isOpen, onOpen, onClose } = useDisclosure(); const [userToken, setUserToken] = useState(null); - const [previousRequest, setPreviousRequest] = useState(null); + const [previousRequest, setPreviousRequest] = + useState(null); + const [error, setError] = useState(null); useEffect(() => { + const fetchPreviousRequest = async () => { + try { + const response = await axios.get( + `http://localhost:5000/findrequest/${userToken?.email}` + ); + setPreviousRequest(response.data); + } catch (error) { + setError("Error fetching previous request data"); + console.error(error); + } + }; + if (userToken == null) { onOpen(); } else { onClose(); console.log("Closed the modal"); - axios - .get(`http://localhost:5000/findrequest/${userToken.email}`) - .then((response) => { - setPreviousRequest(response.data); - console.log(response.data); - }); + fetchPreviousRequest(); } }, [userToken, onOpen, onClose]); - return ( @@ -48,55 +53,12 @@ function App() { index element={ <> - {/* - - - - ACES Project Fund Requests - - - - You need to login with your eng email - - { - console.log(credentialResponse); - - var decodedUserToken: DUserTokenInterface = jwt_decode( - credentialResponse.credential! - ); - - setUserToken(decodedUserToken); - - console.log(decodedUserToken); - - onClose(); - }} - onError={() => { - onOpen(); - console.log("Login Failed"); - }} - /> - - - */} + setUserToken={setUserToken} + /> + {error &&

{error}

} } /> - {/* } /> */} - } /> + + } + /> } /> - } /> + } />{" "} + {/* Use :id for dynamic parameter */} } /> } /> } /> @@ -116,6 +86,6 @@ function App() {
); -} +} -export default App \ No newline at end of file +export default App; diff --git a/Frontend/src/Pages/Admin/Admin.tsx b/Frontend/src/Pages/Admin/Admin.tsx index 959007c..eb0abcc 100644 --- a/Frontend/src/Pages/Admin/Admin.tsx +++ b/Frontend/src/Pages/Admin/Admin.tsx @@ -1,26 +1,16 @@ -import React, { useState, useEffect } from "react"; -import { BrowserRouter, Routes, Route } from "react-router-dom"; +// Admin.tsx +import { useEffect, useState } from "react"; import { Box, - Container, Divider, Grid, - GridItem, - Modal, - ModalBody, - ModalContent, - ModalHeader, - ModalOverlay, - Skeleton, - SkeletonCircle, SkeletonText, Stack, Text, + Button, useDisclosure, } from "@chakra-ui/react"; -import jwt_decode from "jwt-decode"; - import Header from "../../components/Header"; import FooterSection from "../../components/FooterSection"; import CardComponent from "../CardComponent"; @@ -28,124 +18,52 @@ import cardImage from "../../assets/images/cardImage.webp"; import axios from "axios"; import { PreviousRequest } from "../../models/PreviousRequest"; import { DUserTokenInterface } from "../../models/TokenMoodel"; -import { CredentialResponse, GoogleLogin } from "@react-oauth/google"; import LoginModal from "../../components/LoginModal"; - -// interface AdminProps { -// userToken: DUserTokenInterface; -// } - - -// interface RequestData { -// Project_title: string; -// Project_description: string; -// starting_date: string; -// hod_response: boolean; -// // Add other properties as needed -// } +import { useNavigate } from "react-router-dom"; const Admin = () => { const [allRequests, setAllRequests] = useState([]); const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); const { isOpen, onOpen, onClose } = useDisclosure(); const [userToken, setUserToken] = useState(null); - - // const [latestRequests, setLatestRequests] = useState([]); - // const [previousRequests, setPreviousRequests] = useState([]); + const navigate = useNavigate(); useEffect(() => { + const fetchAllRequests = async () => { + try { + setIsLoading(true); + const response = await axios.get("http://localhost:5000/getall"); + setAllRequests(response.data.docs); + } catch (error) { + setError("Error fetching requests"); + console.error(error); + } finally { + setIsLoading(false); + } + }; + if (userToken == null) { onOpen(); } else { onClose(); console.log("Closed the modal"); - - setIsLoading(true); - axios - .get("http://localhost:5000/getall") - .then((response) => { - console.log(response.data.docs[0]); - - setAllRequests(response.data.docs); - setIsLoading(false); - }) - .catch((error) => { - console.error("Error fetching requests:", error); - setIsLoading(false); - }); + fetchAllRequests(); } - }, [userToken]); - - // useEffect(() => { - // // Fetch the requests from your backend API - // setIsLoading(true); - // console.log("Start sending"); - - // // axios - // // .get("http://localhost:5000/getall") - // // .then((response) => { - // // console.log(response.data.docs[0]); + }, [userToken, onOpen, onClose]); - // // setAllReusts(response.data.docs); - // // setIsLoading(false); - // // }) - // // .catch((error) => { - // // console.error("Error fetching requests:", error); - // // setIsLoading(false); - // // }); - // }, []); + const handleViewMore = (id: string) => { + navigate(`/admin1/${id}`); // Corrected route path to use `/admin1/:id` + }; return ( <> - {/* - - - - ACES Project Fund Requests - - - - You need to login with your eng email - - { - console.log(credentialResponse); - - var decodedUserToken: DUserTokenInterface = jwt_decode( - credentialResponse.credential! - ); - - setUserToken(decodedUserToken); - - console.log(decodedUserToken); - - onClose(); - }} - onError={() => { - onOpen(); - console.log("Login Failed"); - }} - /> - - - */} + setUserToken={setUserToken} + />
@@ -176,63 +94,6 @@ const Admin = () => { - {/* - {latestRequests.map((request, index) => ( - - - - ))} - */} - - {/* - - {isLoading ? ( - - - - - ) : ( - allRequests.map((eachRequest) => { - return ( - - ); - }) - )} */} { + ) : error ? ( + {error} ) : ( - allRequests.map((eachRequest) => { - return ( + allRequests.map((eachRequest) => ( + - ); - }) + + + )) )} - - {/* */} - {/* */} - {/* - - */} - {/* */} - - {/* - - Older Requests - - - - - - - - - - - - - - - */} - - {/* {previousRequests.map((request, index) => ( - - - - ))} */}
diff --git a/Frontend/src/Pages/Admin/AdminHome1.tsx b/Frontend/src/Pages/Admin/AdminHome1.tsx index b6351c5..b1b56fb 100644 --- a/Frontend/src/Pages/Admin/AdminHome1.tsx +++ b/Frontend/src/Pages/Admin/AdminHome1.tsx @@ -1,69 +1,62 @@ -import FooterSection from "../../components/FooterSection"; +// AdminHome1.tsx +import { useEffect, useState } from "react"; +import { useParams, Link } from "react-router-dom"; +import axios from "axios"; +import { Text, Grid, GridItem, Box } from "@chakra-ui/react"; import Header from "../../components/Header"; -//import NextButton from "../components/NextButton"; +import FooterSection from "../../components/FooterSection"; import NextButtonAdmin from "../NextButtonAdmin"; -//import { SetStateAction, useState } from "react"; -import { useParams } from "react-router-dom"; -import React, { useEffect, useState } from "react"; -import axios from "axios"; -import { - Text, - Grid, - GridItem, - Link, - //Button, - // Textarea, - Box, - //Stack, -} from "@chakra-ui/react"; - -// const inputBorderColor = "#97bfd4"; -const gridBackgrougndColor = "#F5F5F5"; -// const inputFieldTextColor = "black"; +const gridBackgroundColor = "#F5F5F5"; const labelColor = "black"; const AdminHome1 = () => { - // const [currentStep, setCurrentStep] = useState(1); - // const handleStepperChange = (step: SetStateAction) => { - // setCurrentStep(step); - // }; - - const [data, setData] = useState(null); - const { id } = useParams(); // Dynamically obtain the 'id' from the URL + const { id } = useParams<{ id: string }>(); // Dynamically obtain the 'id' from the URL + const [data, setData] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); useEffect(() => { - // Make an HTTP GET request to fetch data from the backend - axios - .get(`/find/${id}`) - .then((response) => { + const fetchData = async () => { + if (!id) return; // Make sure ID exists before fetching + setIsLoading(true); + try { + const response = await axios.get(`http://localhost:5000/find/${id}`); setData(response.data); - }) - .catch((error) => { + } catch (error) { + setError("Error fetching data"); console.error("Error fetching data:", error); - }); + } finally { + setIsLoading(false); + } + }; + + fetchData(); }, [id]); + if (isLoading) { + return Loading...; + } + + if (error) { + return {error}; + } + + if (!data) { + return No data found for ID: {id}; + } + return ( <> -
- - +
+ - Automated Inventory Management System Upgrade + {data.project_title} @@ -73,11 +66,7 @@ const AdminHome1 = () => { { - Hobby - {/* - CO325 - */} + {data.project_type} @@ -111,11 +97,7 @@ const AdminHome1 = () => { { - - The project aims to upgrade the existing manual inventory - management system of a small retail business to an automated - system. This upgrade is crucial for improving efficiency, - accuracy, and overall management of inventory, which will lead - to reduced operational costs and increased customer - satisfaction. - + {data.project_description} @@ -153,11 +128,7 @@ const AdminHome1 = () => { { - - Efficiency Improvement: The primary goal is to increase - operational efficiency. This will be achieved through the - implementation of an automated system that reduces the time and - effort required for inventory management. Data entry, tracking, - and restocking processes will be streamlined. Accuracy - - - Enhancement: The new system will reduce human errors in data - entry, leading to more accurate inventory counts. Barcode - scanning and RFID technology will be used for real-time - tracking, ensuring inventory accuracy. - + {data.goals} @@ -200,11 +159,7 @@ const AdminHome1 = () => { { - - Data Loss or Corruption: To mitigate the risk of data loss or - corruption during the migration process, regular backups will be - maintained, and a robust data migration plan will be - established. - - - - Staff Resistance: Some employees may resist the change from - manual to automated systems. To address this, a change - management plan will be developed, including training, - incentives, and communication. - + {data.risks} @@ -247,11 +190,7 @@ const AdminHome1 = () => { { - 2023-10-19 + {data.starting_date} @@ -282,11 +221,7 @@ const AdminHome1 = () => { { - 2023-10-26 + {data.ending_date} {/* Budget Report */} - - - Budegt Report + + Budget Report - - Budget repot.pdf + + Download Budget Report - {/* Don't know how to add the report and make it downloadable. */} - + */} {/* Next Button */} - + { + // Handle stepper change if needed }} /> - - {/* - - */} + diff --git a/Frontend/src/Pages/CardComponent.tsx b/Frontend/src/Pages/CardComponent.tsx index 28a57ca..7d0c17d 100644 --- a/Frontend/src/Pages/CardComponent.tsx +++ b/Frontend/src/Pages/CardComponent.tsx @@ -9,9 +9,6 @@ import { Heading, Text, } from "@chakra-ui/react"; -//import ViewMoreButton from "./ViewMoreButton"; -// import { Link } from "react-router-dom"; -//import cardImage from "../assets/images/cardImage.webp" interface CardComponentProps { cardImage: string; diff --git a/Frontend/src/components/LoginModal.tsx b/Frontend/src/components/LoginModal.tsx index 4eaf399..b6f06b7 100644 --- a/Frontend/src/components/LoginModal.tsx +++ b/Frontend/src/components/LoginModal.tsx @@ -1,5 +1,12 @@ import React, { useState } from "react"; -import { Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, Text, Button } from "@chakra-ui/react"; +import { + Modal, + ModalOverlay, + ModalContent, + ModalHeader, + ModalBody, + Text, +} from "@chakra-ui/react"; import { GoogleLogin, CredentialResponse } from "@react-oauth/google"; import jwt_decode from "jwt-decode"; import { DUserTokenInterface } from "../models/TokenMoodel"; @@ -11,18 +18,42 @@ interface LoginModalProps { setUserToken: (token: DUserTokenInterface | null) => void; } -const LoginModal: React.FC = ({ isOpen, onClose, setUserToken }) => { +const LoginModal: React.FC = ({ + isOpen, + onClose, + setUserToken, +}) => { const [errorMessage, setErrorMessage] = useState(null); const navigate = useNavigate(); const handleLoginSuccess = (credentialResponse: CredentialResponse) => { - const decodedUserToken: DUserTokenInterface = jwt_decode(credentialResponse.credential!); + const decodedUserToken: DUserTokenInterface = jwt_decode( + credentialResponse.credential! + ); const email = decodedUserToken.email.toLowerCase(); // Ensure email is lowercase for consistent comparison - + // Check if the email is an admin email or e19304@eng.pdn.ac.lk + if ( + email === "asithab@eng.pdn.ac.lk" || + email === "roshanr@eng.pdn.ac.lk" || + email === "e19111@eng.pdn.ac.lk" + ) { + setUserToken(decodedUserToken); + onClose(); + navigate("/admin"); + return; + } // Check if the email is within the accepted range for students - if (email.match(/^e19\d{3}@eng\.pdn\.ac\.lk$/) || email.match(/^e20\d{3}@eng\.pdn\.ac\.lk$/)) { + if ( + email.match(/^e19\d{3}@eng\.pdn\.ac\.lk$/) || + email.match(/^e20\d{3}@eng\.pdn\.ac\.lk$/) + ) { const numberPart = parseInt(email.substring(1, 6), 10); // Extract and convert the numeric part - if ((numberPart >= 19001 && numberPart <= 19303 || numberPart >= 19305 && numberPart <= 19505) || (numberPart >= 20001 && numberPart <= 20505)) { // Adjusted range for students + if ( + (numberPart >= 19001 && numberPart <= 19110) || + (numberPart >= 19112 && numberPart <= 19505) || + (numberPart >= 20001 && numberPart <= 20505) + ) { + // Adjusted range for students setUserToken(decodedUserToken); onClose(); navigate("/"); @@ -30,29 +61,38 @@ const LoginModal: React.FC = ({ isOpen, onClose, setUserToken } } } - // Check if the email is an admin email or e19304@eng.pdn.ac.lk - if (email === "asithab@eng.pdn.ac.lk" || - email === "roshanr@eng.pdn.ac.lk" || - email === "e19304@eng.pdn.ac.lk") { - setUserToken(decodedUserToken); - onClose(); - navigate("/admin"); - return; - } - // If neither student nor admin email, show error setErrorMessage("You must use a valid @eng.pdn.ac.lk email to login."); }; return ( - + - + ACES Project Fund Requests - - You need to login with your eng email + + + You need to login with your eng email + { diff --git a/backend/app.js b/backend/app.js index 6e70036..7d7dca3 100644 --- a/backend/app.js +++ b/backend/app.js @@ -4,13 +4,13 @@ const axios = require("axios"); const multer = require("multer"); const fs = require("fs"); const app = express(); -const dialogflowRoute = require('./routes/dialogflow'); +const dialogflowRoute = require("./routes/dialogflow"); const mongoose = require("mongoose"); -const dotenv = require('dotenv'); -const path = require('path'); +const dotenv = require("dotenv"); +const path = require("path"); // Load environment variables from a file located outside the backend folder -dotenv.config({ path: path.resolve(__dirname, '../.env') }); +dotenv.config({ path: path.resolve(__dirname, "../.env") }); const bodyParser = require("body-parser"); const emailService = require("./Services/emailService"); @@ -28,11 +28,11 @@ app.use(cors({ // Increase the request size limit to 50MB (or set it to your desired limit) app.use(bodyParser.json({ limit: "50mb" })); app.use(bodyParser.urlencoded({ limit: "50mb", extended: true })); -app.use('/api', dialogflowRoute); +app.use("/api", dialogflowRoute); // Set up mongoose connection mongoose.set("strictQuery", false); -const mongoDB = "mongodb+srv://root:Jeeve123@cluster0.zrs0mqb.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0"; +const mongoDB = process.env.MONGO_URI; main().catch((err) => console.log(err)); async function main() { diff --git a/package-lock.json b/package-lock.json index 26a231b..349ee26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "e19-co328-ACES-Project-Fund-Requests", + "name": "e19-CO328-ACES-Project-Fund-Requests", "lockfileVersion": 3, "requires": true, "packages": {