diff --git a/src/Routes/Router.tsx b/src/Routes/Router.tsx index 874ef7e7..9c98f19d 100644 --- a/src/Routes/Router.tsx +++ b/src/Routes/Router.tsx @@ -9,6 +9,8 @@ import ContributorProfile from "../pages/ContributorProfile/ContributorProfile.t import Home from "../pages/Home/Home.tsx"; import Activity from "../pages/Activity.tsx"; import PrivacyPolicy from "../pages/Privacy/PrivacyPolicy.tsx"; // ✅ Updated import path to match your new folder structure +import Profile from "../pages/Profile/Profile.tsx"; +import ProtectedRoute from "../components/ProtectedRoute"; const Router = () => { return ( @@ -21,6 +23,7 @@ const Router = () => { } /> } /> } /> + } /> } /> {/* Privacy Policy page route */} diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index fd5eac86..5fcdd439 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -1,10 +1,169 @@ import { NavLink, Link } from "react-router-dom"; -import { useState, useContext } from "react"; +import { useEffect, useMemo, useRef, useState, useContext } from "react"; import { ThemeContext } from "../context/ThemeContext"; -import { Moon, Sun, Menu, X, Github } from "lucide-react"; +import { Moon, Sun, Menu, X, ChevronDown, BadgeInfo, LogOut, User } from "lucide-react"; + +type NavbarUser = { + id?: string; + username?: string; + email?: string; +}; + +const AUTH_STORAGE_KEY = "github_tracker_auth_user"; + +const readStoredUser = (): NavbarUser | null => { + if (typeof window === "undefined") { + return null; + } + + const storedUser = window.localStorage.getItem(AUTH_STORAGE_KEY); + + if (!storedUser) { + return null; + } + + try { + const parsedUser = JSON.parse(storedUser) as NavbarUser; + return parsedUser?.username ? parsedUser : null; + } catch { + return null; + } +}; + +type ProfileDropdownProps = { + user: NavbarUser; + onLogout: () => void; + onCloseMenu?: () => void; + mobile?: boolean; +}; + +const ProfileDropdown: React.FC = ({ user, onLogout, onCloseMenu, mobile = false }) => { + const [isOpen, setIsOpen] = useState(false); + const profileMenuRef = useRef(null); + const displayName = useMemo(() => user.username ?? "Profile", [user.username]); + + useEffect(() => { + const handleOutsideClick = (event: MouseEvent) => { + if (profileMenuRef.current && !profileMenuRef.current.contains(event.target as Node)) { + setIsOpen(false); + } + }; + + document.addEventListener("mousedown", handleOutsideClick); + return () => document.removeEventListener("mousedown", handleOutsideClick); + }, []); + + const closeMenu = () => setIsOpen(false); + + if (mobile) { + return ( +
+
+
+ {displayName.charAt(0).toUpperCase()} +
+
+

{displayName}

+

{user.email ?? "Signed in"}

+
+
+ +
+ + + View Profile + + + + Account Details + + +
+
+ ); + } + + return ( +
+ + + {isOpen && ( +
+
+

Account

+
+
+ {displayName.charAt(0).toUpperCase()} +
+
+

{displayName}

+

{user.email ?? "No email available"}

+
+
+
+ +
+ + + View Profile + + + + Account Details + + +
+
+ )} +
+ ); +}; const Navbar: React.FC = () => { const [isOpen, setIsOpen] = useState(false); + const [user, setUser] = useState(() => readStoredUser()); const themeContext = useContext(ThemeContext); @@ -20,44 +179,44 @@ const Navbar: React.FC = () => { }`; const closeMenu = () => setIsOpen(false); + const handleLogout = () => { + if (typeof window !== "undefined") { + window.localStorage.removeItem(AUTH_STORAGE_KEY); + } + setUser(null); + closeMenu(); + }; return (