Files
jobtrackingapp/vendor/saasable-ui-main/admin/nextjs/src/components/Breadcrumbs.jsx
T
2026-03-21 11:55:27 +01:00

110 lines
3.5 KiB
React

'use client';
import { Activity, useEffect, useState } from 'react';
// @next
import Link from 'next/link';
import { usePathname } from 'next/navigation';
// @mui
import { useTheme } from '@mui/material/styles';
import MuiBreadcrumbs from '@mui/material/Breadcrumbs';
import Typography from '@mui/material/Typography';
// @project
import { APP_DEFAULT_PATH } from '@/config';
import menuItems from '@/menu';
import { useGetBreadcrumbsMaster } from '@/states/breadcrumbs';
import { generateFocusStyle } from '@/utils/generateFocusStyle';
// @assets
import { IconChevronRight } from '@tabler/icons-react';
// @data
const homeBreadcrumb = { title: 'Home', url: APP_DEFAULT_PATH };
/*************************** BREADCRUMBS ***************************/
export default function Breadcrumbs() {
const theme = useTheme();
const location = usePathname();
const { breadcrumbsMaster } = useGetBreadcrumbsMaster();
const [breadcrumbItems, setBreadcrumbItems] = useState([]);
const [activeItem, setActiveItem] = useState();
useEffect(() => {
if (breadcrumbsMaster && breadcrumbsMaster.data?.length && breadcrumbsMaster.activePath === location) {
dataHandler(breadcrumbsMaster.data);
} else {
for (const menu of menuItems?.items) {
if (menu.type && menu.type === 'group') {
const matchedParents = findParentElements(menu.children || [], location);
dataHandler(matchedParents || []);
if (matchedParents) break;
}
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [breadcrumbsMaster, location]);
const dataHandler = (data) => {
const active = data.at(-1);
const linkItems = data.slice(0, -1);
if (active && active.url != homeBreadcrumb.url) {
linkItems.unshift(homeBreadcrumb);
}
setActiveItem(active);
setBreadcrumbItems(linkItems);
};
function findParentElements(navItems, targetUrl, parents = []) {
for (const item of navItems) {
// Add the current item to the parents array
const newParents = [...parents, item];
// Check if the current item matches the target URL
if (item.url && targetUrl.includes(item.url)) {
return newParents; // Return the array of parent elements
}
// If the item has children, recurse into them
if (item.children) {
const result = findParentElements(item.children, targetUrl, newParents);
if (result) {
return result; // Return the result if found in children
}
}
}
return null; // Return null if no match is found
}
return (
<MuiBreadcrumbs aria-label="breadcrumb" separator={<IconChevronRight size={16} />}>
{breadcrumbItems.length &&
breadcrumbItems.map((item, index) => (
<Typography
{...(item.url && { component: Link, href: item.url })}
variant="body2"
sx={{
p: 0.5,
color: 'grey.700',
textDecoration: 'none',
...(item.url && { cursor: 'pointer', ':hover': { color: 'primary.main' } }),
':focus-visible': { outline: 'none', borderRadius: 0.25, ...generateFocusStyle(theme.vars.palette.primary.main) }
}}
key={index}
>
{item.title}
</Typography>
))}
<Activity mode={activeItem ? 'visible' : 'hidden'}>
<Typography variant="body2" sx={{ p: 0.5 }}>
{activeItem?.title}
</Typography>
</Activity>
</MuiBreadcrumbs>
);
}