import { createContext, useContext, useState, useEffect } from 'react' import { useNavigate, useLocation } from 'react-router-dom' import PropTypes from 'prop-types' const HistoryContext = createContext() export const HistoryProvider = ({ children }) => { const [navigationHistory, setNavigationHistory] = useState([]) const [currentPosition, setCurrentPosition] = useState(-1) const navigate = useNavigate() const location = useLocation() // Base route names const baseRouteNames = { '/production': 'Production', '/management': 'Management', '/dashboard/production/gcodefiles': 'GCode Files', '/dashboard/management/filaments': 'Filaments', '/dashboard/management/parts': 'Parts', '/dashboard/management/products': 'Products', '/dashboard/management/vendors': 'Vendors', '/dashboard/management/materials': 'Materials' } const getEntityDetails = (pathname, search) => { const searchParams = new URLSearchParams(search) // Handle different entity types if (pathname.includes('/gcodefiles/info')) { const gcodeFileId = searchParams.get('gcodeFileId') return { type: 'gcodefile', id: gcodeFileId, displayName: `GCode File Info${gcodeFileId ? ` (${gcodeFileId})` : ''}` } } if (pathname.includes('/filaments/info')) { const filamentId = searchParams.get('filamentId') return { type: 'filament', id: filamentId, displayName: `Filament Info${filamentId ? ` (${filamentId})` : ''}` } } if (pathname.includes('/parts/info')) { const partId = searchParams.get('partId') return { type: 'part', id: partId, displayName: `Part Info${partId ? ` (${partId})` : ''}` } } if (pathname.includes('/products/info')) { const productId = searchParams.get('productId') return { type: 'product', id: productId, displayName: `Product Info${productId ? ` (${productId})` : ''}` } } if (pathname.includes('/vendors/info')) { const vendorId = searchParams.get('vendorId') return { type: 'vendor', id: vendorId, displayName: `Vendor Info${vendorId ? ` (${vendorId})` : ''}` } } if (pathname.includes('/materials/info')) { const materialId = searchParams.get('materialId') return { type: 'material', id: materialId, displayName: `Material Info${materialId ? ` (${materialId})` : ''}` } } // For base routes, return the simple name const baseName = baseRouteNames[pathname] if (baseName) { return { type: 'base', displayName: baseName } } return null } // Track location changes useEffect(() => { const newPath = location.pathname const details = getEntityDetails(location.pathname, location.search) if ( newPath === '/dashboard/production/gcodefiles' || newPath === '/dashboard/management/filaments' || newPath === '/dashboard/management/materials' ) { setNavigationHistory([ { path: newPath + location.search, details, timestamp: new Date().toISOString() } ]) setCurrentPosition(0) } else if (details) { setNavigationHistory((prev) => { const newHistory = prev.slice(0, currentPosition + 1) return [ ...newHistory, { path: newPath + location.search, details, timestamp: new Date().toISOString() } ] }) setCurrentPosition((prev) => prev + 1) } }, [location]) const goBack = () => { if (currentPosition > 0) { setCurrentPosition((prev) => prev - 1) navigate(-1) } } const goForward = () => { if (currentPosition < navigationHistory.length - 1) { setCurrentPosition((prev) => prev + 1) navigate(1) } } const getBreadcrumbItems = () => { // If there's no history, return empty array if (navigationHistory.length === 0) return [] // Get current location const currentItem = navigationHistory[currentPosition] if (!currentItem) return [] const pathParts = currentItem.path.split('/') const breadcrumbs = [] // Build up breadcrumbs including parent routes if (pathParts[1]) { // First level (e.g. /production or /management) const firstLevelPath = '/' + pathParts[1] breadcrumbs.push({ path: firstLevelPath, title: baseRouteNames[firstLevelPath] }) } if (pathParts[2]) { // Second level (e.g. /dashboard/production/gcodefiles) const secondLevelPath = '/' + pathParts[1] + '/' + pathParts[2].split('?')[0] breadcrumbs.push({ path: currentItem.path, title: baseRouteNames[secondLevelPath] || currentItem.details.displayName }) } // Add the entity detail level if it exists (e.g. specific gcodefile, filament, etc) if (currentItem.details.type !== 'base') { breadcrumbs.push({ path: currentItem.path, title: currentItem.details.displayName }) } return breadcrumbs } const canGoBack = currentPosition > 0 const canGoForward = currentPosition < navigationHistory.length - 1 return ( {children} ) } export const useHistory = () => { const context = useContext(HistoryContext) if (!context) { throw new Error('useHistory must be used within a HistoryProvider') } return context } HistoryProvider.propTypes = { children: PropTypes.node.isRequired } export default HistoryContext