import { PureComponent, createElement } from 'react'; import Badge from '@mui/material/Badge'; import Inventory2Icon from '@mui/icons-material/Inventory2'; import LocalShippingIcon from '@mui/icons-material/LocalShipping'; import AssignmentIcon from '@mui/icons-material/Assignment'; import PeopleIcon from '@mui/icons-material/People'; import InfoIcon from '@mui/icons-material/Info'; import ViewListIcon from '@mui/icons-material/ViewList'; import CategoryIcon from '@mui/icons-material/Category'; import GridViewIcon from '@mui/icons-material/GridView'; import WarehouseIcon from '@mui/icons-material/Warehouse'; import CopyrightIcon from '@mui/icons-material/Copyright'; import ListAltIcon from '@mui/icons-material/ListAlt'; import GroupsIcon from '@mui/icons-material/Groups'; import AddBoxIcon from '@mui/icons-material/AddBox'; import StorefrontIcon from '@mui/icons-material/Storefront'; import RequestQuoteIcon from '@mui/icons-material/RequestQuote'; import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'; import LabelIcon from '@mui/icons-material/Label'; import HistoryIcon from '@mui/icons-material/History'; import PublicIcon from '@mui/icons-material/Public'; import BarChartIcon from '@mui/icons-material/BarChart'; import { isKategorienPath } from './components/category/categoryRoute'; import { deliveryEditorAutomat } from './automats/deliveryEditorAutomat'; class DeliveryNavIcon extends PureComponent { constructor(props) { super(props); const state = deliveryEditorAutomat.state; const isDraft = state.id == null && state.deliveryId == null; this.state = { hasDraft: isDraft && (state.lines?.length || 0) > 0, }; } componentDidMount() { this.unsub = deliveryEditorAutomat.subscribe(this, (state) => { const isDraft = state.id == null && state.deliveryId == null; return { hasDraft: isDraft && (state.lines?.length || 0) > 0, }; }); } componentWillUnmount() { this.unsub?.(); } render() { const { hasDraft } = this.state; const { sx, ...rest } = this.props; return createElement(LocalShippingIcon, { ...rest, sx: [ ...(Array.isArray(sx) ? sx : sx ? [sx] : []), (theme) => (hasDraft ? { color: theme.nav?.itemActiveAccent || '#2dd4bf' } : null), ], }); } } export const NAV_ITEMS = [ { path: '/artikel', label: 'Artikel', icon: Inventory2Icon, help: 'Artikelübersicht, Stammdaten, Barcodes und Bestandsverwaltung', }, { path: '/lieferung', label: 'Lieferung', icon: DeliveryNavIcon, help: 'Wareneingänge verwalten, Lieferungen buchen und Lieferscheine erfassen', }, { path: '/auftrag', label: 'Auftrag', icon: AssignmentIcon, help: 'Kundenangebote kalkulieren und Bestellungen abwickeln', }, { path: '/kunde', label: 'Kunde', icon: PeopleIcon, help: 'Kundenstammdaten, Adressen, Ansprechpartner und Kundengruppen', }, { path: '/infos', label: 'Infos', icon: InfoIcon, help: 'Systemstatus, Serververbindung und Mandanteneinstellungen', }, ]; class DeliveryNeuIcon extends PureComponent { constructor(props) { super(props); const state = deliveryEditorAutomat.state; const isDraft = state.id == null && state.deliveryId == null; this.state = { badgeCount: isDraft ? (state.lines?.length || 0) : 0, }; } componentDidMount() { this.unsub = deliveryEditorAutomat.subscribe(this, (state) => { const isDraft = state.id == null && state.deliveryId == null; return { badgeCount: isDraft ? (state.lines?.length || 0) : 0, }; }); } componentWillUnmount() { this.unsub?.(); } render() { return createElement( Badge, { badgeContent: this.state.badgeCount, invisible: !this.state.badgeCount, color: 'primary', max: 999, }, createElement(AddBoxIcon, this.props) ); } } export const SUB_NAV = { '/artikel': [ { segment: '', label: 'Liste', title: 'Artikel', icon: ViewListIcon, help: 'Gesamtliste aller Artikel durchsuchen, filtern und öffnen', }, { segment: 'kategorien', label: 'Kategorieen', title: 'Kategorien', icon: GridViewIcon, help: 'Hierarchischer Kategoriebaum zur Sortimentsgliederung', }, { segment: 'lager', label: 'Lager', icon: WarehouseIcon, help: 'Lagerbestände einsehen, Bestandsabgleiche und Lagerplatzverwaltung', }, { segment: 'marken', label: 'Marken', icon: CopyrightIcon, help: 'Katalog aller Hersteller und Marken verwalten', }, { segment: 'vorlagen', label: 'Vorlagen', icon: LabelIcon, help: 'Druckvorlagen für Etiketten und Barcodes bearbeiten', }, { segment: 'merkmale', label: 'Merkmale', title: 'Merkmale & Attribute', icon: CategoryIcon, help: 'Globale Merkmale, Attribute und Werte verwalten', }, ], '/lieferung': [ { segment: '', label: 'Liste', title: 'Lieferungen', icon: ListAltIcon, help: 'Historie und Status aller Wareneingänge und Lieferungen', }, { segment: 'neu', label: 'Neu', title: 'Neue Lieferung', icon: DeliveryNeuIcon, help: 'Neuen Wareneingang mit Belegscan und Positionserfassung buchen', }, { segment: 'lieferanten', label: 'Lieferanten', icon: StorefrontIcon, help: 'Lieferantenverzeichnis mit hinterlegten Katalogen und Konditionen', }, ], '/auftrag': [ { segment: '', label: 'Angebot', title: 'Angebot', icon: RequestQuoteIcon, help: 'Angebote für Kunden kalkulieren und versenden', }, { segment: 'bestellung', label: 'Bestellung', title: 'Bestellung', icon: ShoppingCartIcon, help: 'Bestellungen prüfen, freigeben und kommissionieren', }, ], '/kunde': [ { segment: '', label: 'Liste', title: 'Kundenliste', icon: PeopleIcon, help: 'Kundenkartei mit Kontaktdaten und Historie', }, { segment: 'neu', label: 'neu', title: 'Neuer Kunde', icon: AddBoxIcon, help: 'Neuen Kundenstamm mit Anschriften anlegen', }, { segment: 'gruppen', label: 'Gruppen', title: 'Gruppen', icon: GroupsIcon, help: 'Kundengruppen für Staffelpreise und Rabatte verwalten', }, ], '/infos': [ { segment: '', label: 'ArticleHistory', title: 'ArticleHistory', icon: HistoryIcon, help: 'Historie aller Artikeländerungen und Ereignisse', }, { segment: 'globalhistory', label: 'GlobalHistory', title: 'GlobalHistory', icon: PublicIcon, help: 'Globale System- und Änderungshistorie', }, { segment: 'statistics', label: 'Statistics', title: 'Statistics', icon: BarChartIcon, help: 'Statistische Auswertungen und Kennzahlen', }, ], }; export function isNavItemActive(pathname, navPath) { if (navPath === '/artikel') { return ( pathname === navPath || pathname.startsWith(`${navPath}/`) || isKategorienPath(pathname) ); } return pathname === navPath || pathname.startsWith(`${navPath}/`); } /** Stable across article tab changes (e.g. always `/artikel`). */ export function resolveActiveNav(pathname) { for (const item of NAV_ITEMS) { if (isNavItemActive(pathname, item.path)) return item.path; } return null; } /** * Active sub-nav segment for a section. * `''` = section index, `null` = none (e.g. article / kunde detail). */ export function resolveActiveSub(pathname, sectionPath) { const subNav = SUB_NAV[sectionPath]; if (!subNav) return null; const knownSegments = new Set(subNav.map((item) => item.segment).filter(Boolean)); const rest = pathname.slice(sectionPath.length).replace(/^\//, '').split('/')[0]; const isArticleDetail = sectionPath === '/artikel' && !isKategorienPath(pathname) && rest && !knownSegments.has(rest); const isKundeDetail = sectionPath === '/kunde' && rest && !knownSegments.has(rest); const isLieferungDetail = sectionPath === '/lieferung' && rest && !knownSegments.has(rest); // Angebot neu/edit: /auftrag/neu or /auftrag/:quoteId (not a known sub) const isAngebotDoc = sectionPath === '/auftrag' && rest && !knownSegments.has(rest); if (isArticleDetail || isKundeDetail || isLieferungDetail || isAngebotDoc) { return null; } // Keep Bestellung active for nested paths (e.g. /auftrag/bestellung/neu). if (sectionPath === '/auftrag' && rest && knownSegments.has(rest)) { return rest; } // Treat /infos/articlehistory as segment '' if (sectionPath === '/infos' && rest === 'articlehistory') { return ''; } const active = subNav.find((item) => { if (item.segment === 'kategorien') { return isKategorienPath(pathname); } const subPath = item.segment ? `${sectionPath}/${item.segment}` : sectionPath; return pathname === subPath || pathname === `${subPath}/`; }); return active ? active.segment : null; }