diff --git a/src/App.tsx b/src/App.tsx
index 9dfb6af6..c0f0f5e2 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -14,49 +14,49 @@ import ProfilePage from "./shared/pages/Profile.js";
import LoginRedirection from "./auth/Login.tsx";
import LogoutRedirection from "./auth/Logout.tsx";
import StickyFooter from "./shared/components/Navigation/StickyFooter.tsx";
-import IsAuthenticated from "./auth/Auth.tsx";
import Token from "./auth/Token.tsx";
import { HelmetProvider } from 'react-helmet-async';
+import { AuthProvider } from './context/AuthContext.tsx';
function App() {
- const authenticated = IsAuthenticated();
-
return (
-
-
-
-
-
- } />
- App is Healthy
} />
- } />
- } />
- } />
- } />
- } />
+
+
+
+
+
+
+ } />
+ App is Healthy} />
+ } />
+ } />
+ } />
+ } />
+ } />
- } />
- } />
- }
- />
- } />
- } />
- } />
- }
- />
- } />
+ } />
+ } />
+ }
+ />
+ } />
+ } />
+ } />
+ }
+ />
+ } />
- } />
-
-
-
-
-
+ } />
+
+
+
+
+
+
);
}
diff --git a/src/auth/Auth.tsx b/src/auth/Auth.tsx
deleted file mode 100644
index 1f68deda..00000000
--- a/src/auth/Auth.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-const IsAuthenticated = (): [string, boolean] => {
- const jwt = localStorage.getItem('jwt');
-
- if (!jwt) {
- return ["", false];
- }
-
- return [jwt, true];
-};
-
-export default IsAuthenticated;
\ No newline at end of file
diff --git a/src/auth/Login.tsx b/src/auth/Login.tsx
index 6f78c949..9622236c 100644
--- a/src/auth/Login.tsx
+++ b/src/auth/Login.tsx
@@ -1,6 +1,10 @@
-const LoginRedirection = () => {
- window.location.href = `${process.env.REACT_APP_BACKEND_SERVER}/login`;
- return null; // No need to render anything, as the redirection happens immediately
-};
+import { useAuth } from "../context/AuthContext.tsx";
-export default LoginRedirection;
\ No newline at end of file
+export default function LoginRedirection() {
+ const { auth } = useAuth();
+ if (auth.isAuthenticated) {
+ window.location.href = "/";
+ }
+ window.location.href = `${process.env.REACT_APP_BACKEND_SERVER}/login`;
+ return null;
+};
\ No newline at end of file
diff --git a/src/auth/Logout.tsx b/src/auth/Logout.tsx
index da4aeeb7..1d31e828 100644
--- a/src/auth/Logout.tsx
+++ b/src/auth/Logout.tsx
@@ -1,47 +1,38 @@
import { useEffect } from "react";
+import { useAuth } from "../context/AuthContext.tsx";
-const logout = async (token: string) => {
- try {
- const response = await fetch(
- `${process.env.REACT_APP_BACKEND_SERVER}/logout`,
- {
- method: "GET",
- credentials: "include", // to send cookies or session data
- headers: {
- Authorization: `Bearer ${token}`,
- },
- }
- );
- if (response.ok) {
- // Clear local storage or tokens
- localStorage.removeItem("jwt");
-
- // Redirect to the homepage or login page
- const intervalId = setInterval(() => {
- if (!localStorage.getItem("jwt")) {
- clearInterval(intervalId); // Clear the interval once condition is met
- window.location.href = "/";
- }
- }, 5); // Check every 5ms (adjust as needed)
- } else {
- console.error("Failed to logout");
- }
- } catch (error) {
- console.error("Error logging out:", error);
- window.location.href = "/";
- }
-};
+export default function LogoutRedirection() {
+ const { auth, logout } = useAuth();
-const LogoutRedirection = (authenticated) => {
- if (!authenticated.authenticated[1]) {
+ if (!auth.isAuthenticated) {
window.location.href = "/";
}
console.log("Logging out...");
useEffect(() => {
- logout(authenticated.authenticated[0]);
- }, []); // Run only on component mount
+ async function logoutUser() {
+ try {
+ const response = await fetch(
+ `${process.env.REACT_APP_BACKEND_SERVER}/logout`,
+ {
+ method: "GET",
+ credentials: "include", // to send cookies or session data
+ headers: {
+ Authorization: `Bearer ${auth.token}`,
+ },
+ }
+ );
+ if (response.ok) {
+ logout();
+ } else {
+ console.error("Failed to logout");
+ }
+ } catch (error) {
+ console.error("Error logging out:", error);
+ window.location.href = "/";
+ }
+ }
+ logoutUser();
+ }, [auth, logout]);
return null; // Since this component doesn't need to render anything
-};
-
-export default LogoutRedirection;
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/src/auth/Token.tsx b/src/auth/Token.tsx
index 05cf3015..515f5d87 100644
--- a/src/auth/Token.tsx
+++ b/src/auth/Token.tsx
@@ -1,9 +1,12 @@
-const Token = () => {
+import { useAuth } from "../context/AuthContext.tsx";
+
+export default function Token() {
+
+ const { login } = useAuth();
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get("code");
- console.log("Code:", code);
if (code) {
fetch(`${process.env.REACT_APP_BACKEND_SERVER}/token`, {
method: "POST",
@@ -14,26 +17,16 @@ const Token = () => {
})
.then((response) => response.json())
.then((data) => {
- console.log("Data:", data);
const token = data.token;
- console.log("Token:", token);
if (token) {
- localStorage.setItem("jwt", token);
-
- // Periodically check if both jwt and jwt-time are set
- const intervalId = setInterval(() => {
- if (localStorage.getItem("jwt")) {
- clearInterval(intervalId); // Clear the interval once condition is met
- window.location.href = "/";
- }
- }, 5); // Check every 5ms (adjust as needed)
+ login(token);
return null;
}
})
.catch((error) => console.error("Error fetching token:", error));
+ } else {
+ window.location.href = "/";
}
return null;
-}
-
-export default Token;
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/context/AuthContext.tsx b/src/context/AuthContext.tsx
new file mode 100644
index 00000000..add455b5
--- /dev/null
+++ b/src/context/AuthContext.tsx
@@ -0,0 +1,53 @@
+import React, { createContext, useState, useContext } from 'react';
+
+const AuthContext = createContext<{
+ auth: { isAuthenticated: boolean; token: string | null };
+ login: (token: string) => void;
+ logout: () => void;
+ loadToken: () => void;
+}>({
+ auth: { isAuthenticated: false, token: null },
+ login: () => { },
+ logout: () => { },
+ loadToken: () => { }
+});
+
+import { ReactNode } from 'react';
+
+interface AuthProviderProps {
+ children: ReactNode;
+}
+
+export const AuthProvider = ({ children }: AuthProviderProps) => {
+ const [auth, setAuth] = useState<{ isAuthenticated: boolean; token: string | null }>({
+ isAuthenticated: false,
+ token: null,
+ });
+
+ const login = (token: string) => {
+ setAuth({ isAuthenticated: true, token });
+ // Save token to localStorage for persistence
+ localStorage.setItem('jwt', token);
+ };
+
+ const logout = () => {
+ setAuth({ isAuthenticated: false, token: null });
+ // Clear token from localStorage
+ localStorage.removeItem('jwt');
+ };
+
+ const loadToken = () => {
+ const savedToken = localStorage.getItem('jwt');
+ if (savedToken) {
+ setAuth({ isAuthenticated: true, token: savedToken });
+ }
+ };
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useAuth = () => useContext(AuthContext);
\ No newline at end of file
diff --git a/src/context/global/GlobalContext.js b/src/context/global/GlobalContext.js
deleted file mode 100644
index 2a010079..00000000
--- a/src/context/global/GlobalContext.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import { createContext } from 'react';
-
-const globalContext = createContext(null);
-
-export default globalContext;
diff --git a/src/context/global/GlobalContextProvider.js b/src/context/global/GlobalContextProvider.js
deleted file mode 100644
index 95588aa3..00000000
--- a/src/context/global/GlobalContextProvider.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import React, { useEffect } from "react";
-import { Cookies, useCookies } from "react-cookie";
-import globalContext from "./GlobalContext";
-import { useReducer } from "react";
-import useGlobalContext from "./useGlobalContext";
-
-// log in function
-
-const GlobalContextProvider = ({ children }) => {
- // unpack cookies
- const [cookies, setCookie, removeCookie] = useCookies(["userCookie"]);
-
- const unpackCookies = () => {
- const user = cookies.userCookie || null;
-
- if (!user) {
- // if no user cookie, create one
- const userInfo = {
- loggedIn: false,
- };
- setCookie("userCookie", userInfo, {
- path: "/"
- });
- return userInfo;
- } else {
- return user;
- }
- };
-
- function reducer(state, action) {
- switch (action.type) {
- case "login":
- return { ...state, loggedIn: true, ...action.payload };
- case "logout":
- return { loggedIn: false, ...action.payload };
- default:
- return state;
- }
- }
-
- const [state, dispatch] = useReducer(reducer, unpackCookies());
-
- useEffect(() => {
- // login(state);
- }, []);
-
-
-
- return (
-
- {children}
-
- );
-};
-
-// export provider and dispatch
-export { GlobalContextProvider };
diff --git a/src/context/global/authActions.js b/src/context/global/authActions.js
deleted file mode 100644
index 238a4b58..00000000
--- a/src/context/global/authActions.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import useGlobalContext from "./useGlobalContext";
-import { useCookies } from "react-cookie";
-
-const useAuthActions = () => {
- const { dispatch } = useGlobalContext();
- const [cookie, setCookie, removeCookie] = useCookies(["userCookie"]);
-
- async function login() {
- // make fake call to server
-
- async function getDetails() {
- const response = await fetch(
- `${process.env.REACT_APP_BACKEND_SERVER}/getProfessorCookies/cenzar`,
- );
-
- if (!response.ok) {
- return;
- } else {
- return response.json();
- }
-
- // return new Promise((resolve, reject) => {
- // setTimeout(() => {
- // resolve({
- // loggedIn: true,
- // id: "d1",
- // name: "John Doe",
- // email: "johnd@rpi.edu",
- // role: "admin",
- // department: "Computer Science",
- // researchCenter: "AI",
- // });
- // }, 500);
- // });
- }
-
- const response = await getDetails();
-
- // if response, dispatch and set cookies
- setCookie("userCookie", response, {
- path: "/",
- });
-
- response && dispatch({ type: "login", payload: response });
- }
-
- const logout = () => {
- removeCookie("userCookie", {
- path: "/",
- });
- dispatch({ type: "logout", payload: { dispatch } });
- };
-
- return { login, logout };
-};
-
-export default useAuthActions;
diff --git a/src/context/global/useGlobalContext.js b/src/context/global/useGlobalContext.js
deleted file mode 100644
index b856f1c6..00000000
--- a/src/context/global/useGlobalContext.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import globalContext from "./GlobalContext";
-import { useContext } from "react";
-
-const useGlobalContext = () => {
- return useContext(globalContext);
-};
-
-export default useGlobalContext;
\ No newline at end of file
diff --git a/src/shared/data/locations.ts b/src/shared/data/locations.ts
new file mode 100644
index 00000000..4cdd4c45
--- /dev/null
+++ b/src/shared/data/locations.ts
@@ -0,0 +1,25 @@
+export const Locations = [
+ "TBD",
+ "Amos Eaton",
+ "Carnegie",
+ "Center for Biotechnology and Interdisciplinary Studies",
+ "Center for Computational Innovations",
+ "Low Center for Industrial Innovation (CII)",
+ "Cogswell Laboratory",
+ "Darrin Communications Center",
+ "Experimental Media and Performing Arts Center",
+ "Greene Library",
+ "Jonsson Engineering Center",
+ "Jonsson-Rowland Science Center",
+ "Lally Hall",
+ "LINAC Facility (Gaerttner Laboratory)",
+ "Materials Research Center",
+ "Pittsburgh Building",
+ "Ricketts Building",
+ "Russell Sage Laboratory",
+ "Voorhees Computing Center",
+ "Walker Laboratory",
+ "West Hall",
+ "Winslow Building",
+ "Remote"
+]
\ No newline at end of file
diff --git a/src/staff/components/CreationForms.tsx b/src/staff/components/CreationForms.tsx
index 67e48693..3a202853 100644
--- a/src/staff/components/CreationForms.tsx
+++ b/src/staff/components/CreationForms.tsx
@@ -4,80 +4,23 @@ import { useEffect } from "react";
import CheckBox from "./Checkbox.tsx";
import Input from "./Input";
import { useParams } from "react-router";
+import { useAuth } from "../../context/AuthContext.tsx";
+import { Locations } from "../../shared/data/locations.ts";
+
interface CreationFormsProps {
edit: boolean;
- token: string;
}
-const locations = [
- "TBD",
- "Amos Eaton",
- "Carnegie",
- "Center for Biotechnology and Interdisciplinary Studies",
- "Center for Computational Innovations",
- "Low Center for Industrial Innovation (CII)",
- "Cogswell Laboratory",
- "Darrin Communications Center",
- "Experimental Media and Performing Arts Center",
- "Greene Library",
- "Jonsson Engineering Center",
- "Jonsson-Rowland Science Center",
- "Lally Hall",
- "LINAC Facility (Gaerttner Laboratory)",
- "Materials Research Center",
- "Pittsburgh Building",
- "Ricketts Building",
- "Russell Sage Laboratory",
- "Voorhees Computing Center",
- "Walker Laboratory",
- "West Hall",
- "Winslow Building",
- "Remote"
-]
-
-const CreationForms: React.FC = ({ edit, token }) => {
+export default function CreationForms({ edit }: CreationFormsProps) {
+ const { auth } = useAuth();
const { postID } = useParams();
const [loading, setLoading] = useState(false);
const [compensationType, setCompensationType] = useState("For Pay"); // Manage the state for "For Pay" or "For Credit"
const [years, setYears] = useState([]);
- async function fetchEditData() {
-
-
- const response = await fetch(
- `${process.env.REACT_APP_BACKEND_SERVER}/editOpportunity/${postID}`, {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- }
- );
- if (response.ok) {
- console.log("Response ok");
- const { id, title, application_due, type, hourlyPay, credits, description, recommended_experience, location, years } = await response.json();
- await Promise.all([fetchYears()]);
- reset({
- id,
- title,
- application_due,
- type,
- hourlyPay,
- credits,
- description,
- recommended_experience,
- location,
- years,
- });
-
- setLoading(false);
- } else {
- console.log("No response");
- setLoading("no response");
- }
- }
-
async function fetchYears() {
- const response = await fetch(`${process.env.REACT_APP_BACKEND_SERVER}/years`)
+ const response = await fetch(`${process.env.REACT_APP_BACKEND_SERVER}/years`);
if (response.ok) {
const data = await response.json();
@@ -108,23 +51,27 @@ const CreationForms: React.FC = ({ edit, token }) => {
},
});
- useEffect(() => {
- fetchYears();
- if (edit) {
- fetchEditData();
- } else {
- setLoading(false);
- }
- }, []);
+ interface FormData {
+ id: string;
+ title: string;
+ application_due: string;
+ type: string;
+ hourlyPay: number;
+ credits: string[];
+ description: string;
+ recommended_experience: string;
+ location: string;
+ years: string[];
+ }
- const submitHandler = (data) => {
+ function submitHandler(data: FormData) {
console.log({ ...data });
if (edit) {
fetch(`${process.env.REACT_APP_BACKEND_SERVER}/editOpportunity/${postID}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
- Authorization: `Bearer ${token}`,
+ Authorization: `Bearer ${auth.token}`,
},
body: JSON.stringify({ ...data }),
}).then((response) => {
@@ -140,14 +87,15 @@ const CreationForms: React.FC = ({ edit, token }) => {
method: "POST",
headers: {
"Content-Type": "application/json",
- Authorization: `Bearer ${token}`,
+ Authorization: `Bearer ${auth.token}`,
},
body: JSON.stringify({ ...data }),
}).then((response) => {
if (response.ok) {
alert("Successfully created");
- const data_response = response.json()
- window.location.href = `/opportunity/${data_response["id"]}`;
+ response.json().then((data_response) => {
+ window.location.href = `/opportunity/${data_response["id"]}`;
+ });
} else {
alert("Failed to create");
console.log(response);
@@ -156,6 +104,45 @@ const CreationForms: React.FC = ({ edit, token }) => {
}
};
+ useEffect(() => {
+ async function fetchEditData() {
+ const response = await fetch(
+ `${process.env.REACT_APP_BACKEND_SERVER}/editOpportunity/${postID}`, {
+ headers: {
+ Authorization: `Bearer ${auth.token}`,
+ },
+ }
+ );
+ if (response.ok) {
+ const { id, title, application_due, type, hourlyPay, credits, description, recommended_experience, location, years } = await response.json();
+ await Promise.all([fetchYears()]);
+ reset({
+ id,
+ title,
+ application_due,
+ type,
+ hourlyPay,
+ credits,
+ description,
+ recommended_experience,
+ location,
+ years,
+ });
+ setLoading(false);
+ } else {
+ console.log("No response");
+ setLoading("no response");
+ }
+ }
+
+ fetchYears();
+ if (edit) {
+ fetchEditData();
+ } else {
+ setLoading(false);
+ }
+ }, [edit, auth.token, postID, reset]);
+
return loading === false && years != null ? (