Skip to content
Open
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
141 changes: 140 additions & 1 deletion client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

77 changes: 41 additions & 36 deletions client/src/components/Header.jsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,65 @@
import { useState, useRef, useEffect } from "react"
import { Link } from "react-router-dom"
import { FaUser, FaSignOutAlt, FaChevronDown, FaBars, FaTimes } from "react-icons/fa"
import { useAuth } from "../context/AuthContext"
import React from "react"
import { useState, useRef, useEffect } from "react";
import { Link, useNavigate } from "react-router-dom";
import { FaUser, FaSignOutAlt, FaChevronDown, FaBars, FaTimes } from "react-icons/fa";
import { useAuth } from "../context/AuthContext";
import React from "react";

export default function Header() {
const { user, isLoggedIn, logout } = useAuth()
const [isDropdownOpen, setIsDropdownOpen] = useState(false)
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false)
const [showLogoutConfirm, setShowLogoutConfirm] = useState(false)
const dropdownRef = useRef(null)
const { user, isLoggedIn, logout } = useAuth();
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [showLogoutConfirm, setShowLogoutConfirm] = useState(false);
const dropdownRef = useRef(null);
const navigate = useNavigate();

useEffect(() => {
function handleClickOutside(event) {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
setIsDropdownOpen(false)
setIsDropdownOpen(false);
}
}

document.addEventListener("mousedown", handleClickOutside)
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside)
}
}, [])
document.removeEventListener("mousedown", handleClickOutside);
};
}, []);

const handleLogout = () => {
setShowLogoutConfirm(true)
setIsDropdownOpen(false)
}
setShowLogoutConfirm(true);
setIsDropdownOpen(false);
};

const confirmLogout = async () => {
// If you have a delete endpoint, replace this with axios call
// await axios.delete("/api/user/delete", { headers: { Authorization: `Bearer ${user.token}` } });
Copy link

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The confirmLogout function contains commented code that suggests account deletion logic, but this function should only handle logout. The account deletion logic is misplaced and could cause confusion.

Suggested change
// await axios.delete("/api/user/delete", { headers: { Authorization: `Bearer ${user.token}` } });

Copilot uses AI. Check for mistakes.

const confirmLogout = () => {
logout()
setShowLogoutConfirm(false)
}
logout(); // Clears auth state
setShowLogoutConfirm(false);
navigate("/login");
};

const cancelLogout = () => {
setShowLogoutConfirm(false)
}
setShowLogoutConfirm(false);
};

const toggleDropdown = () => {
setIsDropdownOpen(!isDropdownOpen)
}
setIsDropdownOpen(!isDropdownOpen);
};

const toggleMobileMenu = () => {
setIsMobileMenuOpen(!isMobileMenuOpen)
}
setIsMobileMenuOpen(!isMobileMenuOpen);
};

const getInitials = (name) => {
if (!name) return "U"
if (!name) return "U";
return name
.split(" ")
.map((n) => n[0])
.join("")
.toUpperCase()
.slice(0, 2)
}
.slice(0, 2);
};

const NavLinks = () => (
<div className="flex flex-col md:flex-row space-y-2 md:space-y-0 md:space-x-8">
Expand All @@ -68,7 +73,7 @@ export default function Header() {
)}
<Link to="/resources" className="text-gray-700 hover:text-gray-900 transition-colors">Resources</Link>
</div>
)
);

return (
<>
Expand Down Expand Up @@ -96,7 +101,7 @@ export default function Header() {
</div>

<div className="hidden md:flex items-center space-x-4">
{!isLoggedIn ? (
{!user || !isLoggedIn ? (
<>
<Link to="/login" className="px-4 py-2 text-gray-700 hover:text-gray-900 hover:bg-gray-100 rounded-md transition-colors">Log in</Link>
<Link to="/signup" className="px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded-md font-medium transition-colors">Sign up</Link>
Expand Down Expand Up @@ -144,7 +149,7 @@ export default function Header() {
{isMobileMenuOpen && (
<div className="md:hidden mt-2 space-y-2 pb-4">
<NavLinks />
{!isLoggedIn ? (
{!user || !isLoggedIn ? (
<div className="space-y-2 pt-2">
<Link to="/login" className="block px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-md">Log in</Link>
<Link to="/signup" className="block px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">Sign up</Link>
Expand Down Expand Up @@ -183,5 +188,5 @@ export default function Header() {
</div>
)}
</>
)
}
);
}
40 changes: 37 additions & 3 deletions client/src/context/AuthContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ export const AuthProvider = ({ children }) => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [loading, setLoading] = useState(true);

const refreshUser = async () => {
const current = auth.currentUser;
if (current) {
const token = await current.getIdToken();
setUser({
uid: current.uid,
email: current.email,
name: current.displayName || "",
avatar: current.photoURL || "",
token,
});
}
};

const logout = () => {
auth.signOut()
.then(() => {
Expand All @@ -25,7 +39,16 @@ export const AuthProvider = ({ children }) => {
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, async (firebaseUser) => {
if (firebaseUser) {
setUser(firebaseUser);
const token = await firebaseUser.getIdToken();

setUser({
uid: firebaseUser.uid,
email: firebaseUser.email,
name: firebaseUser.displayName || "",
avatar: firebaseUser.photoURL || "",
token,
});

setIsLoggedIn(true);
} else {
setUser(null);
Expand All @@ -38,8 +61,19 @@ export const AuthProvider = ({ children }) => {
}, []);

return (
<AuthContext.Provider value={{ user, setUser, loading, setLoading, isLoggedIn, setIsLoggedIn, logout }}>
<AuthContext.Provider
value={{
user,
setUser,
loading,
setLoading,
isLoggedIn,
setIsLoggedIn,
logout,
refreshUser,
}}
>
{children}
</AuthContext.Provider>
);
};
};
Loading