diff --git a/src/Routes/Router.tsx b/src/Routes/Router.tsx index 79c8f44..10894f4 100644 --- a/src/Routes/Router.tsx +++ b/src/Routes/Router.tsx @@ -10,7 +10,8 @@ import Home from "../pages/Home/Home.tsx"; import Activity from "../pages/Activity.tsx"; import Community from "../pages/Community/Community.tsx"; import PrivacyPolicy from "../pages/Privacy/PrivacyPolicy.tsx"; // ✅ Updated import path to match your new folder structure -import RepoCompare from "../pages/RepoCompare/RepoCompare.tsx"; +import Profile from "../pages/Profile/Profile.tsx"; +import ProtectedRoute from "../components/ProtectedRoute"; const Router = () => { return ( @@ -23,8 +24,7 @@ const Router = () => { } /> } /> } /> - }> - }> + } /> } /> } /> } /> diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 7bf09a5..bada69d 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -1,12 +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 { AuthContext } from "../context/AuthContext"; -import { Moon, Sun, Menu, X } from "lucide-react"; -import { useNavigate } from "react-router-dom"; +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); const authContext = useContext(AuthContext); @@ -25,6 +182,13 @@ const Navbar: React.FC = () => { }`; const closeMenu = () => setIsOpen(false); + const handleLogout = () => { + if (typeof window !== "undefined") { + window.localStorage.removeItem(AUTH_STORAGE_KEY); + } + setUser(null); + closeMenu(); + }; const handleLogout = async () => { try { @@ -40,49 +204,33 @@ const Navbar: React.FC = () => { return (