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.
 
 

325 lines
10 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 {
  38. GENERATE_REPORTS,
  39. IMPORT_INVOICE,
  40. IMPORT_RECEIPT,
  41. MAINTAIN_MASTERDATA,
  42. MAINTAIN_PROJECT,
  43. MAINTAIN_TASK_TEMPLATE,
  44. MAINTAIN_USER,
  45. VIEW_DASHBOARD_ALL,
  46. VIEW_DASHBOARD_SELF,
  47. VIEW_MASTERDATA,
  48. VIEW_PROJECT,
  49. VIEW_USER,
  50. } from "@/middleware";
  51. import { SessionWithAbilities } from "../AppBar/NavigationToggle";
  52. import { authOptions } from "@/config/authConfig";
  53. import { getServerSession } from "next-auth";
  54. import useIsMobile from "@/app/utils/useIsMobile";
  55. interface NavigationItem {
  56. icon: React.ReactNode;
  57. label: string;
  58. path: string;
  59. isHidden?: boolean;
  60. showOnMobile?: boolean;
  61. children?: NavigationItem[];
  62. }
  63. interface Props {
  64. abilities?: string[];
  65. }
  66. const NavigationContent: React.FC<Props> = ({ abilities }) => {
  67. const navigationItems: NavigationItem[] = [
  68. {
  69. icon: <WorkHistory />,
  70. label: "User Workspace",
  71. path: "/home",
  72. showOnMobile: true,
  73. },
  74. {
  75. icon: <Dashboard />,
  76. label: "Dashboard",
  77. path: "",
  78. isHidden: ![VIEW_DASHBOARD_ALL, VIEW_DASHBOARD_SELF].some((ability) =>
  79. abilities!.includes(ability),
  80. ),
  81. children: [
  82. {
  83. icon: <SummarizeIcon />,
  84. label: "Financial Summary",
  85. path: "/dashboard/ProjectFinancialSummary",
  86. },
  87. {
  88. icon: <PaymentsIcon />,
  89. label: "Company / Team Cash Flow",
  90. path: "/dashboard/CompanyTeamCashFlow",
  91. },
  92. {
  93. icon: <PaymentsIcon />,
  94. label: "Project Cash Flow",
  95. path: "/dashboard/ProjectCashFlow",
  96. },
  97. {
  98. icon: <AccountTreeIcon />,
  99. label: "Project Status by Client",
  100. path: "/dashboard/ProjectStatusByClient",
  101. },
  102. {
  103. icon: <AccountTreeIcon />,
  104. label: "Project Status by Team",
  105. path: "/dashboard/ProjectStatusByTeam",
  106. },
  107. {
  108. icon: <PeopleIcon />,
  109. label: "Staff Utilization",
  110. path: "/dashboard/StaffUtilization",
  111. },
  112. {
  113. icon: <ViewWeekIcon />,
  114. label: "Project Resource Summary",
  115. path: "/dashboard/ProjectResourceSummary",
  116. },
  117. ],
  118. },
  119. // No Claim function in Breaur, will be implement later
  120. // {
  121. // icon: <RequestQuote />,
  122. // label: "Staff Reimbursement",
  123. // path: "/staffReimbursement",
  124. // children: [
  125. // {
  126. // icon: <RequestQuote />,
  127. // label: "Claim Approval",
  128. // path: "/staffReimbursement/ClaimApproval",
  129. // },
  130. // {
  131. // icon: <RequestQuote />,
  132. // label: "Claim Summary",
  133. // path: "/staffReimbursement/ClaimSummary",
  134. // },
  135. // ],
  136. // },
  137. { icon: <Assignment />, label: "Project Management", path: "/projects", isHidden: ![MAINTAIN_PROJECT].some((ability) => abilities?.includes(ability)) },
  138. { icon: <Task />, label: "Task Template", path: "/tasks", isHidden: ![MAINTAIN_TASK_TEMPLATE].some((ability) => abilities?.includes(ability)) },
  139. {
  140. icon: <Payments />,
  141. label: "Invoice",
  142. path: "/invoice",
  143. isHidden: ![IMPORT_INVOICE, IMPORT_RECEIPT].some((ability) =>
  144. abilities!.includes(ability),
  145. ),
  146. },
  147. {
  148. icon: <Analytics />,
  149. label: "Analysis Report",
  150. path: "",
  151. isHidden: ![GENERATE_REPORTS].some((ability) =>
  152. abilities!.includes(ability),
  153. ),
  154. children: [
  155. {
  156. icon: <Analytics />,
  157. label: "Late Start Report",
  158. path: "/analytics/LateStartReport",
  159. },
  160. {
  161. icon: <Analytics />,
  162. label: "Project Potential Delay Report",
  163. path: "/analytics/ProjectPotentialDelayReport",
  164. },
  165. {
  166. icon: <Analytics />,
  167. label: "Resource Overconsumption Report",
  168. path: "/analytics/ResourceOverconsumptionReport",
  169. },
  170. {
  171. icon: <Analytics />,
  172. label: "Cost and Expense Report",
  173. path: "/analytics/CostandExpenseReport",
  174. },
  175. {
  176. icon: <Analytics />,
  177. label: "Project Completion Report",
  178. path: "/analytics/ProjectCompletionReport",
  179. },
  180. // {
  181. // icon: <Analytics />,
  182. // label: "Completion Report with Outstanding Un-billed Hours Report",
  183. // path: "/analytics/ProjectCompletionReportWO",
  184. // },
  185. // {
  186. // icon: <Analytics />,
  187. // label: "Project Claims Report",
  188. // path: "/analytics/ProjectClaimsReport",
  189. // },
  190. {
  191. icon: <Analytics />,
  192. label: "Project P&L Report",
  193. path: "/analytics/ProjectPandLReport",
  194. },
  195. {
  196. icon: <Analytics />,
  197. label: "Financial Status Report",
  198. path: "/analytics/FinancialStatusReport",
  199. },
  200. {
  201. icon: <Analytics />,
  202. label: "Project Cash Flow Report",
  203. path: "/analytics/ProjectCashFlowReport",
  204. },
  205. {
  206. icon: <Analytics />,
  207. label: "Staff Monthly Work Hours Analysis Report",
  208. path: "/analytics/StaffMonthlyWorkHoursAnalysisReport",
  209. },
  210. ],
  211. },
  212. {
  213. icon: <Settings />,
  214. label: "Setting",
  215. path: "",
  216. isHidden: ![VIEW_MASTERDATA, MAINTAIN_MASTERDATA].some((ability) =>
  217. abilities!.includes(ability),
  218. ),
  219. children: [
  220. { icon: <GroupIcon />, label: "Client", path: "/settings/customer" },
  221. {
  222. icon: <BusinessIcon />,
  223. label: "Subsidiary",
  224. path: "/settings/subsidiary",
  225. },
  226. { icon: <Staff />, label: "Staff", path: "/settings/staff" },
  227. { icon: <Company />, label: "Company", path: "/settings/company" },
  228. { icon: <EmojiEventsIcon />, label: "Skill", path: "/settings/skill" },
  229. {
  230. icon: <Department />,
  231. label: "Department",
  232. path: "/settings/department",
  233. },
  234. { icon: <Position />, label: "Position", path: "/settings/position" },
  235. { icon: <Salary />, label: "Salary", path: "/settings/salary" },
  236. { icon: <Team />, label: "Team", path: "/settings/team" },
  237. // { icon: <ManageAccountsIcon />, label: "User", path: "/settings/user" },
  238. {
  239. icon: <ManageAccountsIcon />,
  240. label: "User Group",
  241. path: "/settings/group",
  242. },
  243. { icon: <Holiday />, label: "Holiday", path: "/settings/holiday" },
  244. ],
  245. },
  246. ];
  247. const isMobile = useIsMobile();
  248. const { t } = useTranslation("common");
  249. const pathname = usePathname();
  250. const [openItems, setOpenItems] = React.useState<string[]>([]);
  251. const toggleItem = (label: string) => {
  252. setOpenItems((prevOpenItems) =>
  253. prevOpenItems.includes(label)
  254. ? prevOpenItems.filter((item) => item !== label)
  255. : [...prevOpenItems, label],
  256. );
  257. };
  258. const renderNavigationItem = (item: NavigationItem) => {
  259. const isOpen = openItems.includes(item.label);
  260. return (
  261. <Box
  262. key={`${item.label}-${item.path}`}
  263. component={Link}
  264. href={item.path}
  265. sx={{ textDecoration: "none", color: "inherit" }}
  266. >
  267. <ListItemButton
  268. selected={pathname.includes(item.label)}
  269. onClick={() => item.children && toggleItem(item.label)}
  270. >
  271. <ListItemIcon>{item.icon}</ListItemIcon>
  272. <ListItemText primary={t(item.label)} />
  273. </ListItemButton>
  274. {item.children && isOpen && (
  275. <List sx={{ pl: 2 }}>
  276. {item.children.map((child) => renderNavigationItem(child))}
  277. </List>
  278. )}
  279. </Box>
  280. );
  281. };
  282. return (
  283. <Box sx={{ width: NAVIGATION_CONTENT_WIDTH }}>
  284. <Box sx={{ p: 3, display: "flex" }}>
  285. <Logo height={60} />
  286. {/* <button className="float-right bg-transparent border-transparent" >
  287. <ArrowCircleLeftRoundedIcon className="text-slate-400 hover:text-blue-400 hover:cursor-pointer " style={{ fontSize: '35px' }} />
  288. </button> */}
  289. </Box>
  290. <Divider />
  291. <List component="nav">
  292. {navigationItems
  293. .filter(
  294. (item) => !item.isHidden && (isMobile ? item.showOnMobile : true),
  295. )
  296. .map((item) => renderNavigationItem(item))}
  297. {/* {navigationItems.map(({ icon, label, path }, index) => {
  298. return (
  299. <Box
  300. key={`${label}-${index}`}
  301. component={Link}
  302. href={path}
  303. sx={{ textDecoration: "none", color: "inherit" }}
  304. >
  305. <ListItemButton selected={pathname.includes(path)}>
  306. <ListItemIcon>{icon}</ListItemIcon>
  307. <ListItemText primary={t(label)} />
  308. </ListItemButton>
  309. </Box>
  310. );
  311. })} */}
  312. </List>
  313. </Box>
  314. );
  315. };
  316. export default NavigationContent;