| @@ -83,27 +83,41 @@ const NavigationContent: React.FC = () => { | |||
| labelKey: "nav.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", | |||
| icon: <Storefront />, | |||
| labelKey: "nav.storeManagement", | |||
| 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: [ | |||
| { | |||
| 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", | |||
| icon: <Inventory />, | |||
| @@ -118,13 +132,6 @@ const NavigationContent: React.FC = () => { | |||
| requiredAbility: [AUTH.ITEM_TRACING], | |||
| 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", | |||
| icon: <ReportProblem />, | |||
| @@ -132,13 +139,6 @@ const NavigationContent: React.FC = () => { | |||
| requiredAbility: [AUTH.STOCK, AUTH.STOCK_TAKE, AUTH.ADMIN], | |||
| 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", | |||
| icon: <ViewModule />, | |||
| @@ -444,15 +444,12 @@ const NavigationContent: React.FC = () => { | |||
| const canSeeMasterDataIssueBadge = abilitySet.has(AUTH.ADMIN); | |||
| 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(() => { | |||
| const ensureOpen: string[] = []; | |||
| if (pathname.startsWith("/chart")) { | |||
| ensureOpen.push("nav.chartReports"); | |||
| } | |||
| if (pathname === "/po" || pathname.startsWith("/po/")) { | |||
| ensureOpen.push("nav.storeManagement"); | |||
| } | |||
| if (pathname === "/productionProcess" || pathname.startsWith("/productionProcess/")) { | |||
| ensureOpen.push("nav.jobOrderManagement"); | |||
| } | |||
| @@ -555,7 +552,47 @@ const NavigationContent: React.FC = () => { | |||
| return ( | |||
| <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" }}> | |||
| {content} | |||
| </Link> | |||
| @@ -566,52 +603,7 @@ const NavigationContent: React.FC = () => { | |||
| <List sx={{ pl: 2, py: 0 }}> | |||
| {item.children.map( | |||
| (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 | |||
| key={child.id} | |||
| component={Link} | |||