FPSMS-frontend
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

NavigationContent.tsx 12 KiB

před 11 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 3 týdny
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 4 měsíci
před 11 měsíci
před 11 měsíci
před 6 měsíci
před 11 měsíci
před 7 měsíci
před 11 měsíci
před 8 měsíci
před 11 měsíci
před 3 měsíci
před 4 týdny
před 2 měsíci
před 5 měsíci
před 5 měsíci
před 5 měsíci
před 11 měsíci
před 11 měsíci
před 7 měsíci
před 11 měsíci
před 7 měsíci
před 11 měsíci
před 2 měsíci
před 2 měsíci
před 2 měsíci
před 2 měsíci
před 4 měsíci
před 4 měsíci
před 4 měsíci
před 2 měsíci
před 4 týdny
před 3 týdny
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 7 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 6 měsíci
před 8 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
před 11 měsíci
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;