FPSMS-frontend
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

NavigationContent.tsx 12 KiB

há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 3 semanas
há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 4 meses
há 11 meses
há 11 meses
há 6 meses
há 11 meses
há 7 meses
há 11 meses
há 8 meses
há 11 meses
há 3 meses
há 4 semanas
há 2 meses
há 5 meses
há 5 meses
há 5 meses
há 11 meses
há 11 meses
há 11 meses
há 7 meses
há 11 meses
há 2 meses
há 2 meses
há 2 meses
há 2 meses
há 4 meses
há 4 meses
há 4 meses
há 2 meses
há 4 semanas
há 3 semanas
há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 6 meses
há 8 meses
há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 11 meses
há 11 meses
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;