diff --git a/.gitignore b/.gitignore index 3fa64d3..928fbec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules .idea .vs +.env \ No newline at end of file diff --git a/client/.gitignore b/client/.gitignore index 4d29575..8692cf6 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -13,6 +13,7 @@ # misc .DS_Store +.env .env.local .env.development.local .env.test.local diff --git a/client/package-lock.json b/client/package-lock.json index f34dfda..1dcfae8 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -7185,14 +7185,6 @@ "tslib": "^2.0.3" } }, - "node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "engines": { - "node": ">=10" - } - }, "node_modules/dotenv-expand": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", @@ -15116,6 +15108,14 @@ } } }, + "node_modules/react-scripts/node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "engines": { + "node": ">=10" + } + }, "node_modules/react-toastify": { "version": "10.0.5", "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz", @@ -23404,11 +23404,6 @@ "tslib": "^2.0.3" } }, - "dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" - }, "dotenv-expand": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", @@ -28929,6 +28924,13 @@ "webpack-dev-server": "^4.6.0", "webpack-manifest-plugin": "^4.0.2", "workbox-webpack-plugin": "^6.4.1" + }, + "dependencies": { + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + } } }, "react-toastify": { diff --git a/client/src/AdminHome.js b/client/src/AdminHome.js index 8f2d28a..3381708 100644 --- a/client/src/AdminHome.js +++ b/client/src/AdminHome.js @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import axios from 'axios'; import './AdminHome.css'; import { useAuth } from './AuthContext'; +import { BASE_URL } from './App'; const AdminHome = () => { const [announcementText, setAnnouncementText] = useState(''); @@ -14,7 +15,7 @@ const AdminHome = () => { const fetchAnnouncements = async () => { try { - const response = await axios.get('http://localhost:5000/announcements'); + const response = await axios.get(`${BASE_URL}/announcements`); setAnnouncements(response.data); } catch (error) { console.error('Error fetching announcements:', error); @@ -24,7 +25,7 @@ const AdminHome = () => { const handleAnnouncementSubmit = async () => { try { - await axios.post('http://localhost:5000/announcement', { message: announcementText }); + await axios.post(`${BASE_URL}/announcement`, { message: announcementText }); setAnnouncementText(''); fetchAnnouncements(); } catch (error) { @@ -35,7 +36,7 @@ const AdminHome = () => { const handleDeleteAnnouncement = async (id) => { if (window.confirm('Are you sure you want to delete this announcement?')) { try { - const response = await axios.delete(`http://localhost:5000/announcement/${id}`); + const response = await axios.delete(`${BASE_URL}/announcement/${id}`); if (response.status === 200) { alert('Announcement deleted successfully'); // Refresh the announcements list @@ -55,7 +56,7 @@ const AdminHome = () => { const handleReset = async () => { if (window.confirm('Are you sure you want to reset the semester? This action cannot be undone.')) { try { - await axios.post('http://localhost:5000/admin/reset'); + await axios.post(`${BASE_URL}/admin/reset`); alert('Reset successful'); fetchAnnouncements(); } catch (error) { diff --git a/client/src/App.js b/client/src/App.js index b98e7e7..fc714e5 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -10,11 +10,14 @@ import Search from './Search'; import Register from './Register'; import Schedule from './Schedule'; import ScheduleW from './ScheduleW'; +import Emails from './Emails'; import { NavLink, useNavigate } from 'react-router-dom'; import './Navbar.css'; import { AuthProvider, useAuth } from './AuthContext'; // Adjust the path if necessary import bannerImage from './images/banner.jpg'; +export const BASE_URL = process.env.REACT_APP_BASE_URL; + function Navigation() { const { isAuthenticated, isAdmin, logout } = useAuth(); const [showLogoutConfirm, setShowLogoutConfirm] = useState(false); @@ -77,8 +80,9 @@ function Navigation() { {!isAdmin && Profile} {!isAdmin && Form} {isAdmin && Search} + {isAdmin && Emails} {isAdmin && PRP} - {isAdmin && Waived} + {isAdmin && Waived} @@ -110,6 +114,7 @@ function App() { } /> } /> } /> + } /> diff --git a/client/src/AuthContext.js b/client/src/AuthContext.js index 80e1932..3fe1386 100644 --- a/client/src/AuthContext.js +++ b/client/src/AuthContext.js @@ -1,5 +1,6 @@ import React, { useState, createContext, useContext, useEffect } from 'react'; import axios from 'axios'; +import { BASE_URL } from './App'; const AuthContext = createContext(); @@ -20,7 +21,7 @@ export const AuthProvider = ({ children }) => { try { - const response = await axios.get('http://localhost:5000/userData', { params: { userId: loggedInUserId } }); + const response = await axios.get(`${BASE_URL}/userData`, { params: { userId: loggedInUserId } }); if (response.data.waive === 'admin') setIsAdmin(true); // Set admin flag to true else setIsAdmin(false); // Set admin flag to false setUser(response.data); diff --git a/client/src/Emails.css b/client/src/Emails.css new file mode 100644 index 0000000..4410a65 --- /dev/null +++ b/client/src/Emails.css @@ -0,0 +1,89 @@ +.emails-container { + max-width: 800px; + margin: 40px auto; + padding: 20px; + background: #fff; + border-radius: 8px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + } + + + /* Filter container styling */ + .filter-container { + display: flex; + align-items: center; + margin-top: 20px; + margin-bottom: 20px; + margin-left: 20px; + margin-right: 20px; + padding: 10px; + background: #f8f9fa; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); + } + + /* Label styling */ + .filter-container label { + font-weight: bold; + margin-right: 10px; + font-size: 1.1em; + color: #007bff; + + } + + /* Select dropdown styling */ + .filter-container select { + flex: 1; + padding: 8px; + border-radius: 4px; + border: 1px solid #ccc; + font-size: 1em; + background: #ffffff; + transition: border-color 0.3s ease; + } + + .filter-container select:hover { + border-color: #007bff; + } + + /* Table styling */ + table { + width: 100%; + margin-top: 20px; + border-collapse: collapse; + background: #ffffff; + border-radius: 8px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + margin-left: 20px; + margin-right: 20px !important; + } + + table thead { + background-color: #f5f5f5; + } + + table th, table td { + padding: 12px 15px; + text-align: left; + border: 1px solid #ddd; + font-size: 1em; + } + + table th { + font-weight: bold; + color: #555; + } + + table tbody tr:nth-child(even) { + background-color: #f9f9f9; + } + + table tbody tr:hover { + background-color: #f0f0f0; + color: #333; + } + +/* Logout button styling */ +.logout-button:hover { + background-color: #0056b3; +} diff --git a/client/src/Emails.js b/client/src/Emails.js new file mode 100644 index 0000000..ae29e8d --- /dev/null +++ b/client/src/Emails.js @@ -0,0 +1,88 @@ +import './Emails.css'; +import React, { useState, useEffect } from 'react'; +import axios from 'axios'; +import { BASE_URL } from './App'; + +function Emails() { + const [users, setUsers] = useState([]); + const [filter, setFilter] = useState("All"); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + + useEffect(() => { + //getting all user data + const fetchUsers = async () => { + try { + setLoading(true); + const response = await axios.get(`${BASE_URL}/users`, { + params: { + waive: ["yes", "no"], + } + }); console.log('Fetched users:', response.data); + setUsers(response.data); + } catch (error) { + console.error('Error fetching users:', error); + setError('Error fetching users'); + } finally { + setLoading(false); + } + }; + + fetchUsers(); + }, []); + + + // returns correct output based on filter selection + const filteredUsers = Array.isArray(users) ? users.filter(user => { + if (filter === "All") return true; + + if (filter === "Registered") return user.waive === "no"; + if (filter === "Waived") return user.waive === "yes"; + if (filter === "Uploaded document") return typeof user.pdfFileUrl === "string" && user.pdfFileUrl.length > 0; + if (filter === "Did not upload document") return !user.pdfFileUrl || user.pdfFileUrl.length === 0; + + return false; + }) : []; + + if (loading) return

