Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

487 строки
16 KiB

  1. import Divider from "@mui/material/Divider";
  2. import Box from "@mui/material/Box";
  3. import React from "react";
  4. import List from "@mui/material/List";
  5. import ListItemButton from "@mui/material/ListItemButton";
  6. import ListItemText from "@mui/material/ListItemText";
  7. import ListItemIcon from "@mui/material/ListItemIcon";
  8. import WorkHistory from "@mui/icons-material/WorkHistory";
  9. import Dashboard from "@mui/icons-material/Dashboard";
  10. import SummarizeIcon from "@mui/icons-material/Summarize";
  11. import PaymentsIcon from "@mui/icons-material/Payments";
  12. import AccountTreeIcon from "@mui/icons-material/AccountTree";
  13. import RequestQuote from "@mui/icons-material/RequestQuote";
  14. import PeopleIcon from "@mui/icons-material/People";
  15. import Task from "@mui/icons-material/Task";
  16. import Assignment from "@mui/icons-material/Assignment";
  17. import Settings from "@mui/icons-material/Settings";
  18. import Analytics from "@mui/icons-material/Analytics";
  19. import Payments from "@mui/icons-material/Payments";
  20. import Staff from "@mui/icons-material/PeopleAlt";
  21. import Company from "@mui/icons-material/Store";
  22. import Department from "@mui/icons-material/Diversity3";
  23. import Position from "@mui/icons-material/Paragliding";
  24. import Salary from "@mui/icons-material/AttachMoney";
  25. import Team from "@mui/icons-material/Paragliding";
  26. import Holiday from "@mui/icons-material/CalendarMonth";
  27. import { useTranslation } from "react-i18next";
  28. import { usePathname } from "next/navigation";
  29. import Link from "next/link";
  30. import { NAVIGATION_CONTENT_WIDTH } from "@/config/uiConfig";
  31. import Logo from "../Logo";
  32. import GroupIcon from "@mui/icons-material/Group";
  33. import BusinessIcon from "@mui/icons-material/Business";
  34. import ViewWeekIcon from "@mui/icons-material/ViewWeek";
  35. import ManageAccountsIcon from "@mui/icons-material/ManageAccounts";
  36. import EmojiEventsIcon from "@mui/icons-material/EmojiEvents";
  37. import FileUploadIcon from '@mui/icons-material/FileUpload';
  38. import EmailIcon from "@mui/icons-material/Email";
  39. import {
  40. IMPORT_INVOICE,
  41. IMPORT_RECEIPT,
  42. MAINTAIN_PROJECT,
  43. MAINTAIN_TASK_TEMPLATE,
  44. MAINTAIN_USER,
  45. VIEW_DASHBOARD_ALL,
  46. VIEW_DASHBOARD_SELF,
  47. VIEW_PROJECT,
  48. VIEW_CLIENT,
  49. VIEW_SUBSIDIARY,
  50. VIEW_STAFF,
  51. VIEW_COMPANY,
  52. VIEW_SKILL,
  53. VIEW_DEPARTMENT,
  54. VIEW_POSITION,
  55. VIEW_SALARY,
  56. VIEW_TEAM,
  57. VIEW_GROUP,
  58. VIEW_HOLIDAY,
  59. MAINTAIN_CLIENT,
  60. MAINTAIN_SUBSIDIARY,
  61. MAINTAIN_STAFF,
  62. MAINTAIN_COMPANY,
  63. MAINTAIN_SKILL,
  64. MAINTAIN_DEPARTMENT,
  65. MAINTAIN_POSITION,
  66. MAINTAIN_SALARY,
  67. MAINTAIN_TEAM,
  68. MAINTAIN_GROUP,
  69. MAINTAIN_HOLIDAY,
  70. VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING,
  71. GENERATE_LATE_START_REPORT,
  72. GENERATE_PROJECT_POTENTIAL_DELAY_REPORT,
  73. GENERATE_RESOURCE_OVERCONSUMPTION_REPORT,
  74. GENERATE_COST_AND_EXPENSE_REPORT,
  75. GENERATE_PROJECT_COMPLETION_REPORT,
  76. GENERATE_PROJECT_PANDL_REPORT,
  77. GENERATE_FINANCIAL_STATUS_REPORT,
  78. GENERATE_PROJECT_CASH_FLOW_REPORT,
  79. GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT,
  80. GENERATE_CROSS_TEAM_CHARGE_REPORT,
  81. VIEW_MAIL,
  82. MAINTAIN_MAIL
  83. } from "@/middleware";
  84. import { SessionWithAbilities } from "../AppBar/NavigationToggle";
  85. import { authOptions } from "@/config/authConfig";
  86. import { getServerSession } from "next-auth";
  87. import useIsMobile from "@/app/utils/useIsMobile";
  88. interface NavigationItem {
  89. icon: React.ReactNode;
  90. label: string;
  91. path: string;
  92. isHidden?: boolean;
  93. showOnMobile?: boolean;
  94. children?: NavigationItem[];
  95. }
  96. interface Props {
  97. abilities?: string[];
  98. username?: string;
  99. }
  100. const NavigationContent: React.FC<Props> = ({ abilities, username }) => {
  101. const navigationItems: NavigationItem[] = [
  102. {
  103. icon: <WorkHistory />,
  104. label: "User Workspace",
  105. path: "/home",
  106. showOnMobile: true,
  107. },
  108. {
  109. icon: <Dashboard />,
  110. label: "Dashboard",
  111. path: "",
  112. isHidden: ![VIEW_DASHBOARD_ALL, VIEW_DASHBOARD_SELF].some((ability) =>
  113. abilities!.includes(ability),
  114. ),
  115. children: [
  116. {
  117. icon: <SummarizeIcon />,
  118. label: "Financial Summary",
  119. path: "/dashboard/ProjectFinancialSummary",
  120. },
  121. {
  122. icon: <PaymentsIcon />,
  123. label: "Company / Team Cash Flow",
  124. path: "/dashboard/CompanyTeamCashFlow",
  125. },
  126. {
  127. icon: <PaymentsIcon />,
  128. label: "Project Cash Flow",
  129. path: "/dashboard/ProjectCashFlow",
  130. },
  131. {
  132. icon: <AccountTreeIcon />,
  133. label: "Project Status by Client",
  134. path: "/dashboard/ProjectStatusByClient",
  135. },
  136. {
  137. icon: <AccountTreeIcon />,
  138. label: "Project Status by Team",
  139. path: "/dashboard/ProjectStatusByTeam",
  140. },
  141. {
  142. icon: <AccountTreeIcon />,
  143. label: "Project Resource Consumption Ranking",
  144. path: "/dashboard/ProjectResourceConsumptionRanking",
  145. isHidden: ![VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING].some((ability) =>
  146. abilities!.includes(ability),
  147. )
  148. },
  149. {
  150. icon: <PeopleIcon />,
  151. label: "Staff Utilization",
  152. path: "/dashboard/StaffUtilization",
  153. },
  154. {
  155. icon: <ViewWeekIcon />,
  156. label: "Project Resource Summary",
  157. path: "/dashboard/ProjectResourceSummary",
  158. },
  159. ],
  160. },
  161. // No Claim function in Breaur, will be implement later
  162. // {
  163. // icon: <RequestQuote />,
  164. // label: "Staff Reimbursement",
  165. // path: "/staffReimbursement",
  166. // children: [
  167. // {
  168. // icon: <RequestQuote />,
  169. // label: "Claim Approval",
  170. // path: "/staffReimbursement/ClaimApproval",
  171. // },
  172. // {
  173. // icon: <RequestQuote />,
  174. // label: "Claim Summary",
  175. // path: "/staffReimbursement/ClaimSummary",
  176. // },
  177. // ],
  178. // },
  179. { icon: <Assignment />, label: "Project Management", path: "/projects", isHidden: ![MAINTAIN_PROJECT].some((ability) => abilities?.includes(ability)) },
  180. { icon: <Task />, label: "Task Template", path: "/tasks", isHidden: ![MAINTAIN_TASK_TEMPLATE].some((ability) => abilities?.includes(ability)) },
  181. {
  182. icon: <Payments />,
  183. label: "Invoice",
  184. path: "/invoice",
  185. isHidden: ![IMPORT_INVOICE, IMPORT_RECEIPT].some((ability) =>
  186. abilities!.includes(ability),
  187. ),
  188. },
  189. {
  190. icon: <Analytics />,
  191. label: "Analysis Report",
  192. path: "",
  193. isHidden: ![
  194. GENERATE_LATE_START_REPORT,
  195. GENERATE_PROJECT_POTENTIAL_DELAY_REPORT,
  196. GENERATE_RESOURCE_OVERCONSUMPTION_REPORT,
  197. GENERATE_COST_AND_EXPENSE_REPORT,
  198. GENERATE_PROJECT_COMPLETION_REPORT,
  199. GENERATE_PROJECT_PANDL_REPORT,
  200. GENERATE_FINANCIAL_STATUS_REPORT,
  201. GENERATE_PROJECT_CASH_FLOW_REPORT,
  202. GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT,
  203. GENERATE_CROSS_TEAM_CHARGE_REPORT
  204. ].some((ability) =>
  205. abilities!.includes(ability),
  206. ),
  207. children: [
  208. {
  209. icon: <Analytics />,
  210. label: "Late Start Report",
  211. path: "/analytics/LateStartReport",
  212. isHidden: ![GENERATE_LATE_START_REPORT].some((ability) =>
  213. abilities!.includes(ability),
  214. ),
  215. },
  216. {
  217. icon: <Analytics />,
  218. label: "Project Potential Delay Report",
  219. path: "/analytics/ProjectPotentialDelayReport",
  220. isHidden: ![GENERATE_PROJECT_POTENTIAL_DELAY_REPORT].some((ability) =>
  221. abilities!.includes(ability),
  222. ),
  223. },
  224. {
  225. icon: <Analytics />,
  226. label: "Resource Overconsumption Report",
  227. path: "/analytics/ResourceOverconsumptionReport",
  228. isHidden: ![GENERATE_RESOURCE_OVERCONSUMPTION_REPORT].some((ability) =>
  229. abilities!.includes(ability),
  230. ),
  231. },
  232. {
  233. icon: <Analytics />,
  234. label: "Cost and Expense Report",
  235. path: "/analytics/CostandExpenseReport",
  236. isHidden: ![GENERATE_COST_AND_EXPENSE_REPORT].some((ability) =>
  237. abilities!.includes(ability),
  238. ),
  239. },
  240. {
  241. icon: <Analytics />,
  242. label: "Project Completion Report",
  243. path: "/analytics/ProjectCompletionReport",
  244. isHidden: ![GENERATE_PROJECT_COMPLETION_REPORT].some((ability) =>
  245. abilities!.includes(ability),
  246. ),
  247. },
  248. // {
  249. // icon: <Analytics />,
  250. // label: "Completion Report with Outstanding Un-billed Hours Report",
  251. // path: "/analytics/ProjectCompletionReportWO",
  252. // },
  253. // {
  254. // icon: <Analytics />,
  255. // label: "Project Claims Report",
  256. // path: "/analytics/ProjectClaimsReport",
  257. // },
  258. {
  259. icon: <Analytics />,
  260. label: "Project P&L Report",
  261. path: "/analytics/ProjectPandLReport",
  262. isHidden: ![GENERATE_PROJECT_COMPLETION_REPORT].some((ability) =>
  263. abilities!.includes(ability),
  264. ),
  265. },
  266. {
  267. icon: <Analytics />,
  268. label: "Financial Status Report",
  269. path: "/analytics/FinancialStatusReport",
  270. isHidden: ![GENERATE_FINANCIAL_STATUS_REPORT].some((ability) =>
  271. abilities!.includes(ability),
  272. ),
  273. },
  274. {
  275. icon: <Analytics />,
  276. label: "Project Cash Flow Report",
  277. path: "/analytics/ProjectCashFlowReport",
  278. isHidden: ![GENERATE_PROJECT_CASH_FLOW_REPORT].some((ability) =>
  279. abilities!.includes(ability),
  280. ),
  281. },
  282. {
  283. icon: <Analytics />,
  284. label: "Staff Monthly Work Hours Analysis Report",
  285. path: "/analytics/StaffMonthlyWorkHoursAnalysisReport",
  286. isHidden: ![GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT].some((ability) =>
  287. abilities!.includes(ability),
  288. ),
  289. },
  290. {
  291. icon: <Analytics />,
  292. label: "Cross Team Charge Report",
  293. path: "/analytics/CrossTeamChargeReport",
  294. isHidden: ![GENERATE_CROSS_TEAM_CHARGE_REPORT].some((ability) =>
  295. abilities!.includes(ability),
  296. ),
  297. },
  298. ],
  299. },
  300. {
  301. icon: <Settings />,
  302. label: "Setting",
  303. path: "",
  304. isHidden: ![
  305. VIEW_CLIENT,
  306. VIEW_SUBSIDIARY,
  307. VIEW_STAFF,
  308. VIEW_COMPANY,
  309. VIEW_SKILL,
  310. VIEW_DEPARTMENT,
  311. VIEW_POSITION,
  312. VIEW_SALARY,
  313. VIEW_TEAM,
  314. VIEW_GROUP,
  315. VIEW_HOLIDAY,
  316. MAINTAIN_CLIENT,
  317. MAINTAIN_SUBSIDIARY,
  318. MAINTAIN_STAFF,
  319. MAINTAIN_COMPANY,
  320. MAINTAIN_SKILL,
  321. MAINTAIN_DEPARTMENT,
  322. MAINTAIN_POSITION,
  323. MAINTAIN_SALARY,
  324. MAINTAIN_TEAM,
  325. MAINTAIN_GROUP,
  326. MAINTAIN_HOLIDAY
  327. ].some((ability) =>
  328. abilities!.includes(ability),
  329. ),
  330. children: [
  331. {
  332. icon: <GroupIcon />,
  333. label: "Client",
  334. path: "/settings/customer",
  335. isHidden: ![VIEW_CLIENT, MAINTAIN_CLIENT].some((ability) => abilities!.includes(ability),),
  336. },
  337. {
  338. icon: <BusinessIcon />,
  339. label: "Subsidiary",
  340. path: "/settings/subsidiary",
  341. isHidden: ![VIEW_SUBSIDIARY, MAINTAIN_SUBSIDIARY].some((ability) => abilities!.includes(ability),),
  342. },
  343. {
  344. icon: <Staff />,
  345. label: "Staff",
  346. path: "/settings/staff",
  347. isHidden: ![VIEW_STAFF, MAINTAIN_STAFF].some((ability) => abilities!.includes(ability),),
  348. },
  349. {
  350. icon: <Company />,
  351. label: "Company",
  352. path: "/settings/company",
  353. isHidden: ![VIEW_COMPANY, MAINTAIN_COMPANY].some((ability) => abilities!.includes(ability),),
  354. },
  355. {
  356. icon: <EmojiEventsIcon />,
  357. label: "Skill",
  358. path: "/settings/skill",
  359. isHidden: ![VIEW_SKILL, MAINTAIN_SKILL].some((ability) => abilities!.includes(ability),),
  360. },
  361. {
  362. icon: <Department />,
  363. label: "Department",
  364. path: "/settings/department",
  365. isHidden: ![VIEW_DEPARTMENT, MAINTAIN_DEPARTMENT].some((ability) => abilities!.includes(ability),),
  366. },
  367. {
  368. icon: <Position />,
  369. label: "Position",
  370. path: "/settings/position",
  371. isHidden: ![VIEW_POSITION, MAINTAIN_POSITION].some((ability) => abilities!.includes(ability),),
  372. },
  373. {
  374. icon: <Salary />,
  375. label: "Salary",
  376. path: "/settings/salary",
  377. isHidden: ![VIEW_SALARY, MAINTAIN_SALARY].some((ability) => abilities!.includes(ability),),
  378. },
  379. {
  380. icon: <Team />,
  381. label: "Team",
  382. path: "/settings/team",
  383. isHidden: ![VIEW_TEAM, MAINTAIN_TEAM].some((ability) => abilities!.includes(ability),),
  384. },
  385. // { icon: <ManageAccountsIcon />, label: "User", path: "/settings/user" },
  386. {
  387. icon: <ManageAccountsIcon />,
  388. label: "User Group",
  389. path: "/settings/group",
  390. isHidden: ![VIEW_GROUP, MAINTAIN_GROUP].some((ability) => abilities!.includes(ability),),
  391. },
  392. {
  393. icon: <Holiday />,
  394. label: "Holiday",
  395. path: "/settings/holiday",
  396. isHidden: ![VIEW_HOLIDAY, MAINTAIN_HOLIDAY].some((ability) => abilities!.includes(ability),),
  397. },
  398. {
  399. icon: <EmailIcon />,
  400. label: "Mail",
  401. path: "/settings/mail",
  402. isHidden: ![VIEW_MAIL, MAINTAIN_MAIL].some((ability) => abilities!.includes(ability),),
  403. },
  404. { icon: <FileUploadIcon />, label: "Import Excel File", path: "/settings/import", isHidden: username !== "2fi" },
  405. ],
  406. },
  407. ];
  408. const isMobile = useIsMobile();
  409. const { t } = useTranslation("common");
  410. const pathname = usePathname();
  411. const [openItems, setOpenItems] = React.useState<string[]>([]);
  412. const toggleItem = (label: string) => {
  413. setOpenItems((prevOpenItems) =>
  414. prevOpenItems.includes(label)
  415. ? prevOpenItems.filter((item) => item !== label)
  416. : [...prevOpenItems, label],
  417. );
  418. };
  419. const renderNavigationItem = (item: NavigationItem) => {
  420. const isOpen = openItems.includes(item.label);
  421. return (
  422. <Box
  423. key={`${item.label}-${item.path}`}
  424. component={Link}
  425. href={item.path}
  426. sx={{ textDecoration: "none", color: "inherit" }}
  427. >
  428. <ListItemButton
  429. selected={pathname.includes(item.label)}
  430. onClick={() => item.children && toggleItem(item.label)}
  431. >
  432. <ListItemIcon>{item.icon}</ListItemIcon>
  433. <ListItemText primary={t(item.label)} />
  434. </ListItemButton>
  435. {item.children && isOpen && (
  436. <List sx={{ pl: 2 }}>
  437. {item.children.map((child) => (!child.isHidden && renderNavigationItem(child)))}
  438. </List>
  439. )}
  440. </Box>
  441. );
  442. };
  443. return (
  444. <Box sx={{ width: NAVIGATION_CONTENT_WIDTH }}>
  445. <Box sx={{ p: 3, display: "flex" }}>
  446. <Logo height={60} />
  447. {/* <button className="float-right bg-transparent border-transparent" >
  448. <ArrowCircleLeftRoundedIcon className="text-slate-400 hover:text-blue-400 hover:cursor-pointer " style={{ fontSize: '35px' }} />
  449. </button> */}
  450. </Box>
  451. <Divider />
  452. <List component="nav">
  453. {navigationItems
  454. .filter(
  455. (item) => !item.isHidden && (isMobile ? item.showOnMobile : true),
  456. )
  457. .map((item) => renderNavigationItem(item))}
  458. {/* {navigationItems.map(({ icon, label, path }, index) => {
  459. return (
  460. <Box
  461. key={`${label}-${index}`}
  462. component={Link}
  463. href={path}
  464. sx={{ textDecoration: "none", color: "inherit" }}
  465. >
  466. <ListItemButton selected={pathname.includes(path)}>
  467. <ListItemIcon>{icon}</ListItemIcon>
  468. <ListItemText primary={t(label)} />
  469. </ListItemButton>
  470. </Box>
  471. );
  472. })} */}
  473. </List>
  474. </Box>
  475. );
  476. };
  477. export default NavigationContent;