pagamio-frontend-commons-lib
Version:
Pagamio library for Frontend reusable components like the form engine and table container
108 lines (107 loc) • 4.69 kB
JavaScript
'use client';
import { jsx as _jsx } from "react/jsx-runtime";
import { HiChartPie } from 'react-icons/hi';
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import { isUUIDorID } from '../shared';
/**
* Context for managing breadcrumbs in the application.
* Provides breadcrumbs, a function to update breadcrumb labels, and the root page icon.
*/
const AppBreadcrumbContext = createContext(undefined);
/**
* Provider component for the BreadcrumbContext.
* Manages the state and logic for breadcrumbs based on the current pathname.
*
* @param children - The child components to be wrapped by the provider.
* @param pathname - The pathname of the current app route.
* @param pages - The app root pages of the sidebar
*/
const AppBreadcrumbProvider = ({ children, pathname, pages }) => {
const [breadcrumbs, setBreadcrumbs] = useState([]);
const manualUpdates = useRef({}); // Track manual label updates
/**
* Calculates the breadcrumbs based on the current pathname.
* Uses the `pages` configuration to determine labels and paths.
* Preserves manual updates to breadcrumb labels.
*/
const calculatedBreadcrumbs = useMemo(() => {
const pathSegments = pathname.replace(/\/$/, '').split('/').filter(Boolean);
const newBreadcrumbs = [];
let icon = undefined;
if (pathSegments.length === 0) {
return {
icon: HiChartPie,
breadcrumbs: [{ label: 'Dashboard', path: '/dashboard' }],
};
}
let currentPath = '';
pathSegments.forEach((segment) => {
currentPath += `/${segment}`;
const pageConfig = pages.find((page) => page.href === currentPath);
if (pageConfig) {
const label = manualUpdates.current[segment] ?? pageConfig.label; // Use manual update if available
newBreadcrumbs.push({ label, path: currentPath });
if (!icon)
icon = pageConfig.icon;
if (!!pageConfig.items?.length && currentPath === pathname) {
newBreadcrumbs.push({ label: 'List', path: currentPath });
}
}
else if (isUUIDorID(segment)) {
const previousLabel = newBreadcrumbs[newBreadcrumbs.length - 1]?.label;
if (previousLabel) {
const baseLabel = previousLabel.replace(/s$/, '');
const label = manualUpdates.current[segment] ?? `${baseLabel} Details`; // Use manual update if available
newBreadcrumbs.push({
label,
path: currentPath,
key: segment,
});
}
}
else {
const label = manualUpdates.current[segment] ?? segment.charAt(0).toUpperCase() + segment.slice(1); // Use manual update if available
newBreadcrumbs.push({
label,
path: currentPath,
});
}
});
return { icon, breadcrumbs: newBreadcrumbs };
}, [pathname]);
useEffect(() => {
setBreadcrumbs(calculatedBreadcrumbs.breadcrumbs);
}, [calculatedBreadcrumbs.breadcrumbs]);
/**
* Updates the label of a specific breadcrumb identified by its key.
*
* @param key - The key of the breadcrumb to update.
* @param newLabel - The new label to set for the breadcrumb.
*/
const updateBreadcrumb = useCallback((key, newLabel) => {
manualUpdates.current[key] = newLabel; // Store the manual update
setBreadcrumbs((current) => current.map((breadcrumb) => (breadcrumb.key === key ? { ...breadcrumb, label: newLabel } : breadcrumb)));
}, []);
const breadcrumbsContextValue = useMemo(() => ({
breadcrumbs,
updateBreadcrumb,
pathname,
rootPageIcon: calculatedBreadcrumbs.icon,
}), [pathname, breadcrumbs, updateBreadcrumb, calculatedBreadcrumbs.icon]);
return _jsx(AppBreadcrumbContext.Provider, { value: breadcrumbsContextValue, children: children });
};
/**
* Hook to access the BreadcrumbContext.
* Provides access to breadcrumbs, the update function, and the root page icon.
*
* @throws Will throw an error if used outside a BreadcrumbProvider.
*/
const useAppBreadcrumbs = () => {
const context = useContext(AppBreadcrumbContext);
if (!context) {
throw new Error('useBreadcrumbs must be used within a BreadcrumbProvider');
}
return context;
};
export default AppBreadcrumbProvider;
export { useAppBreadcrumbs };