Tom Butcher 6870320ab4
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
Implemented materials.
2026-03-08 01:28:09 +00:00

214 lines
5.8 KiB
JavaScript

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 (
<HistoryContext.Provider
value={{
navigationHistory,
currentPosition,
goBack,
goForward,
canGoBack,
canGoForward,
getBreadcrumbItems
}}
>
{children}
</HistoryContext.Provider>
)
}
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