Skip to content

Instantly share code, notes, and snippets.

@voltuer
Created April 10, 2025 20:00
Show Gist options
  • Save voltuer/df0f3d3843a64a3cefdd81176b6a572f to your computer and use it in GitHub Desktop.
Save voltuer/df0f3d3843a64a3cefdd81176b6a572f to your computer and use it in GitHub Desktop.
menu.js
'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