1import { useState, useRef, useEffect } from "react";
2import { Link, useLocation } from "react-router-dom";
3import { useAuth } from "../context/AuthContext";
4import {
5 Home,
6 Search,
7 Folder,
8 Bell,
9 PenSquare,
10 User,
11 LogOut,
12 MoreHorizontal,
13 Highlighter,
14 Bookmark,
15} from "lucide-react";
16import { getUnreadNotificationCount } from "../api/client";
17import logo from "../assets/logo.svg";
18
19export default function Sidebar() {
20 const { user, isAuthenticated, logout, loading } = useAuth();
21 const location = useLocation();
22 const [menuOpen, setMenuOpen] = useState(false);
23 const [unreadCount, setUnreadCount] = useState(0);
24 const menuRef = useRef(null);
25
26 const isActive = (path) => {
27 if (path === "/") return location.pathname === "/";
28 return location.pathname.startsWith(path);
29 };
30
31 useEffect(() => {
32 if (isAuthenticated) {
33 getUnreadNotificationCount()
34 .then((data) => setUnreadCount(data.count || 0))
35 .catch(() => {});
36 const interval = setInterval(() => {
37 getUnreadNotificationCount()
38 .then((data) => setUnreadCount(data.count || 0))
39 .catch(() => {});
40 }, 60000);
41 return () => clearInterval(interval);
42 }
43 }, [isAuthenticated]);
44
45 useEffect(() => {
46 const handleClickOutside = (e) => {
47 if (menuRef.current && !menuRef.current.contains(e.target)) {
48 setMenuOpen(false);
49 }
50 };
51 document.addEventListener("mousedown", handleClickOutside);
52 return () => document.removeEventListener("mousedown", handleClickOutside);
53 }, []);
54
55 const getInitials = () => {
56 if (user?.displayName) {
57 return user.displayName.substring(0, 2).toUpperCase();
58 }
59 if (user?.handle) {
60 return user.handle.substring(0, 2).toUpperCase();
61 }
62 return "U";
63 };
64
65 return (
66 <aside className="sidebar">
67 <Link to="/" className="sidebar-header">
68 <img src={logo} alt="Margin" className="sidebar-logo" />
69 <span className="sidebar-brand">Margin</span>
70 </Link>
71
72 <nav className="sidebar-nav">
73 <Link
74 to="/"
75 className={`sidebar-link ${isActive("/") ? "active" : ""}`}
76 >
77 <Home size={20} />
78 <span>Home</span>
79 </Link>
80 <Link
81 to="/url"
82 className={`sidebar-link ${isActive("/url") ? "active" : ""}`}
83 >
84 <Search size={20} />
85 <span>Browse</span>
86 </Link>
87
88 {isAuthenticated && (
89 <>
90 <div className="sidebar-section-title">Library</div>
91 <Link
92 to="/highlights"
93 className={`sidebar-link ${isActive("/highlights") ? "active" : ""}`}
94 >
95 <Highlighter size={20} />
96 <span>Highlights</span>
97 </Link>
98 <Link
99 to="/bookmarks"
100 className={`sidebar-link ${isActive("/bookmarks") ? "active" : ""}`}
101 >
102 <Bookmark size={20} />
103 <span>Bookmarks</span>
104 </Link>
105 <Link
106 to="/collections"
107 className={`sidebar-link ${isActive("/collections") ? "active" : ""}`}
108 >
109 <Folder size={20} />
110 <span>Collections</span>
111 </Link>
112 <Link
113 to="/notifications"
114 className={`sidebar-link ${isActive("/notifications") ? "active" : ""}`}
115 onClick={() => setUnreadCount(0)}
116 >
117 <Bell size={20} />
118 <span>Notifications</span>
119 {unreadCount > 0 && (
120 <span className="notification-badge">{unreadCount}</span>
121 )}
122 </Link>
123 </>
124 )}
125 </nav>
126
127 {isAuthenticated && (
128 <Link to="/new" className="sidebar-new-btn">
129 <PenSquare size={18} />
130 <span>New</span>
131 </Link>
132 )}
133
134 <div className="sidebar-footer" ref={menuRef}>
135 {!loading &&
136 (isAuthenticated ? (
137 <>
138 <div
139 className="sidebar-user"
140 onClick={() => setMenuOpen(!menuOpen)}
141 >
142 <div className="sidebar-avatar">
143 {user?.avatar ? (
144 <img src={user.avatar} alt={user.displayName} />
145 ) : (
146 <span>{getInitials()}</span>
147 )}
148 </div>
149 <div className="sidebar-user-info">
150 <div className="sidebar-user-name">
151 {user?.displayName || user?.handle}
152 </div>
153 <div className="sidebar-user-handle">@{user?.handle}</div>
154 </div>
155 <MoreHorizontal size={18} className="sidebar-user-menu" />
156 </div>
157
158 {menuOpen && (
159 <div className="sidebar-dropdown">
160 <Link
161 to={`/profile/${user?.did}`}
162 className="sidebar-dropdown-item"
163 onClick={() => setMenuOpen(false)}
164 >
165 <User size={16} />
166 View Profile
167 </Link>
168 <button
169 onClick={() => {
170 logout();
171 setMenuOpen(false);
172 }}
173 className="sidebar-dropdown-item danger"
174 >
175 <LogOut size={16} />
176 Sign Out
177 </button>
178 </div>
179 )}
180 </>
181 ) : (
182 <Link to="/login" className="sidebar-new-btn" style={{ margin: 0 }}>
183 Sign In
184 </Link>
185 ))}
186 </div>
187 </aside>
188 );
189}