source: frontend/src/pages/Nav.tsx@ c684a6d

main
Last change on this file since c684a6d was dc30259, checked in by Filip Gavrilovski <filipgavrilovski28@…>, 5 months ago

add loading spinner; don't show sidebar for unauthenticated users

  • Property mode set to 100644
File size: 4.4 KB
Line 
1import { useEffect, useRef, useState } from "react";
2import { Link } from "react-router-dom";
3import { toast } from "react-toastify";
4import axiosInstance, { baseURL } from "../api/axiosInstance";
5import Logo from "../assets/logo-finkwave.png";
6import { useAuth } from "../context/authContext";
7
8interface NavProps {
9 isSidebarOpen?: boolean;
10 onToggleSidebar?: () => void;
11}
12
13const Nav = ({ isSidebarOpen = false, onToggleSidebar }: NavProps) => {
14 const { user, setUser, isAuthLoading } = useAuth();
15 const [isDropdownOpen, setIsDropdownOpen] = useState(false);
16 const dropdownRef = useRef<HTMLDivElement>(null);
17
18 const handleLogout = async (e: React.MouseEvent<HTMLButtonElement>) => {
19 e.preventDefault();
20 try {
21 await axiosInstance.post("/auth/logout");
22 setUser(undefined);
23 setIsDropdownOpen(false);
24 toast.success("Logout successful!");
25 } catch (error) {
26 console.error("Logout failed:", error);
27 toast.error("Logout failed!");
28 }
29 };
30
31 useEffect(() => {
32 const handleClickOutside = (event: MouseEvent) => {
33 if (
34 dropdownRef.current &&
35 !dropdownRef.current.contains(event.target as Node)
36 ) {
37 setIsDropdownOpen(false);
38 }
39 };
40
41 document.addEventListener("mousedown", handleClickOutside);
42 return () => {
43 document.removeEventListener("mousedown", handleClickOutside);
44 };
45 }, []);
46
47 return (
48 <div
49 className={`bg-gray-800 p-4 flex justify-between items-center fixed top-0 right-0 z-50 transition-all duration-300 ${
50 isSidebarOpen ? "left-64" : "left-0"
51 }`}
52 >
53 <div className="flex items-center gap-4">
54 {onToggleSidebar && user && (
55 <button
56 onClick={onToggleSidebar}
57 className="text-white hover:text-[#1db954] transition-colors p-2"
58 aria-label="Toggle sidebar"
59 >
60 <svg
61 className="w-6 h-6"
62 fill="none"
63 stroke="currentColor"
64 viewBox="0 0 24 24"
65 >
66 <path
67 strokeLinecap="round"
68 strokeLinejoin="round"
69 strokeWidth={2}
70 d="M4 6h16M4 12h16M4 18h16"
71 />
72 </svg>
73 </button>
74 )}
75 <Link to="/" className="text-white text-lg font-semibold">
76 <img src={Logo} alt="Finkwave Logo" className="h-12 w-auto" />
77 </Link>
78 </div>
79
80 <div className="flex items-center space-x-4">
81 {!isAuthLoading && (
82 <div className="flex items-center space-x-3">
83 {user ? (
84 <div className="relative" ref={dropdownRef}>
85 <button
86 onClick={() => setIsDropdownOpen(!isDropdownOpen)}
87 className="focus:outline-none focus:ring-2 focus:ring-blue-500 rounded-full"
88 >
89 {user.profilePhoto ? (
90 <img
91 src={`${baseURL}/${user.profilePhoto}`}
92 alt={`${user.username}'s profile`}
93 className="w-10 h-10 rounded-full object-cover cursor-pointer hover:ring-2 hover:ring-blue-400 transition-all"
94 />
95 ) : (
96 <div className="w-10 h-10 bg-blue-500 rounded-full flex items-center justify-center cursor-pointer hover:ring-2 hover:ring-blue-400 transition-all">
97 <span className="text-white text-lg font-semibold">
98 {user.username.charAt(0).toUpperCase()}
99 </span>
100 </div>
101 )}
102 </button>
103
104 {isDropdownOpen && (
105 <div className="absolute right-0 mt-2 w-48 bg-gray-700 rounded-lg shadow-lg py-1 z-50">
106 <Link
107 to="/me"
108 className="block px-4 py-2 text-sm text-white hover:bg-gray-600 transition-colors"
109 onClick={() => setIsDropdownOpen(false)}
110 >
111 Account
112 </Link>
113 <button
114 onClick={handleLogout}
115 className="w-full text-left px-4 py-2 text-sm text-white hover:bg-gray-600 transition-colors"
116 >
117 Log out
118 </button>
119 </div>
120 )}
121 </div>
122 ) : (
123 <div className="flex items-center space-x-4">
124 <Link
125 to="/login"
126 className="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg text-sm
127 font-medium transition-colors duration-200 cursor-pointer"
128 >
129 Login
130 </Link>
131 <Link
132 to="/register"
133 className="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-lg text-sm
134 font-medium transition-colors duration-200 cursor-pointer"
135 >
136 Register
137 </Link>
138 </div>
139 )}
140 </div>
141 )}
142 </div>
143 </div>
144 );
145};
146
147export default Nav;
Note: See TracBrowser for help on using the repository browser.