25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

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