Loading...

; + if (error) return

{error}

; + + return ( +
+
+ + +
+ + + + + + + + + + {filteredUsers.map((user, index) => ( + + + + + ))} + +
NameEmail
{user.formData?.name || user.username}{user.email}
+
+ ); +} + +export default Emails; \ No newline at end of file diff --git a/client/src/Form.js b/client/src/Form.js index bc23fb5..a25e9ee 100644 --- a/client/src/Form.js +++ b/client/src/Form.js @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import axios from 'axios'; import { useAuth } from './AuthContext'; import './Form.css'; +import { BASE_URL } from './App'; function Form() { const { user, updateFormData, updateWaiveOption } = useAuth(); @@ -50,13 +51,15 @@ function Form() { const handleFormSubmit = async (event) => { event.preventDefault(); try { - await axios.post('http://localhost:5000/saveFormData', { userId: user.id, formData }); //Post to Database + console.log(user.id) + await axios.post(`${BASE_URL}/saveFormData`, { userId: user.id, formData }); //Post to Database updateFormData(formData); //Update user context of formData setIsReadOnly(true); // Make fields read-only after saving - await axios.post('http://localhost:5000/saveWaiveOption', { userId: user.id, waive: waiverOption === 'waiver' ? 'yes' : 'no' }); // Post to Database + await axios.post(`${BASE_URL}`, { userId: user.id, waive: waiverOption === 'waiver' ? 'yes' : 'no' }); // Post to Database updateWaiveOption(waiverOption === 'waiver' ? 'yes' : 'no' ); //Update user context of waiveOption console.log('Form data saved successfully'); } catch (error) { + console.log(error.toJSON()) console.error('Error saving form data', error); } }; diff --git a/client/src/Home.css b/client/src/Home.css index fabf123..5a9c8f0 100644 --- a/client/src/Home.css +++ b/client/src/Home.css @@ -1,13 +1,27 @@ /* Home.css */ .home-container { display: flex; - justify-content: space-around; + flex-direction: row; + width: 100%; + box-sizing: border-box; + border-style: dashed; + align-items: flex-start; /* Aligns containers at the top */ +} + +.left-container { + flex: 1; /* Distributes space evenly */ padding: 20px; - max-width: 1200px; - margin: auto; + box-sizing: border-box; + border-style: solid; } -.notifications-container, +.right-container { + flex: 1; /* Distributes space evenly */ + padding: 20px; + box-sizing: border-box; + border-style: dotted; +} +.notifications-container, .calendar-container { flex: 1; margin: 10px; @@ -37,3 +51,8 @@ border: none; /* Ensure no border around the iframe */ } +.go-to-form-button { + width:20%; + margin: 0 auto; +} + diff --git a/client/src/Home.js b/client/src/Home.js index c613e7b..149a847 100644 --- a/client/src/Home.js +++ b/client/src/Home.js @@ -1,17 +1,53 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, } from 'react'; import axios from 'axios'; import './Home.css'; // Ensure your CSS file is imported +import { BASE_URL } from './App'; +import { useNavigate } from 'react-router-dom'; +import { user } from './AuthContext'; const Home = () => { const [announcements, setAnnouncements] = useState([]); + const [user, setUser] = useState({ + name: '', + id: '', + titleOfPRPTopic: '', + researchAdvisor: '', + prpSubmitted: '', + nameOfJournal: '', + paperAccepted: '', + reviewsAvailable: '', + listenWaiver: '' + }); + const [pdf, setPdf] = useState(''); useEffect(() => { + fetchUserData(); fetchAnnouncements(); + fetchPdf(); + }, []); + useEffect(() => { + const isFormDataValid = validateFormData(); + setIsTask1Checked(isFormDataValid); + console.log("Check if data is stored: ", user); + console.log("Form data validation result: ", isFormDataValid); + }, [user]); + + // fetches formData + const fetchUserData = async () => { + try { + const response = await axios.get(`${BASE_URL}/userData`, {params: { userId: localStorage.getItem("id") }}); + setUser(response.data.formData); + } catch (error) { + console.error('Error fetching user data:', error); + // Handle error + } + }; + const fetchAnnouncements = async () => { try { - const response = await axios.get('http://localhost:5000/announcements'); + const response = await axios.get(`${BASE_URL}/announcements`); setAnnouncements(response.data); } catch (error) { console.error('Error fetching announcements:', error); @@ -19,29 +55,113 @@ const Home = () => { } }; + const fetchPdf = async () => { + try { + const response = await axios.get(`${BASE_URL}/userData`, {params: { userId: localStorage.getItem("id") }}); + setPdf(response.data.pdfFileUrl); + } catch (error) { + console.error('Error fetching pdf:', error); + // Handle error + } + }; + + const GoToFormButton = () => { + const navigate = useNavigate(); + + const navigateToForm = () => { + navigate('/form'); // Navigates to /form page + }; + + return ( + + ); + }; + + // validating if formData is null + const validateFormData = () => { + return ( + user.name && user.id && user.titleOfPRPTopic && user.researchAdvisor && + user.prpSubmitted && + user.paperAccepted && user.reviewsAvailable + ); + }; + + const validatePdfUrl = () => { + return pdf.length > 0; + } + + const isPdfValid = validatePdfUrl(); + const isFormDataValid = validateFormData(); + + console.log("check if pdf stored: " + isPdfValid); + console.log("check if data stored: " + isFormDataValid); + + const [isTask1Checked, setIsTask1Checked] = useState(isFormDataValid); + const [isTask2Checked, setIsTask2Checked] = useState(isPdfValid); + + + useEffect(() => { + setIsTask1Checked(isFormDataValid); + setIsTask2Checked(isPdfValid); + }, [isFormDataValid, isPdfValid]); + + // Toggle checkbox manually if user interacts + const handleCheckbox1Click = () => { + setIsTask1Checked((prev) => !prev); + }; + const handleCheckbox2Click = () => { + setIsTask2Checked((prev) => !prev); + }; + + return (
-
-

Notifications/Announcements

+
+
+

Home Page

+

You have not signed up to register or waive the exam.

+
    + {announcements.map((announcement) => ( +
  • {announcement.message}
  • + ))} +
+ +

Complete by [].

+
+
+ +
+

To Do:

    - {announcements.map((announcement) => ( -
  • {announcement.message}
  • - ))} +
  • + + +
  • +
  • + + +
  • +
  • + + +
-
- -
); + }; -export default Home; +export default Home; \ No newline at end of file diff --git a/client/src/Profile.js b/client/src/Profile.js index dfa8b25..b7b34a2 100644 --- a/client/src/Profile.js +++ b/client/src/Profile.js @@ -4,6 +4,7 @@ import './Profile.css'; import axios from 'axios'; import { ToastContainer, toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; +import { BASE_URL } from './App'; const Profile = () => { const [selectedFile, setSelectedFile] = useState(null); @@ -15,12 +16,12 @@ const Profile = () => { const handleFileUpload = () => { if (!selectedFile) return; - + const formData = new FormData(); formData.append('pdfFile', selectedFile); formData.append('userId', user.id); // Adjust according to where user id is stored - - axios.post('http://localhost:5000/uploadPdf', formData, { + + axios.post(`${BASE_URL}/uploadPdf`, formData, { headers: { 'Content-Type': 'multipart/form-data' } @@ -30,10 +31,43 @@ const Profile = () => { toast.success('File uploaded successfully!'); }) .catch(error => { - console.error('Upload error:', error); - toast.error('Upload error: ' + error.response.data); + if (error.response) { + // Server responded with a status other than 200 range + console.error('Upload error:', error.response.data); + toast.error(`Upload error: ${error.response.data.message || 'Unknown error'}`); + } else if (error.request) { + // No response was received from the server + console.error('No response received:', error.request); + toast.error('Upload error: No response received from the server'); + } else { + // Error setting up the request + console.error('Error setting up upload request:', error.message); + toast.error('Upload error: ' + error.message); + } }); }; + + // const handleFileUpload = () => { + // if (!selectedFile) return; + + // const formData = new FormData(); + // formData.append('pdfFile', selectedFile); + // formData.append('userId', user.id); // Adjust according to where user id is stored + + // axios.post(`${BASE_URL}/uploadPdf`, formData, { + // headers: { + // 'Content-Type': 'multipart/form-data' + // } + // }) + // .then(response => { + // console.log('File uploaded successfully:', response.data); + // toast.success('File uploaded successfully!'); + // }) + // .catch(error => { + // console.error('Upload error:', error); + // toast.error('Upload error: ' + error.response.data); + // }); + // }; if (!user) { return
Please log in to view this page.
; diff --git a/client/src/Register.js b/client/src/Register.js index 0dcfcc5..a1e1294 100644 --- a/client/src/Register.js +++ b/client/src/Register.js @@ -2,6 +2,7 @@ import React, { useState } from 'react'; import axios from 'axios'; import { useNavigate } from 'react-router-dom'; import './Register.css'; // Import the CSS here +import { BASE_URL } from './App'; function Register() { const [username, setUsername] = useState(''); @@ -27,7 +28,7 @@ function Register() { }; try { - const response = await axios.post('http://localhost:5000/register', userData); + const response = await axios.post(`${BASE_URL}/register`, userData); console.log('User registered:', response.data); navigate('/'); } catch (error) { diff --git a/client/src/Schedule.js b/client/src/Schedule.js index 46f85ce..e8d761c 100644 --- a/client/src/Schedule.js +++ b/client/src/Schedule.js @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import axios from 'axios'; import './Schedule.css'; import ScheduleTable from './ScheduleTable'; +import { BASE_URL } from './App'; function Schedule() { const [users, setUsers] = useState([]); @@ -19,7 +20,7 @@ function Schedule() { useEffect(() => { const fetchUsers = async () => { try { - const response = await axios.get('http://localhost:5000/users?waive=no'); + const response = await axios.get(`${BASE_URL}/users?waive=no`); setUsers(response.data); } catch (error) { console.error('Error fetching users:', error); @@ -53,10 +54,10 @@ function Schedule() { const handleInfoSubmit = async () => { try { - await axios.post('http://localhost:5000/saveSchedulingData', { selectedUserId, schedulingData }); + await axios.post(`${BASE_URL}/saveSchedulingData`, { selectedUserId, schedulingData }); setIsReadOnly(true); // Fetch updated data - const updatedUsers = await axios.get('http://localhost:5000/users?waive=no'); + const updatedUsers = await axios.get(`${BASE_URL}/users?waive=no`); setUsers(updatedUsers.data); console.log('Scheduling data saved successfully'); } catch (error) { diff --git a/client/src/ScheduleTable.js b/client/src/ScheduleTable.js index c4a7580..78ecd9c 100644 --- a/client/src/ScheduleTable.js +++ b/client/src/ScheduleTable.js @@ -1,6 +1,7 @@ import React from 'react'; import { useNavigate } from 'react-router-dom'; // Import useNavigate import './ScheduleTable.css'; +import { BASE_URL } from './App'; function ScheduleTable({ users }) { const navigate = useNavigate(); @@ -27,7 +28,7 @@ function ScheduleTable({ users }) { {[user.schedulingData.date," ", user.schedulingData.time]} {user.formData.name} {user.pdfFileUrl ? ( - + {user.formData.titleOfPRPTopic} ) : ( diff --git a/client/src/ScheduleW.js b/client/src/ScheduleW.js index 6866707..d8b7412 100644 --- a/client/src/ScheduleW.js +++ b/client/src/ScheduleW.js @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import axios from 'axios'; import './Schedule.css'; import ScheduleWTable from './ScheduleWTable'; +import { BASE_URL } from './App'; function ScheduleW() { const [users, setUsers] = useState([]); @@ -19,7 +20,7 @@ function ScheduleW() { useEffect(() => { const fetchUsers = async () => { try { - const response = await axios.get('http://localhost:5000/users?waive=yes'); + const response = await axios.get(`${BASE_URL}/users?waive=yes`); setUsers(response.data); } catch (error) { console.error('Error fetching users:', error); @@ -61,10 +62,10 @@ function ScheduleW() { const handleInfoSubmit = async () => { try { - await axios.post('http://localhost:5000/saveSchedulingData', { selectedUserId, schedulingData }); + await axios.post(`${BASE_URL}/saveSchedulingData`, { selectedUserId, schedulingData }); setIsReadOnly(true); // Fetch updated data - const updatedUsers = await axios.get('http://localhost:5000/users?waive=yes'); + const updatedUsers = await axios.get(`${BASE_URL}/users?waive=yes`); setUsers(updatedUsers.data); console.log('Scheduling data saved successfully'); } catch (error) { diff --git a/client/src/ScheduleWTable.js b/client/src/ScheduleWTable.js index 407cfa4..9c1798a 100644 --- a/client/src/ScheduleWTable.js +++ b/client/src/ScheduleWTable.js @@ -1,6 +1,7 @@ import React from 'react'; import { useNavigate } from 'react-router-dom'; // Import useNavigate import './ScheduleTable.css'; +import { BASE_URL } from './App'; function ScheduleWTable({ users }) { const navigate = useNavigate(); @@ -25,7 +26,7 @@ function ScheduleWTable({ users }) { {user.formData.name} {user.pdfFileUrl ? ( - + {user.formData.titleOfPRPTopic} ) : ( diff --git a/client/src/Search.css b/client/src/Search.css index 19396ef..b0ce6e0 100644 --- a/client/src/Search.css +++ b/client/src/Search.css @@ -9,7 +9,7 @@ .search-form { display: flex; - margin-bottom: 20px; /* Spacing between search and results */ + margin-bottom: 20px; } .search-input { @@ -27,7 +27,7 @@ border-radius: 4px; padding: 8px 15px; cursor: pointer; - width: 150px; /* Ensures that the button is wider */ + width: 150px; } .search-results { diff --git a/client/src/Search.js b/client/src/Search.js index 04986d3..8678930 100644 --- a/client/src/Search.js +++ b/client/src/Search.js @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import { useLocation } from 'react-router-dom'; // Import useLocation import axios from 'axios'; import './Search.css'; +import { BASE_URL } from './App'; function Search() { const location = useLocation(); // Access the location object @@ -24,7 +25,7 @@ function Search() { const handleSearchSubmit = async (event) => { event.preventDefault(); try { - const response = await axios.get(`http://localhost:5000/search?name=${searchQuery}`); + const response = await axios.get(`${BASE_URL}/search?name=${searchQuery}`); setSearchResults(response.data.sort((a, b) => a.username.localeCompare(b.username))); setSelectedUser(null); } catch (error) { @@ -34,7 +35,7 @@ function Search() { const handleUserClick = async (userId) => { try { - const response = await axios.get(`http://localhost:5000/userData?userId=${userId}`); + const response = await axios.get(`${BASE_URL}/userData?userId=${userId}`); setSelectedUser(response.data); } catch (error) { console.error('Error fetching user data:', error); @@ -50,7 +51,7 @@ function Search() { const handlePasswordReset = async (event) => { event.preventDefault(); try { - await axios.post('http://localhost:5000/resetPassword', { + await axios.post(`${BASE_URL}/resetPassword`, { selectedUserId: selectedUser.username, password: newPassword }); @@ -112,7 +113,7 @@ function Search() {

Semester: {selectedUser.semester}

Waiver: {selectedUser.waive}

PRP Paper: {selectedUser.pdfFileUrl && ( - Open PDF + Open PDF )}

diff --git a/client/src/SignIn.css b/client/src/SignIn.css index 0ad8527..9e3ee2a 100644 --- a/client/src/SignIn.css +++ b/client/src/SignIn.css @@ -27,9 +27,9 @@ font-weight: 500; } - .form-input { + #form-input { width: 100%; - padding: 10px; + padding-right: 0px; border: 1px solid #ccc; border-radius: 4px; font-size: 16px; diff --git a/client/src/SignIn.js b/client/src/SignIn.js index 5491084..2c2f5ea 100644 --- a/client/src/SignIn.js +++ b/client/src/SignIn.js @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import axios from 'axios'; import { Link, useNavigate } from 'react-router-dom'; import { useAuth } from './AuthContext'; - +import { BASE_URL } from './App'; @@ -23,7 +23,7 @@ function SignIn() { try { // Replace URL with your actual backend endpoint - const response = await axios.post('http://localhost:5000/signin', { username, password }); + const response = await axios.post(`${BASE_URL}/signin`, { username, password }); // Handle login success by logging in info and putting info into local Storage login(response.data); localStorage.setItem("localToken", JSON.stringify(response.data)); @@ -53,11 +53,11 @@ function SignIn() {
{/* Add a class if specific form styling is needed */}
- setUsername(e.target.value)} required /> + setUsername(e.target.value)} required />
- setPassword(e.target.value)} required /> + setPassword(e.target.value)} required />

diff --git a/server.js b/server.js index 1b15827..3d1720d 100644 --- a/server.js +++ b/server.js @@ -146,33 +146,54 @@ app.post('/saveSchedulingData', async (req, res) => { // PDF File Upload app.post('/uploadPdf', upload.single('pdfFile'), async (req, res) => { - if (!req.file) { - return res.status(400).send('No file uploaded.'); - } + try { + // Check if file is uploaded + if (!req.file) { + return res.status(400).send('No file uploaded.'); + } - if (path.extname(req.file.originalname).toLowerCase() !== '.pdf') { - return res.status(400).send('Only PDF files are allowed.'); - } + // Check if file is a PDF + if (path.extname(req.file.originalname).toLowerCase() !== '.pdf') { + return res.status(400).send('Only PDF files are allowed.'); + } - try { - const userId = req.body.userId; // Ensure userId is passed with the file - const user = await User.findById(userId); + const userId = req.body.userId; + // Ensure userId is provided + if (!userId) { + return res.status(400).send('User ID is required.'); + } + + // Find user by ID + const user = await User.findById(userId); if (!user) { return res.status(404).send('User not found.'); } - // Check if there's an existing PDF and delete it + // Delete existing PDF file if it exists if (user.pdfFileUrl) { const existingFilePath = path.join(__dirname, user.pdfFileUrl); - await fs.remove(existingFilePath); + try { + await fs.remove(existingFilePath); + } catch (removeError) { + console.error('Error deleting existing file:', removeError); + return res.status(500).send('Error deleting existing file.'); + } } - // Set new PDF URL + // Set new PDF URL and update user const pdfUrl = `/uploads/${req.file.filename}`; - - // Update user's PDF URL - const updatedUser = await User.findByIdAndUpdate(userId, { pdfFileUrl: pdfUrl }, { new: true }); + const updatedUser = await User.findByIdAndUpdate( + userId, + { pdfFileUrl: pdfUrl }, + { new: true } + ); + + if (!updatedUser) { + return res.status(500).send('Error updating user with new PDF URL.'); + } + + // Send successful response res.json({ message: "File uploaded successfully.", user: updatedUser }); } catch (error) { console.error('File upload or deletion error:', error); @@ -180,6 +201,41 @@ app.post('/uploadPdf', upload.single('pdfFile'), async (req, res) => { } }); +// app.post('/uploadPdf', upload.single('pdfFile'), async (req, res) => { +// if (!req.file) { +// return res.status(400).send('No file uploaded.'); +// } + +// if (path.extname(req.file.originalname).toLowerCase() !== '.pdf') { +// return res.status(400).send('Only PDF files are allowed.'); +// } + +// try { +// const userId = req.body.userId; // Ensure userId is passed with the file +// const user = await User.findById(userId); + +// if (!user) { +// return res.status(404).send('User not found.'); +// } + +// // Check if there's an existing PDF and delete it +// if (user.pdfFileUrl) { +// const existingFilePath = path.join(__dirname, user.pdfFileUrl); +// await fs.remove(existingFilePath); +// } + +// // Set new PDF URL +// const pdfUrl = `/uploads/${req.file.filename}`; + +// // Update user's PDF URL +// const updatedUser = await User.findByIdAndUpdate(userId, { pdfFileUrl: pdfUrl }, { new: true }); +// res.json({ message: "File uploaded successfully.", user: updatedUser }); +// } catch (error) { +// console.error('File upload or deletion error:', error); +// res.status(500).send('Error uploading file'); +// } +// }); + //Register user diff --git a/uploads/pdfFile-1730316367613-824075995.pdf b/uploads/pdfFile-1730316367613-824075995.pdf new file mode 100644 index 0000000..e19b112 Binary files /dev/null and b/uploads/pdfFile-1730316367613-824075995.pdf differ diff --git a/uploads/pdfFile-1730316662814-261939244.pdf b/uploads/pdfFile-1730316662814-261939244.pdf new file mode 100644 index 0000000..2b9b749 Binary files /dev/null and b/uploads/pdfFile-1730316662814-261939244.pdf differ diff --git a/uploads/pdfFile-1730316773601-668527035.pdf b/uploads/pdfFile-1730316773601-668527035.pdf new file mode 100644 index 0000000..2b9b749 Binary files /dev/null and b/uploads/pdfFile-1730316773601-668527035.pdf differ diff --git a/uploads/pdfFile-1730317208310-479725548.pdf b/uploads/pdfFile-1730317208310-479725548.pdf new file mode 100644 index 0000000..2b9b749 Binary files /dev/null and b/uploads/pdfFile-1730317208310-479725548.pdf differ diff --git a/uploads/pdfFile-1730318010918-353754108.pdf b/uploads/pdfFile-1730318010918-353754108.pdf new file mode 100644 index 0000000..2b9b749 Binary files /dev/null and b/uploads/pdfFile-1730318010918-353754108.pdf differ diff --git a/uploads/pdfFile-1730318240801-789512743.pdf b/uploads/pdfFile-1730318240801-789512743.pdf new file mode 100644 index 0000000..2b9b749 Binary files /dev/null and b/uploads/pdfFile-1730318240801-789512743.pdf differ diff --git a/uploads/pdfFile-1731703298401-265110535.pdf b/uploads/pdfFile-1731703298401-265110535.pdf new file mode 100644 index 0000000..9acc965 Binary files /dev/null and b/uploads/pdfFile-1731703298401-265110535.pdf differ diff --git a/uploads/pdfFile-1731879348885-491957976.pdf b/uploads/pdfFile-1731879348885-491957976.pdf new file mode 100644 index 0000000..58af0ff Binary files /dev/null and b/uploads/pdfFile-1731879348885-491957976.pdf differ