FPSMS-frontend
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

NavigationContent.tsx 12 KiB

пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 3 недеља
пре 3 недеља
пре 11 месеци
пре 3 недеља
пре 11 месеци
пре 11 месеци
пре 7 месеци
пре 11 месеци
пре 4 месеци
пре 11 месеци
пре 11 месеци
пре 6 месеци
пре 11 месеци
пре 7 месеци
пре 11 месеци
пре 8 месеци
пре 11 месеци
пре 3 месеци
пре 4 недеља
пре 2 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 5 месеци
пре 11 месеци
пре 11 месеци
пре 7 месеци
пре 11 месеци
пре 7 месеци
пре 11 месеци
пре 2 месеци
пре 7 месеци
пре 2 месеци
пре 2 месеци
пре 2 месеци
пре 4 месеци
пре 4 месеци
пре 4 месеци
пре 2 месеци
пре 4 недеља
пре 3 недеља
пре 3 недеља
пре 3 недеља
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 7 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 6 месеци
пре 8 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 11 месеци
пре 7 месеци
пре 11 месеци
пре 11 месеци
пре 3 недеља
пре 11 месеци
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. import { useSession } from "next-auth/react";
  2. import Divider from "@mui/material/Divider";
  3. import Box from "@mui/material/Box";
  4. import React, { useEffect } from "react";
  5. import List from "@mui/material/List";
  6. import ListItemButton from "@mui/material/ListItemButton";
  7. import ListItemText from "@mui/material/ListItemText";
  8. import ListItemIcon from "@mui/material/ListItemIcon";
  9. import WorkHistory from "@mui/icons-material/WorkHistory";
  10. import Dashboard from "@mui/icons-material/Dashboard";
  11. import SummarizeIcon from "@mui/icons-material/Summarize";
  12. import PaymentsIcon from "@mui/icons-material/Payments";
  13. import AccountTreeIcon from "@mui/icons-material/AccountTree";
  14. import RequestQuote from "@mui/icons-material/RequestQuote";
  15. import PeopleIcon from "@mui/icons-material/People";
  16. import Task from "@mui/icons-material/Task";
  17. import Assignment from "@mui/icons-material/Assignment";
  18. import Settings from "@mui/icons-material/Settings";
  19. import Analytics from "@mui/icons-material/Analytics";
  20. import Payments from "@mui/icons-material/Payments";
  21. import QrCodeIcon from "@mui/icons-material/QrCode";
  22. import { useTranslation } from "react-i18next";
  23. import Typography from "@mui/material/Typography";
  24. import { usePathname } from "next/navigation";
  25. import Link from "next/link";
  26. import { NAVIGATION_CONTENT_WIDTH } from "@/config/uiConfig";
  27. import Logo from "../Logo";
  28. import BugReportIcon from "@mui/icons-material/BugReport";
  29. import {
  30. VIEW_USER,
  31. MAINTAIN_USER,
  32. VIEW_GROUP,
  33. MAINTAIN_GROUP,
  34. // Add more authorities as needed, e.g.:
  35. TESTING, PROD, PACK, ADMIN, STOCK, Driver
  36. } from "../../authorities";
  37. interface NavigationItem {
  38. icon: React.ReactNode;
  39. label: string;
  40. path: string;
  41. children?: NavigationItem[];
  42. isHidden?: boolean | undefined;
  43. requiredAbility?: string | string[];
  44. }
  45. const NavigationContent: React.FC = () => {
  46. const { data: session, status } = useSession();
  47. const abilities = session?.user?.abilities ?? [];
  48. // Helper: check if user has required permission
  49. const hasAbility = (required?: string | string[]): boolean => {
  50. if (!required) return true; // no requirement → always show
  51. if (Array.isArray(required)) {
  52. return required.some(ability => abilities.includes(ability));
  53. }
  54. return abilities.includes(required);
  55. };
  56. const navigationItems: NavigationItem[] = [
  57. {
  58. icon: <Dashboard />,
  59. label: "Dashboard",
  60. path: "/dashboard",
  61. },
  62. {
  63. icon: <RequestQuote />,
  64. label: "Store Management",
  65. path: "",
  66. children: [
  67. {
  68. icon: <RequestQuote />,
  69. label: "Purchase Order",
  70. path: "/po",
  71. },
  72. {
  73. icon: <RequestQuote />,
  74. label: "Pick Order",
  75. path: "/pickOrder",
  76. },
  77. // {
  78. // icon: <RequestQuote />,
  79. // label: "Cons. Pick Order",
  80. // path: "",
  81. // },
  82. // {
  83. // icon: <RequestQuote />,
  84. // label: "Delivery Pick Order",
  85. // path: "",
  86. // },
  87. // {
  88. // icon: <RequestQuote />,
  89. // label: "Warehouse",
  90. // path: "",
  91. // },
  92. // {
  93. // icon: <RequestQuote />,
  94. // label: "Location Transfer Order",
  95. // path: "",
  96. // },
  97. {
  98. icon: <RequestQuote />,
  99. label: "View item In-out And inventory Ledger",
  100. path: "/inventory",
  101. },
  102. {
  103. icon: <RequestQuote />,
  104. label: "Stock Take Management",
  105. path: "/stocktakemanagement",
  106. },
  107. {
  108. icon: <RequestQuote />,
  109. label: "Stock Issue",
  110. path: "/stockIssue",
  111. },
  112. //TODO: anna
  113. // {
  114. // icon: <RequestQuote />,
  115. // label: "Stock Issue",
  116. // path: "/stockIssue",
  117. // },
  118. {
  119. icon: <RequestQuote />,
  120. label: "Put Away Scan",
  121. path: "/putAway",
  122. },
  123. {
  124. icon: <RequestQuote />,
  125. label: "Finished Good Order",
  126. path: "/finishedGood",
  127. },
  128. ],
  129. },
  130. {
  131. icon: <RequestQuote />,
  132. label: "Delivery",
  133. path: "",
  134. //requiredAbility: VIEW_DO,
  135. children: [
  136. {
  137. icon: <RequestQuote />,
  138. label: "Delivery Order",
  139. path: "/do",
  140. },
  141. ],
  142. },
  143. // {
  144. // icon: <RequestQuote />,
  145. // label: "Report",
  146. // path: "",
  147. // children: [
  148. // {
  149. // icon: <RequestQuote />,
  150. // label: "report",
  151. // path: "",
  152. // },
  153. // ],
  154. // },
  155. // {
  156. // icon: <RequestQuote />,
  157. // label: "Recipe",
  158. // path: "",
  159. // children: [
  160. // {
  161. // icon: <RequestQuote />,
  162. // label: "FG Recipe",
  163. // path: "",
  164. // },
  165. // {
  166. // icon: <RequestQuote />,
  167. // label: "SFG Recipe",
  168. // path: "",
  169. // },
  170. // {
  171. // icon: <RequestQuote />,
  172. // label: "Recipe",
  173. // path: "",
  174. // },
  175. // ],
  176. // },
  177. {
  178. icon: <RequestQuote />,
  179. label: "Scheduling",
  180. path: "",
  181. children: [
  182. {
  183. icon: <RequestQuote />,
  184. label: "Demand Forecast",
  185. path: "/scheduling/rough",
  186. },
  187. {
  188. icon: <RequestQuote />,
  189. label: "Detail Scheduling",
  190. path: "/scheduling/detailed",
  191. },
  192. /*
  193. {
  194. icon: <RequestQuote />,
  195. label: "Production",
  196. path: "/production",
  197. },
  198. */
  199. ],
  200. },
  201. {
  202. icon: <RequestQuote />,
  203. label: "Management Job Order",
  204. path: "",
  205. children: [
  206. {
  207. icon: <RequestQuote />,
  208. label: "Search Job Order/ Create Job Order",
  209. path: "/jo",
  210. },
  211. {
  212. icon: <RequestQuote />,
  213. label: "Job Order Pickexcution",
  214. path: "/jodetail",
  215. },
  216. {
  217. icon: <RequestQuote />,
  218. label: "Job Order Production Process",
  219. path: "/productionProcess",
  220. },
  221. {
  222. icon: <RequestQuote />,
  223. label: "Bag Usage",
  224. path: "/bag",
  225. },
  226. ],
  227. },
  228. {
  229. icon: <BugReportIcon />,
  230. label: "PS",
  231. path: "/ps",
  232. requiredAbility: TESTING,
  233. isHidden: false,
  234. },
  235. {
  236. icon: <BugReportIcon />,
  237. label: "Printer Testing",
  238. path: "/testing",
  239. requiredAbility: TESTING,
  240. isHidden: false,
  241. },
  242. {
  243. icon: <RequestQuote />,
  244. label: "Settings",
  245. path: "",
  246. requiredAbility: [VIEW_USER, VIEW_GROUP],
  247. children: [
  248. {
  249. icon: <RequestQuote />,
  250. label: "User",
  251. path: "/settings/user",
  252. requiredAbility: VIEW_USER,
  253. },
  254. {
  255. icon: <RequestQuote />,
  256. label: "User Group",
  257. path: "/settings/user",
  258. requiredAbility: VIEW_GROUP,
  259. },
  260. // {
  261. // icon: <RequestQuote />,
  262. // label: "Material",
  263. // path: "/settings/material",
  264. // },
  265. // {
  266. // icon: <RequestQuote />,
  267. // label: "By-product",
  268. // path: "/settings/byProduct",
  269. // },
  270. {
  271. icon: <RequestQuote />,
  272. label: "Items",
  273. path: "/settings/items",
  274. },
  275. {
  276. icon: <RequestQuote />,
  277. label: "ShopAndTruck",
  278. path: "/settings/shop",
  279. },
  280. {
  281. icon: <RequestQuote />,
  282. label: "Demand Forecast Setting",
  283. path: "/settings/rss",
  284. },
  285. //{
  286. // icon: <RequestQuote />,
  287. // label: "Equipment Type",
  288. // path: "/settings/equipmentType",
  289. //},
  290. {
  291. icon: <RequestQuote />,
  292. label: "Equipment",
  293. path: "/settings/equipment",
  294. },
  295. {
  296. icon: <RequestQuote />,
  297. label: "Warehouse",
  298. path: "/settings/warehouse",
  299. },
  300. {
  301. icon: <RequestQuote />,
  302. label: "Supplier",
  303. path: "/settings/user",
  304. },
  305. {
  306. icon: <RequestQuote />,
  307. label: "Customer",
  308. path: "/settings/user",
  309. },
  310. {
  311. icon: <RequestQuote />,
  312. label: "QC Check Item",
  313. path: "/settings/qcItem",
  314. },
  315. {
  316. icon: <RequestQuote />,
  317. label: "QC Category",
  318. path: "/settings/qcCategory",
  319. },
  320. {
  321. icon: <RequestQuote />,
  322. label: "QC Check Template",
  323. path: "/settings/user",
  324. },
  325. {
  326. icon: <QrCodeIcon />,
  327. label: "QR Code Handle",
  328. path: "/settings/qrCodeHandle",
  329. },
  330. // {
  331. // icon: <RequestQuote />,
  332. // label: "Mail",
  333. // path: "/settings/mail",
  334. // },
  335. {
  336. icon: <RequestQuote />,
  337. label: "Import Testing",
  338. path: "/settings/m18ImportTesting",
  339. },
  340. {
  341. icon: <RequestQuote />,
  342. label: "Import Excel",
  343. path: "/settings/importExcel",
  344. },
  345. ],
  346. },
  347. ];
  348. const { t } = useTranslation("common");
  349. const pathname = usePathname();
  350. const [openItems, setOpenItems] = React.useState<string[]>([]);
  351. const toggleItem = (label: string) => {
  352. setOpenItems((prevOpenItems) =>
  353. prevOpenItems.includes(label)
  354. ? prevOpenItems.filter((item) => item !== label)
  355. : [...prevOpenItems, label],
  356. );
  357. };
  358. const renderNavigationItem = (item: NavigationItem) => {
  359. if (!hasAbility(item.requiredAbility)) {
  360. return null;
  361. }
  362. const isOpen = openItems.includes(item.label);
  363. const hasVisibleChildren = item.children?.some(child => hasAbility(child.requiredAbility));
  364. return (
  365. <Box
  366. key={`${item.label}-${item.path}`}
  367. component={Link}
  368. href={item.path}
  369. sx={{ textDecoration: "none", color: "inherit" }}
  370. >
  371. <ListItemButton
  372. selected={pathname.includes(item.label)}
  373. onClick={() => item.children && toggleItem(item.label)}
  374. >
  375. <ListItemIcon>{item.icon}</ListItemIcon>
  376. <ListItemText primary={t(item.label)} />
  377. </ListItemButton>
  378. {item.children && isOpen && hasVisibleChildren && (
  379. <List sx={{ pl: 2 }}>
  380. {item.children.map(
  381. (child) => !child.isHidden && renderNavigationItem(child),
  382. )}
  383. </List>
  384. )}
  385. </Box>
  386. );
  387. };
  388. if (status === "loading") {
  389. return <Box sx={{ width: NAVIGATION_CONTENT_WIDTH, p: 3 }}>Loading...</Box>;
  390. }
  391. return (
  392. <Box sx={{ width: NAVIGATION_CONTENT_WIDTH }}>
  393. <Box sx={{ p: 3, display: "flex" }}>
  394. <Logo height={60} />
  395. {/* <button className="float-right bg-transparent border-transparent" >
  396. <ArrowCircleLeftRoundedIcon className="text-slate-400 hover:text-blue-400 hover:cursor-pointer " style={{ fontSize: '35px' }} />
  397. </button> */}
  398. </Box>
  399. <Divider />
  400. <List component="nav">
  401. {navigationItems
  402. .filter(item => !item.isHidden)
  403. .map(renderNavigationItem)
  404. .filter(Boolean)}
  405. {/* {navigationItems.map(({ icon, label, path }, index) => {
  406. return (
  407. <Box
  408. key={`${label}-${index}`}
  409. component={Link}
  410. href={path}
  411. sx={{ textDecoration: "none", color: "inherit" }}
  412. >
  413. <ListItemButton selected={pathname.includes(path)}>
  414. <ListItemIcon>{icon}</ListItemIcon>
  415. <ListItemText primary={t(label)} />
  416. </ListItemButton>
  417. </Box>
  418. );
  419. })} */}
  420. </List>
  421. </Box>
  422. );
  423. };
  424. export default NavigationContent;