| @@ -83,27 +83,41 @@ const NavigationContent: React.FC = () => { | |||||
| labelKey: "nav.dashboard", | labelKey: "nav.dashboard", | ||||
| path: "/dashboard", | path: "/dashboard", | ||||
| }, | }, | ||||
| { | |||||
| id: "nav.store.purchaseOrder", | |||||
| icon: <LocalShipping />, | |||||
| labelKey: "nav.store.purchaseOrder", | |||||
| requiredAbility: [AUTH.PURCHASE, AUTH.ADMIN], | |||||
| path: "/po", | |||||
| }, | |||||
| { | |||||
| id: "nav.store.pickOrder", | |||||
| icon: <Assignment />, | |||||
| labelKey: "nav.store.pickOrder", | |||||
| requiredAbility: [AUTH.STOCK, AUTH.ADMIN], | |||||
| path: "/pickOrder", | |||||
| }, | |||||
| { | |||||
| id: "nav.store.stockTake", | |||||
| icon: <AssignmentTurnedIn />, | |||||
| labelKey: "nav.store.stockTake", | |||||
| requiredAbility: [AUTH.STOCK, AUTH.STOCK_TAKE, AUTH.ADMIN], | |||||
| path: "/stocktakemanagement", | |||||
| }, | |||||
| { | |||||
| id: "nav.store.putAwayScan", | |||||
| icon: <QrCodeIcon />, | |||||
| labelKey: "nav.store.putAwayScan", | |||||
| requiredAbility: [AUTH.STOCK, AUTH.STOCK_TAKE, AUTH.STOCK_IN_BIND, AUTH.ADMIN], | |||||
| path: "/putAway", | |||||
| }, | |||||
| { | { | ||||
| id: "nav.storeManagement", | id: "nav.storeManagement", | ||||
| icon: <Storefront />, | icon: <Storefront />, | ||||
| labelKey: "nav.storeManagement", | labelKey: "nav.storeManagement", | ||||
| path: "", | path: "", | ||||
| requiredAbility: [AUTH.PURCHASE, AUTH.STOCK, AUTH.STOCK_TAKE, AUTH.STOCK_FG, AUTH.STOCK_IN_BIND, AUTH.ITEM_TRACING, AUTH.ADMIN], | |||||
| requiredAbility: [AUTH.STOCK, AUTH.STOCK_TAKE, AUTH.STOCK_FG, AUTH.STOCK_IN_BIND, AUTH.ITEM_TRACING, AUTH.ADMIN], | |||||
| children: [ | children: [ | ||||
| { | |||||
| id: "nav.store.purchaseOrder", | |||||
| icon: <LocalShipping />, | |||||
| labelKey: "nav.store.purchaseOrder", | |||||
| requiredAbility: [AUTH.PURCHASE, AUTH.ADMIN], | |||||
| path: "/po", | |||||
| }, | |||||
| { | |||||
| id: "nav.store.pickOrder", | |||||
| icon: <Assignment />, | |||||
| labelKey: "nav.store.pickOrder", | |||||
| requiredAbility: [AUTH.STOCK, AUTH.ADMIN], | |||||
| path: "/pickOrder", | |||||
| }, | |||||
| { | { | ||||
| id: "nav.store.inventoryLedger", | id: "nav.store.inventoryLedger", | ||||
| icon: <Inventory />, | icon: <Inventory />, | ||||
| @@ -118,13 +132,6 @@ const NavigationContent: React.FC = () => { | |||||
| requiredAbility: [AUTH.ITEM_TRACING], | requiredAbility: [AUTH.ITEM_TRACING], | ||||
| path: "/itemTracing", | path: "/itemTracing", | ||||
| }, | }, | ||||
| { | |||||
| id: "nav.store.stockTake", | |||||
| icon: <AssignmentTurnedIn />, | |||||
| labelKey: "nav.store.stockTake", | |||||
| requiredAbility: [AUTH.STOCK, AUTH.STOCK_TAKE, AUTH.ADMIN], | |||||
| path: "/stocktakemanagement", | |||||
| }, | |||||
| { | { | ||||
| id: "nav.store.stockIssue", | id: "nav.store.stockIssue", | ||||
| icon: <ReportProblem />, | icon: <ReportProblem />, | ||||
| @@ -132,13 +139,6 @@ const NavigationContent: React.FC = () => { | |||||
| requiredAbility: [AUTH.STOCK, AUTH.STOCK_TAKE, AUTH.ADMIN], | requiredAbility: [AUTH.STOCK, AUTH.STOCK_TAKE, AUTH.ADMIN], | ||||
| path: "/stockIssue", | path: "/stockIssue", | ||||
| }, | }, | ||||
| { | |||||
| id: "nav.store.putAwayScan", | |||||
| icon: <QrCodeIcon />, | |||||
| labelKey: "nav.store.putAwayScan", | |||||
| requiredAbility: [AUTH.STOCK, AUTH.STOCK_TAKE, AUTH.STOCK_IN_BIND, AUTH.ADMIN], | |||||
| path: "/putAway", | |||||
| }, | |||||
| { | { | ||||
| id: "nav.store.finishedGoodManagement", | id: "nav.store.finishedGoodManagement", | ||||
| icon: <ViewModule />, | icon: <ViewModule />, | ||||
| @@ -444,15 +444,12 @@ const NavigationContent: React.FC = () => { | |||||
| const canSeeMasterDataIssueBadge = abilitySet.has(AUTH.ADMIN); | const canSeeMasterDataIssueBadge = abilitySet.has(AUTH.ADMIN); | ||||
| const [openItems, setOpenItems] = React.useState<string[]>([]); | const [openItems, setOpenItems] = React.useState<string[]>([]); | ||||
| /** Keep parent sections expanded on deep links (e.g. /po/edit from nav red spot) so alerts stay visible. */ | |||||
| /** Keep parent sections expanded on deep links so nested alerts stay visible. */ | |||||
| React.useEffect(() => { | React.useEffect(() => { | ||||
| const ensureOpen: string[] = []; | const ensureOpen: string[] = []; | ||||
| if (pathname.startsWith("/chart")) { | if (pathname.startsWith("/chart")) { | ||||
| ensureOpen.push("nav.chartReports"); | ensureOpen.push("nav.chartReports"); | ||||
| } | } | ||||
| if (pathname === "/po" || pathname.startsWith("/po/")) { | |||||
| ensureOpen.push("nav.storeManagement"); | |||||
| } | |||||
| if (pathname === "/productionProcess" || pathname.startsWith("/productionProcess/")) { | if (pathname === "/productionProcess" || pathname.startsWith("/productionProcess/")) { | ||||
| ensureOpen.push("nav.jobOrderManagement"); | ensureOpen.push("nav.jobOrderManagement"); | ||||
| } | } | ||||
| @@ -555,7 +552,47 @@ const NavigationContent: React.FC = () => { | |||||
| return ( | return ( | ||||
| <Box key={item.id}> | <Box key={item.id}> | ||||
| {isLeaf ? ( | |||||
| {isLeaf && item.path === "/po" ? ( | |||||
| <Box | |||||
| sx={{ | |||||
| display: "flex", | |||||
| alignItems: "stretch", | |||||
| mx: 1, | |||||
| borderRadius: 1, | |||||
| overflow: "hidden", | |||||
| "&:hover": { bgcolor: "action.hover" }, | |||||
| }} | |||||
| > | |||||
| <Box | |||||
| component={Link} | |||||
| href={item.path} | |||||
| sx={{ | |||||
| flex: 1, | |||||
| minWidth: 0, | |||||
| textDecoration: "none", | |||||
| color: "inherit", | |||||
| display: "flex", | |||||
| }} | |||||
| > | |||||
| <ListItemButton | |||||
| selected={isSelected} | |||||
| sx={{ | |||||
| flex: 1, | |||||
| py: 1, | |||||
| pr: 0.5, | |||||
| "&.Mui-selected .MuiListItemIcon-root": { color: "primary.main" }, | |||||
| }} | |||||
| > | |||||
| <ListItemIcon sx={{ minWidth: 40 }}>{item.icon}</ListItemIcon> | |||||
| <ListItemText | |||||
| primary={t(item.labelKey)} | |||||
| primaryTypographyProps={{ fontWeight: isSelected ? 600 : 500 }} | |||||
| /> | |||||
| </ListItemButton> | |||||
| </Box> | |||||
| <PurchaseStockInNavAlerts enabled={canSeePoAlerts} /> | |||||
| </Box> | |||||
| ) : isLeaf ? ( | |||||
| <Link href={item.path!} style={{ textDecoration: "none", color: "inherit" }}> | <Link href={item.path!} style={{ textDecoration: "none", color: "inherit" }}> | ||||
| {content} | {content} | ||||
| </Link> | </Link> | ||||
| @@ -566,52 +603,7 @@ const NavigationContent: React.FC = () => { | |||||
| <List sx={{ pl: 2, py: 0 }}> | <List sx={{ pl: 2, py: 0 }}> | ||||
| {item.children.map( | {item.children.map( | ||||
| (child) => !child.isHidden && hasAbility(child.requiredAbility) && ( | (child) => !child.isHidden && hasAbility(child.requiredAbility) && ( | ||||
| child.path === "/po" ? ( | |||||
| <Box | |||||
| key={child.id} | |||||
| sx={{ | |||||
| display: "flex", | |||||
| alignItems: "stretch", | |||||
| mx: 1, | |||||
| borderRadius: 1, | |||||
| overflow: "hidden", | |||||
| "&:hover": { bgcolor: "action.hover" }, | |||||
| }} | |||||
| > | |||||
| <Box | |||||
| component={Link} | |||||
| href={child.path} | |||||
| sx={{ | |||||
| flex: 1, | |||||
| minWidth: 0, | |||||
| textDecoration: "none", | |||||
| color: "inherit", | |||||
| display: "flex", | |||||
| }} | |||||
| > | |||||
| <ListItemButton | |||||
| selected={child.path === selectedLeafPath} | |||||
| sx={{ | |||||
| flex: 1, | |||||
| py: 1, | |||||
| pr: 0.5, | |||||
| "&.Mui-selected .MuiListItemIcon-root": { color: "primary.main" }, | |||||
| }} | |||||
| > | |||||
| <ListItemIcon sx={{ minWidth: 40 }}>{child.icon}</ListItemIcon> | |||||
| <ListItemText | |||||
| primary={t(child.labelKey)} | |||||
| primaryTypographyProps={{ | |||||
| fontWeight: | |||||
| child.path === selectedLeafPath ? 600 : 500, | |||||
| fontSize: "0.875rem", | |||||
| }} | |||||
| /> | |||||
| </ListItemButton> | |||||
| </Box> | |||||
| <PurchaseStockInNavAlerts enabled={canSeePoAlerts} /> | |||||
| </Box> | |||||
| ) : child.path === "/settings/masterDataIssues" ? ( | |||||
| child.path === "/settings/masterDataIssues" ? ( | |||||
| <Box | <Box | ||||
| key={child.id} | key={child.id} | ||||
| component={Link} | component={Link} | ||||