Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions src/auth/Logout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@ export default function LogoutRedirection() {
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}`,
},
credentials: "include",
}
);
if (response.ok) {
Expand All @@ -32,7 +28,7 @@ export default function LogoutRedirection() {
}
}
logoutUser();
}, [logout, auth.token]);
}, [logout]);

return null; // Since this component doesn't need to render anything
};
23 changes: 15 additions & 8 deletions src/auth/Token.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { useEffect } from "react";

export default function Token() {

const { login } = useAuth();
const { auth, login } = useAuth();

if (auth.isAuthenticated) {
window.location.href = "/";
}

const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get("code");
Expand All @@ -16,15 +20,18 @@ export default function Token() {
"Content-Type": "application/json",
},
body: JSON.stringify({ code }),
credentials: "include",
})
.then((response) => response.json())
.then((data) => {
const token = data.token;
if (token) {
login(token);
window.location.href = "/";
return null;
}
const registered = data.registered;
console.log("registered", registered);
login();
// if (registered) {
window.location.href = "/";
return null;
// }
// TODO: Redirect to registration page
})
.catch((error) => console.error("Error fetching token:", error));
}
Expand All @@ -34,4 +41,4 @@ export default function Token() {
}, [code, login]);

return null;
}
}
63 changes: 36 additions & 27 deletions src/context/AuthContext.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,62 @@
import React, { createContext, useState, useContext, useEffect } from 'react';
import { ReactNode } from 'react';
import React, { createContext, useState, useContext } from 'react';
import { ReactNode, useEffect } from 'react';


const AuthContext = createContext<{
auth: { isAuthenticated: boolean; token: string | null };
login: (token: string) => void;
auth: { isAuthenticated: boolean };
login: () => void;
logout: () => void;
loadToken: () => void;
}>({
auth: { isAuthenticated: false, token: null },
auth: { isAuthenticated: false },
login: () => { },
logout: () => { },
loadToken: () => { }
});
interface AuthProviderProps {
children: ReactNode;
}

export const AuthProvider = ({ children }: AuthProviderProps) => {
const [auth, setAuth] = useState<{ isAuthenticated: boolean; token: string | null }>({
const [auth, setAuth] = useState<{ isAuthenticated: boolean }>({
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 });
const checkAuth = async () => {
try {
const response = await fetch(`${process.env.REACT_APP_BACKEND_SERVER}/authcheck`, {
credentials: "include",
});
if (response.ok) {
setAuth({ isAuthenticated: true });
} else {
const refreshResponse = await fetch(`${process.env.REACT_APP_BACKEND_SERVER}/token/refresh`, {
credentials: "include",
});
if (refreshResponse.ok) {
setAuth({ isAuthenticated: true });
} else {
setAuth({ isAuthenticated: false });
}
}
} catch (error) {
console.error("Auth check failed:", error);
setAuth({ isAuthenticated: false });
}
};

useEffect(() => {
loadToken();
checkAuth(); // Run this on mount to persist session state
}, []);

const login = () => {
setAuth({ isAuthenticated: true });
};

const logout = () => {
setAuth({ isAuthenticated: false });
};

return (
<AuthContext.Provider value={{ auth, login, logout, loadToken }}>
<AuthContext.Provider value={{ auth, login, logout }}>
{children}
</AuthContext.Provider>
);
Expand Down
10 changes: 1 addition & 9 deletions src/shared/components/Profile/ProfileComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,7 @@ import ProfileDescription from "./ProfileDescription.tsx";
import ProfileOpportunities from "./ProfileOpportunities.tsx";
import SEO from "..//SEO.tsx";
import Breadcrumb from "../UIElements/Breadcrumb.tsx";

interface Profile {
name: string;
image: string;
department: string;
description: string;
website?: string;
}
import { Profile } from "../../../types/profile.ts";

const ProfileComponents = ({ profile, id, staff }: { profile: Profile, id: string, staff: boolean }) => {
return (
Expand All @@ -36,7 +29,6 @@ const ProfileComponents = ({ profile, id, staff }: { profile: Profile, id: strin
<div className="flex gap-5">
<ProfileAvatar name={profile.name} image={profile.image} />
<ProfileDescription
website={profile.website}
{...profile}
/>
</div>
Expand Down
18 changes: 6 additions & 12 deletions src/shared/components/Profile/ProfileDescription.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import React from "react";
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
import { Profile } from "../../../types/profile.ts";

const ProfileDescription = ({ name, department, description, website }) => {
export default function ProfileDescription({
name, department, description, website, pronouns
}: Profile) {
return (
<div className="font-light flex2 gap-2">
<h2 className="font-extrabold text-5xl">{name}</h2>
<h5 className="text-gray-700">{department}</h5>
{pronouns && <h5 className="text-gray-700">{pronouns}</h5>}
<p>{description}</p>
{website && website.length && (
<Link to={website} target="_blank">
Expand All @@ -15,13 +18,4 @@ const ProfileDescription = ({ name, department, description, website }) => {
)}
</div>
);
};

ProfileDescription.propTypes = {
name: PropTypes.string.isRequired,
department: PropTypes.string,
description: PropTypes.string.isRequired,
website: PropTypes.string,
};

export default ProfileDescription;
};
8 changes: 2 additions & 6 deletions src/shared/components/Profile/ProfileOpportunities.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import React from "react";
import LargeTextCard from "../UIElements/LargeTextCard.tsx";
import { useState, useEffect } from "react";
import { useAuth } from "../../../context/AuthContext.tsx";

export default function ProfileOpportunities({ id, staff }: { id: string, staff: boolean }) {
const { auth } = useAuth();
const [opportunities, setOpportunities] = useState<Array<{ id: string; title: string; due: string; pay: string; credits: string }> | null | "no response">(null);

useEffect(() => {
async function setData() {
const response = await fetch(
`${process.env.REACT_APP_BACKEND_SERVER}/${staff ? "staff" : "profile"}/opportunities/${id}`, {
headers: {
Authorization: `Bearer ${auth.token}`,
},
credentials: "include",
}
);

Expand All @@ -26,7 +22,7 @@ export default function ProfileOpportunities({ id, staff }: { id: string, staff:
}

setData();
}, [auth.token, id, staff]);
}, [id, staff]);

const opportunityList = (
<div className="flex gap-2 flex-wrap">
Expand Down
2 changes: 1 addition & 1 deletion src/shared/pages/404.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const PageNotFound = () => {
<>
<SEO title="404 Not Found" description="Not found page" />
<p className="text-4xl text-center pt-20">Whoops!</p>
<p className="text-xl text-center pt-8">It looks like that page couldn't be reached. Please click the link below to return to LabConnect or try refreshing the page</p>
<p className="text-xl text-center pt-8">It looks like that page couldn&apos;t be reached. Please click the link below to return to LabConnect or try refreshing the page</p>
<section className="pt-8 flex justify-center">
<Link to="/" className="btn btn-primary w-1/5 text-gray-200 bg-blue-600 hover:bg-blue-900 focus:bg-blue-900">Home</Link>
</section>
Expand Down
15 changes: 0 additions & 15 deletions src/shared/pages/LoginRedirect.tsx

This file was deleted.

15 changes: 3 additions & 12 deletions src/shared/pages/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useEffect } from "react";
import { useState } from "react";
import ProfileComponents from "../components/Profile/ProfileComponents.tsx";
import { useAuth } from "../../context/AuthContext.tsx";
import { Profile } from "../../types/profile.ts";
// import EditProfile from "./EditProfile";

export default function ProfilePage() {
Expand All @@ -12,14 +13,6 @@ export default function ProfilePage() {
}

// const [editMode, setEditMode] = useState(false);
interface Profile {
id: string;
name: string;
image: string;
department: string;
description: string;
website?: string;
}

const [profile, setProfile] = useState<null | Profile | boolean>(null);

Expand All @@ -31,9 +24,7 @@ export default function ProfilePage() {
const fetchProfile = async () => {
const response = await fetch(
`${process.env.REACT_APP_BACKEND_SERVER}/profile`, {
headers: {
Authorization: `Bearer ${auth.token}`,
},
credentials: "include",
}
);

Expand All @@ -48,7 +39,7 @@ export default function ProfilePage() {
}
};
fetchProfile();
}, [auth.token]);
}, []);

// const editButton = (
// <button className="btn btn-primary my-3" onClick={changeEditMode}>
Expand Down
Loading