UNPKG

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
'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 };