Created
April 10, 2025 20:00
-
-
Save voltuer/df0f3d3843a64a3cefdd81176b6a572f to your computer and use it in GitHub Desktop.
menu.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use client'; | |
import React, { useEffect, useState } from 'react'; | |
import { useRouter, usePathname } from 'next/navigation'; | |
import { LogoutOutlined } from '@ant-design/icons'; | |
import { useEntiContext } from '@/services/context'; | |
import { QuotaProgress } from '@/components/QuotaProgress'; | |
import { createClient } from '@/services/supabase/client'; | |
import { Menu, Tooltip } from 'antd'; | |
import useWorkerStatus from '@/services/workerStatus'; | |
import CompanyMenu from './CompanyMenu'; | |
import i8n from '@/services/lang/i8n'; | |
import { buildMenu } from './items'; | |
import Link from 'next/link'; | |
const SideMenu = () => { | |
const [current, setCurrent] = useState(''); | |
const [ready, setReady] = useState(false); | |
const [items, setItems] = useState([]); | |
const [statusColor, setStatusColor] = useState('gray'); | |
const [status, setStatus] = useState('Cargando estado...'); | |
const { user, activeCompany, companies, myPermissions, canI, lang } = | |
useEntiContext(); | |
const router = useRouter(); | |
const path = usePathname(); | |
const __ = i8n(lang); | |
const signOut = async () => { | |
const supabase = createClient(); | |
await supabase.auth.signOut(); | |
localStorage.removeItem('activeCompanyId'); | |
document.cookie = `activeCompanyId=`; | |
return router.replace('/login'); | |
}; | |
useWorkerStatus( | |
canI, | |
myPermissions, | |
createClient(), | |
setStatus, | |
setStatusColor, | |
); | |
useEffect(() => { | |
if (!companies.length) return; | |
setReady(true); | |
}, [path, activeCompany, companies]); | |
useEffect(() => { | |
if (!myPermissions.length) return; | |
const asyncFilter = async (arr, predicate) => { | |
const results = await Promise.all(arr.map(predicate)); | |
return arr.filter((_v, index) => results[index]); | |
}; | |
const filterMenuItems = async (items) => { | |
const filteredItems = await asyncFilter(items, async (item) => { | |
if (item.scope) { | |
return canI(item.scope); | |
} | |
return true; | |
}); | |
const itemsWithFilteredChildren = await Promise.all( | |
filteredItems.map(async (item) => { | |
if (!item.children) return item; | |
const filteredChildren = await asyncFilter( | |
item.children, | |
async (child) => { | |
if (child?.scope) { | |
return canI(child?.scope); | |
} | |
return true; | |
}, | |
); | |
const childrenWithFilteredGrandchildren = await Promise.all( | |
filteredChildren.map(async (child) => { | |
if (!child?.children) return child; | |
const filteredGrandchildren = await asyncFilter( | |
child?.children, | |
async (grandchild) => { | |
if (grandchild?.scope) { | |
return canI(grandchild?.scope); | |
} | |
return true; | |
}, | |
); | |
return { | |
...child, | |
children: filteredGrandchildren, | |
}; | |
}), | |
); | |
return { | |
...item, | |
children: childrenWithFilteredGrandchildren, | |
}; | |
}), | |
); | |
return itemsWithFilteredChildren; | |
}; | |
(async () => { | |
const menuItems = buildMenu(__); | |
const filteredItems = await filterMenuItems(menuItems); | |
setItems(filteredItems); | |
})(); | |
setCurrent('/' + path.substring(1)); | |
setReady(true); | |
}, [path, user, router, myPermissions, lang]); | |
const onClick = (e) => { | |
setCurrent(e.key); | |
router.push(e.key); | |
}; | |
return ( | |
ready && ( | |
<div className="noflex"> | |
{/* Sidebar */} | |
<div className="fixed menu-enti left-0 h-full w-52 bg-purple-800 shadow-lg z-50"> | |
{/* Logo container */} | |
<div className="p-4 text-center"> | |
<Link href="/"> | |
<img src="/logo-enti.png" alt="ENTi" className="w-32 mx-auto" /> | |
</Link> | |
{canI(['god', 'Administrador', 'Ver_Estado_Worker']) && ( | |
<Tooltip title={status} placement="right"> | |
<span | |
className="w-5 h-5 rounded-full absolute top-[120px] left-[140px] estado z-10" | |
style={{ backgroundColor: statusColor }} | |
></span> | |
</Tooltip> | |
)} | |
</div> | |
{/* Company selector */} | |
<div className="px-4 mb-4 text-center"> | |
<CompanyMenu /> | |
</div> | |
{/* Navigation menu */} | |
<Menu | |
onClick={onClick} | |
selectedKeys={[current]} | |
mode="inline" | |
items={items} | |
className="bg-purple-800 text-white border-r-0" | |
theme="dark" | |
/> | |
<QuotaProgress | |
className="text-white p-5" | |
style={{ position: 'absolute', bottom: 90, width: 170 }} | |
/> | |
<form | |
action={signOut} | |
className="absolute bottom-2 text-center w-full" | |
> | |
<button className="py-2 px-4 text-white no-underline bg-transparent cursor-pointer"> | |
{__('LOG_OUT')} <LogoutOutlined /> | |
</button> | |
</form> | |
</div> | |
</div> | |
) | |
); | |
}; | |
export default SideMenu; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment