DataScope26/WEB
0
1import { useState, useEffect, useRef } from "react";2import { NavLink, useNavigate, Link } from "react-router-dom";3import { useAuth } from "../context/AuthContext.jsx";4import {5 LayoutGrid,6 ShieldCheck,7 Building2,8 Settings2,9 Settings,10 Briefcase,11 HelpCircle,12 LogOut,13 Mail,14 Users,15} from "lucide-react";16import "./Sidebar.css";17import ButtonPrimary from "./ButtonPrimary.jsx";18 19const NAV_ITEMS = [20 { key: "dashboard", label: "General dashboard", icon: LayoutGrid, path: "/overview" },21 { key: "company", label: "My companies", icon: Building2, path: "/overview/mycompanies" },22 { key: "invitations", label: "Invitaciones", icon: Mail, path: "/overview/invitaciones" },23 { key: "waitlist", label: "Waitlist", icon: Users, path: "/overview/waitlist", developerOnly: true },24 //{ key: "control", label: "Control panel", icon: ShieldCheck, path: "/overview/control" },25 { key: "user", label: "User settings", icon: Settings, path: "/overview/perfil" },26 { key: "companysettings", label: "Company settings", icon: Briefcase, path: "/overview/companysettings" },27];28 29export default function Sidebar() {30 31 const [expanded, setExpanded] = useState(false);32 const [hasSelectedCompany, setHasSelectedCompany] = useState(false);33 const [companyMenuOpen, setCompanyMenuOpen] = useState(false);34 35 36 const sidebarRef = useRef(null);37 const companyRef = useRef(null);38 const navigate = useNavigate();39 const { logout, selectedCompany, user, setSelectedCompany } = useAuth();40 41 // Determine whether the current user has any companies — hide company settings when none42 useEffect(() => {43 setHasSelectedCompany(!!(user && user.companies && user.companies.length > 0));44 }, [user]);45 46 useEffect(() => {47 const handleScroll = () => {48 const footer = document.querySelector('.footer');49 if (footer && sidebarRef.current) {50 const footerRect = footer.getBoundingClientRect();51 const visibleFooterHeight = Math.max(0, window.innerHeight - footerRect.top);52 sidebarRef.current.style.setProperty('--footer-offset', `${visibleFooterHeight}px`);53 }54 };55 56 window.addEventListener('scroll', handleScroll, { passive: true });57 window.addEventListener('resize', handleScroll);58 59 handleScroll();60 const timer = setTimeout(handleScroll, 300);61 62 return () => {63 window.removeEventListener('scroll', handleScroll);64 window.removeEventListener('resize', handleScroll);65 clearTimeout(timer);66 };67 }, []);68 69 // Close company menu and collapse sidebar when clicking outside the sidebar70 useEffect(() => {71 const handleOutside = (e) => {72 if (sidebarRef.current && !sidebarRef.current.contains(e.target)) {73 setCompanyMenuOpen(false);74 setExpanded(false);75 }76 };77 document.addEventListener('mousedown', handleOutside);78 return () => document.removeEventListener('mousedown', handleOutside);79 }, []);80 81 const handleLogout = () => {82 logout();83 navigate('/');84 };85 86 const handleSelectCompany = (company) => {87 setSelectedCompany && setSelectedCompany(company);88 try { localStorage.setItem('selectedCompanyId', company.id.toString()); } catch (e) {}89 setCompanyMenuOpen(false);90 navigate('/overview', { state: { company } });91 };92 93 const currentCompany = selectedCompany || (user && user.companies && user.companies[0]) || null;94 const otherCompanies = (user && user.companies ? user.companies.filter(c => !currentCompany || c.id !== currentCompany.id) : []);95 const companyInitial = currentCompany && currentCompany.name ? currentCompany.name.charAt(0).toUpperCase() : '';96 const canToggleMenu = otherCompanies.length > 0; // only show menu when there are other companies97 98 const renderCompanyAvatar = (company, size = 'default') => {99 const initials = company && company.name ? company.name.charAt(0).toUpperCase() : '';100 const isSmall = size === 'small';101 102 return (103 <span className={`company-avatar ${isSmall ? 'company-avatar--small' : ''}`}>104 {company && company.logo ? (105 <img src={company.logo} alt={company.name} className="company-logo-img" />106 ) : (107 <span className="company-avatar__placeholder" aria-label={company ? company.name : 'Company'}>{initials}</span>108 )}109 </span>110 );111 };112 113 return (114 <aside115 ref={sidebarRef}116 className={`sidebar ${expanded ? "sidebar--expanded" : ""}`}117 onMouseEnter={() => setExpanded(true)}118 onMouseLeave={() => { if (!companyMenuOpen) setExpanded(false); }}119 >120 <nav className="sidebar-nav">121 {/* Company row with toggleable list of other companies */}122 {hasSelectedCompany && user && (123 <div className="sidebar-company" ref={companyRef}>124 <button125 type="button"126 className="sidebar-link sidebar-company-btn"127 onClick={() => { if (canToggleMenu) setCompanyMenuOpen(s => !s); }}128 aria-expanded={companyMenuOpen}129 disabled={!canToggleMenu}130 >131 <span className="sidebar-icon sidebar-company-icon">132 {renderCompanyAvatar(currentCompany)}133 </span>134 <span className="sidebar-label sidebar-company-label">{currentCompany ? currentCompany.name : 'Sin empresa'}</span>135 </button>136 {companyMenuOpen && canToggleMenu && (137 <div className={`sidebar-company-list sidebar-company-list--inline`} role="menu">138 {otherCompanies.map((c) => (139 <button140 key={c.id}141 type="button"142 className={`sidebar-company-item`}143 onClick={() => handleSelectCompany(c)}144 >145 <span className="sidebar-company-item-icon">146 {renderCompanyAvatar(c, 'small')}147 </span>148 <span className="sidebar-company-item-label">{c.name}</span>149 </button>150 ))}151 </div>152 )}153 </div>154 )}155 <ul className="sidebar-list">156 {NAV_ITEMS157 .filter(item => {158 if (item.key === 'companysettings' && !hasSelectedCompany) return false;159 if ((item.key === 'companysettings' || item.key === 'company' || item.key === 'invitations') && Number(user?.rolefk) === 3) return false;160 if (item.developerOnly && Number(user?.rolefk) !== 4) return false;161 return true;162 })163 .map(({ key, label, icon: Icon, path }) => (164 <li key={key} className="sidebar-item">165 <NavLink166 to={path}167 end={path === "/overview"}168 className={({ isActive }) =>169 `sidebar-link ${isActive ? "sidebar-link--active" : ""}`170 }171 >172 <span className="sidebar-icon">173 <Icon size={20} strokeWidth={2} />174 </span>175 <span className="sidebar-label">{label}</span>176 </NavLink>177 </li>178 ))}179 </ul>180 </nav>181 182 <div className="sidebar-footer">183 <ButtonPrimary type="button" onClick={handleLogout} className="sidebar-link sidebar-link--button">184 <span className="sidebar-icon">185 <LogOut size={20} strokeWidth={2} />186 </span>187 <span className="sidebar-label">Logout</span>188 </ButtonPrimary>189 </div>190 </aside>191 );192}