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.
 
 

842 line
36 KiB

  1. "use client";
  2. import * as React from "react";
  3. import Grid from "@mui/material/Grid";
  4. import { useState,useEffect, useMemo } from 'react'
  5. import Paper from "@mui/material/Paper";
  6. import { TFunction } from "i18next";
  7. import { useTranslation } from "react-i18next";
  8. import {Card,CardHeader} from '@mui/material';
  9. import CustomSearchForm from "../CustomSearchForm/CustomSearchForm";
  10. import CustomDatagrid from '../CustomDatagrid/CustomDatagrid';
  11. import ReactApexChart from 'react-apexcharts';
  12. import { ApexOptions } from 'apexcharts';
  13. import { GridColDef, GridRowSelectionModel} from '@mui/x-data-grid';
  14. import ReportProblemIcon from '@mui/icons-material/ReportProblem';
  15. import dynamic from 'next/dynamic';
  16. import '../../app/global.css';
  17. import { AnyARecord, AnyCnameRecord } from "dns";
  18. import SearchBox, { Criterion } from "../SearchBox";
  19. import ProgressByClientSearch from "@/components/ProgressByClientSearch";
  20. import { Suspense } from "react";
  21. import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch";
  22. import {Input,Label} from "reactstrap";
  23. import Select, {components} from 'react-select';
  24. import { DateCalendar } from '@mui/x-date-pickers/DateCalendar';
  25. import { DatePicker } from '@mui/x-date-pickers/DatePicker';
  26. import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
  27. import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
  28. import dayjs, { Dayjs } from 'dayjs';
  29. import isBetweenPlugin from 'dayjs/plugin/isBetween';
  30. import { PickersDay, PickersDayProps } from '@mui/x-date-pickers/PickersDay';
  31. import { styled } from '@mui/material/styles';
  32. dayjs.extend(isBetweenPlugin);
  33. interface CustomPickerDayProps extends PickersDayProps<Dayjs> {
  34. isSelected: boolean;
  35. isHovered: boolean;
  36. }
  37. const CustomPickersDay = styled(PickersDay, {
  38. shouldForwardProp: (prop) => prop !== 'isSelected' && prop !== 'isHovered',
  39. })<CustomPickerDayProps>(({ theme, isSelected, isHovered, day }) => ({
  40. borderRadius: 0,
  41. ...(isSelected && {
  42. backgroundColor: theme.palette.primary.main,
  43. color: theme.palette.primary.contrastText,
  44. '&:hover, &:focus': {
  45. backgroundColor: theme.palette.primary.main,
  46. },
  47. }),
  48. ...(isHovered && {
  49. backgroundColor: theme.palette.primary[theme.palette.mode],
  50. '&:hover, &:focus': {
  51. backgroundColor: theme.palette.primary[theme.palette.mode],
  52. },
  53. }),
  54. ...(day.day() === 0 && {
  55. borderTopLeftRadius: '50%',
  56. borderBottomLeftRadius: '50%',
  57. }),
  58. ...(day.day() === 6 && {
  59. borderTopRightRadius: '50%',
  60. borderBottomRightRadius: '50%',
  61. }),
  62. })) as React.ComponentType<CustomPickerDayProps>;
  63. const isInSameWeek = (dayA: Dayjs, dayB: Dayjs | null | undefined) => {
  64. if (dayB == null) {
  65. return false;
  66. }
  67. return dayA.isSame(dayB, 'week');
  68. };
  69. function Day(
  70. props: PickersDayProps<Dayjs> & {
  71. selectedDay?: Dayjs | null;
  72. hoveredDay?: Dayjs | null;
  73. },
  74. ) {
  75. const { day, selectedDay, hoveredDay, ...other } = props;
  76. return (
  77. <CustomPickersDay
  78. {...other}
  79. day={day}
  80. sx={{ px: 2.5 }}
  81. disableMargin
  82. selected={false}
  83. isSelected={isInSameWeek(day, selectedDay)}
  84. isHovered={isInSameWeek(day, hoveredDay)}
  85. />
  86. );
  87. }
  88. const StaffUtilization: React.FC = () => {
  89. const todayDate = new Date;
  90. const firstDayOfWeek = new Date;
  91. const lastDayOfWeek = new Date;
  92. firstDayOfWeek.setDate(todayDate.getDate() - todayDate.getDay() + 1);
  93. lastDayOfWeek.setDate(todayDate.getDate() - todayDate.getDay() + 7);
  94. const firstDayOfMonth = new Date(todayDate.getFullYear(), todayDate.getMonth(), 1);
  95. const lastDayOfMonth = new Date(todayDate.getFullYear(), todayDate.getMonth() + 1, 0);
  96. const [firstDayOfWeekString, setFirstDayOfWeekString] = React.useState(dayjs(firstDayOfWeek).format('DD MMM YYYY'));
  97. const [lastDayOfWeekString, setLastDayOfWeekString] = React.useState(dayjs(lastDayOfWeek).format('DD MMM YYYY'));
  98. const [firstDayOfMonthString, setFirstDayOfMonthString] = React.useState(dayjs(firstDayOfMonth).format('DD MMM YYYY'));
  99. const [lastDayOfMonthString, setLastDayOfMonthString] = React.useState(dayjs(lastDayOfMonth).format('DD MMM YYYY'))
  100. const [selectionModel, setSelectionModel] : any[] = React.useState([]);
  101. const [manHoursSpentPeriod, setManHoursSpentPeriod] : any[] = React.useState(firstDayOfWeekString + " to " + lastDayOfWeekString);
  102. const [teamTotalManhoursSpentSelect, setTeamTotalManhoursSpentSelect] :any = React.useState("Weekly")
  103. const [staffGradeManhoursSpentSelect, setStaffGradeManhoursSpentSelect] :any = React.useState("Weekly")
  104. const [individualStaffManhoursSpentSelect, setIndividualStaffManhoursSpentSelect] :any = React.useState("Daily")
  105. const weekDates :any[] = [];
  106. const monthDates :any[] = [];
  107. const currentDate = dayjs();
  108. const sixMonthsAgo = currentDate.subtract(6, 'month');
  109. for (let i = 0; i < 7; i++) {
  110. const currentDate = new Date(firstDayOfWeek);
  111. currentDate.setDate(firstDayOfWeek.getDate() + i);
  112. const formattedDate = dayjs(currentDate).format('DD MMM (ddd)');
  113. weekDates.push(formattedDate);
  114. }
  115. for (let date = sixMonthsAgo.clone(); date.isBefore(currentDate, 'month'); date = date.add(1, 'month')) {
  116. monthDates.push(date.format('MM-YYYY'));
  117. }
  118. monthDates.push(currentDate.format('MM-YYYY'));
  119. // for (let i = firstDayOfMonth.getDate(); i <= lastDayOfMonth.getDate(); i++) {
  120. // const currentDate = new Date(todayDate.getFullYear(), todayDate.getMonth(), i);
  121. // const formattedDate = dayjs(currentDate).format('DD MMM');
  122. // monthDates.push(formattedDate);
  123. // }
  124. const [teamTotalManhoursSpentPeriod, setTeamTotalManhoursSpentPeriod] : any[] = React.useState(weekDates)
  125. const [teamTotalManhoursByStaffGrade, setTeamTotalManhoursByStaffGrade] : any[] = React.useState(weekDates)
  126. const [individualStaffManhoursSpentPeriod, setIndividualStaffManhoursSpentPeriod] : any[] = React.useState(weekDates)
  127. const [teamTotalManhoursSpentPlanData, setTeamTotalManhoursSpentPlanData] : any[] = React.useState([42,42,42,42,42,0,0])
  128. const [teamTotalManhoursSpentActualData, setTeamTotalManhoursSpentActualData] : any[] = React.useState([45,42,60,42,58,0,0])
  129. const [hoveredDay, setHoveredDay] = React.useState<Dayjs | null>(null);
  130. const [value, setValue] = React.useState<Dayjs | null>(dayjs());
  131. const [weeklyValueByStaffGrade, setWeeklyValueByStaffGrade] = React.useState<Dayjs | null>(dayjs());
  132. const [weeklyValueByIndividualStaff, setWeeklyValueByIndividualStaff] = React.useState<Dayjs | null>(dayjs());
  133. const [staffGradeManhoursSpentValue, setStaffGradeManhoursSpentValue] = React.useState<Dayjs | null>(dayjs());
  134. const [totalManHoursMonthlyFromValue, setTotalManHoursMonthlyFromValue] = React.useState<Dayjs>(dayjs(new Date).subtract(6, 'month'));
  135. const [totalManHoursMonthlyToValue, setTotalManHoursMonthlyToValue] = React.useState<Dayjs>(dayjs());
  136. const [totalManHoursByStaffGradeMonthlyFromValue, setTotalManHoursByStaffGradeMonthlyFromValue] = React.useState<Dayjs>(dayjs(new Date).subtract(6, 'month'));
  137. const [totalManHoursByStaffGradeMonthlyToValue, setTotalManHoursByStaffGradeMonthlyToValue] = React.useState<Dayjs>(dayjs());
  138. const [totalManHoursByIndividualStaffMonthlyFromValue, setTotalManHoursByIndividualStaffMonthlyFromValue] = React.useState<Dayjs>(dayjs(new Date).subtract(6, 'month'));
  139. const [totalManHoursByIndividualStaffMonthlyToValue, setTotalManHoursByIndividualStaffMonthlyToValue] = React.useState<Dayjs>(dayjs());
  140. const [totalManHoursByIndividualStaffDailyFromValue, setTotalManHoursByIndividualStaffDailyFromValue] = React.useState<Dayjs>(dayjs(new Date).subtract(6, 'day'));
  141. const [totalManHoursByIndividualStaffDailyToValue, setTotalManHoursByIndividualStaffDailyToValue] = React.useState<Dayjs>(dayjs());
  142. const [totalManHoursMaxValue, setTotalManHoursMaxValue] = React.useState(75);
  143. const teamOptions = [
  144. { value: 1, label: 'XXX Team' },
  145. { value: 2, label: 'YYY Team' },
  146. { value: 3, label: 'ZZZ Team' }
  147. ]
  148. const columns = [
  149. {
  150. id: 'projectCode',
  151. field: 'projectCode',
  152. headerName: "Project Code",
  153. flex: 1,
  154. },
  155. {
  156. id: 'projectName',
  157. field: 'projectName',
  158. headerName: "Project Name",
  159. flex: 1,
  160. },
  161. {
  162. id: 'team',
  163. field: 'team',
  164. headerName: "Team",
  165. flex: 1,
  166. },
  167. {
  168. id: 'teamLeader',
  169. field: 'teamLeader',
  170. headerName: "Team Leader",
  171. flex: 1,
  172. },
  173. {
  174. id: 'startDate',
  175. field: 'startDate',
  176. headerName: "Start Date",
  177. flex: 1,
  178. },
  179. {
  180. id: 'targetEndDate',
  181. field: 'targetEndDate',
  182. headerName: "Target End Date",
  183. flex: 1,
  184. },
  185. {
  186. id: 'client',
  187. field: 'client',
  188. headerName: "Client",
  189. flex: 1,
  190. },
  191. {
  192. id: 'subsidiary',
  193. field: 'subsidiary',
  194. headerName: "Subsidiary",
  195. flex: 1,
  196. },
  197. ];
  198. const options: ApexOptions = {
  199. chart: {
  200. height: 350,
  201. type: 'line',
  202. },
  203. stroke: {
  204. width: [2, 2]
  205. },
  206. plotOptions: {
  207. bar: {
  208. horizontal: false,
  209. distributed: false,
  210. },
  211. },
  212. dataLabels: {
  213. enabled: true
  214. },
  215. xaxis: {
  216. categories: teamTotalManhoursSpentPeriod
  217. },
  218. yaxis: [
  219. {
  220. title: {
  221. text: 'Team Total Manhours Spent (Hour)'
  222. },
  223. min: 0,
  224. max: totalManHoursMaxValue,
  225. tickAmount: 5
  226. },
  227. ],
  228. grid: {
  229. borderColor: '#f1f1f1',
  230. },
  231. annotations: {
  232. },
  233. series:[
  234. {
  235. name:"Planned",
  236. type:"line",
  237. color: "#efbe7d",
  238. data:teamTotalManhoursSpentPlanData
  239. },
  240. {
  241. name:"Actual",
  242. type:"line",
  243. color: "#7cd3f2",
  244. data:teamTotalManhoursSpentActualData
  245. }
  246. ]
  247. };
  248. const staffGradeOptions: ApexOptions = {
  249. chart: {
  250. height: 350,
  251. type: 'line',
  252. },
  253. stroke: {
  254. width: [2, 2]
  255. },
  256. plotOptions: {
  257. bar: {
  258. horizontal: true,
  259. distributed: false,
  260. },
  261. },
  262. dataLabels: {
  263. enabled: true
  264. },
  265. xaxis: {
  266. categories: [
  267. "Grade 1: A. QS / QS Trainee",
  268. "Grade 2: QS",
  269. "Grade 3: Senior QS",
  270. "Grade 4: Manager",
  271. "Grade 5: Director"
  272. ]
  273. },
  274. yaxis: [
  275. {
  276. title: {
  277. text: 'Staff Grade'
  278. },
  279. min: 0,
  280. max: 60,
  281. tickAmount: 5
  282. },
  283. ],
  284. grid: {
  285. borderColor: '#f1f1f1',
  286. },
  287. annotations: {
  288. },
  289. series:[
  290. {
  291. name:"Planned",
  292. type:"bar",
  293. color: "#efbe7d",
  294. data:[35,45,35,20,10]
  295. },
  296. {
  297. name:"Actual",
  298. type:"bar",
  299. color: "#00acb1",
  300. data:[25,26,33,20,11]
  301. }
  302. ]
  303. };
  304. const individualStaffOptions: ApexOptions = {
  305. chart: {
  306. height: 350,
  307. type: 'line',
  308. },
  309. stroke: {
  310. width: [1]
  311. },
  312. plotOptions: {
  313. bar: {
  314. horizontal: true,
  315. distributed: false,
  316. },
  317. },
  318. dataLabels: {
  319. enabled: true
  320. },
  321. xaxis: {
  322. categories: [
  323. "Consultancy Project 123 (CUST-001, Subsidiary A)",
  324. "Consultancy Project 456 (CUST-001, Subsidiary A)",
  325. "Construction Project A (CUST-001, Subsidiary A)",
  326. "Construction Project B (CUST-001, Subsidiary A)",
  327. "Construction Project C (CUST-001, Subsidiary A)"
  328. ]
  329. },
  330. yaxis: [
  331. {
  332. title: {
  333. text: 'Project'
  334. },
  335. min: 0,
  336. max: 12,
  337. tickAmount: 5
  338. },
  339. ],
  340. grid: {
  341. borderColor: '#f1f1f1',
  342. },
  343. annotations: {
  344. },
  345. series:[
  346. {
  347. name:"Manhours(Hour)",
  348. type:"bar",
  349. color: "#00acb1",
  350. data:[12,12,11,12,0]
  351. }
  352. ]
  353. };
  354. const teamTotalManhoursSpentOnClick = (r:any) => {
  355. setTeamTotalManhoursSpentSelect(r)
  356. if (r === "Weekly") {
  357. setValue(dayjs(new Date))
  358. setTeamTotalManhoursSpentPeriod(weekDates)
  359. setTeamTotalManhoursSpentPlanData([42,42,42,42,42,0,0])
  360. setTeamTotalManhoursSpentActualData([45,42,60,42,58,0,0])
  361. setTotalManHoursMaxValue(75)
  362. } else if (r === "Monthly") {
  363. setTeamTotalManhoursSpentPeriod(monthDates)
  364. setTeamTotalManhoursSpentPlanData([840,840,840,840,840,840])
  365. setTeamTotalManhoursSpentActualData([900,840,1200,840,1160,840])
  366. setTotalManHoursMaxValue(1250)
  367. }
  368. };
  369. const individualStaffManhoursSpentOnClick = (r:any) => {
  370. setIndividualStaffManhoursSpentSelect(r)
  371. // if (r === "Weekly") {
  372. // setValue(dayjs(new Date))
  373. // setTeamTotalManhoursSpentPeriod(weekDates)
  374. // setTeamTotalManhoursSpentPlanData([42,42,42,42,42,0,0])
  375. // setTeamTotalManhoursSpentActualData([45,42,60,42,58,0,0])
  376. // setTotalManHoursMaxValue(75)
  377. // } else if (r === "Monthly") {
  378. // setTeamTotalManhoursSpentPeriod(monthDates)
  379. // setTeamTotalManhoursSpentPlanData([840,840,840,840,840,840])
  380. // setTeamTotalManhoursSpentActualData([900,840,1200,840,1160,840])
  381. // setTotalManHoursMaxValue(1250)
  382. // }
  383. };
  384. const selectWeeklyPeriod = (r:any) => {
  385. const selectDate = new Date(r);
  386. const firstDayOfWeek = new Date;
  387. firstDayOfWeek.setDate(selectDate.getDate() - selectDate.getDay() + 0);
  388. const weekDates :any[] = [];
  389. for (let i = 0; i < 7; i++) {
  390. const currentDate = new Date(firstDayOfWeek);
  391. currentDate.setDate(firstDayOfWeek.getDate() + i);
  392. const formattedDate = dayjs(currentDate).format('DD MMM (ddd)');
  393. weekDates.push(formattedDate);
  394. }
  395. setTeamTotalManhoursSpentPeriod(weekDates)
  396. setValue(dayjs(firstDayOfWeek))
  397. }
  398. const selectWeeklyPeriodByStaffGrade = (r:any) => {
  399. const selectDate = new Date(r);
  400. const firstDayOfWeek = new Date;
  401. firstDayOfWeek.setDate(selectDate.getDate() - selectDate.getDay() + 0);
  402. const weekDates :any[] = [];
  403. for (let i = 0; i < 7; i++) {
  404. const currentDate = new Date(firstDayOfWeek);
  405. currentDate.setDate(firstDayOfWeek.getDate() + i);
  406. const formattedDate = dayjs(currentDate).format('DD MMM (ddd)');
  407. weekDates.push(formattedDate);
  408. }
  409. setTeamTotalManhoursByStaffGrade(weekDates)
  410. setWeeklyValueByStaffGrade(dayjs(firstDayOfWeek))
  411. }
  412. const selectWeeklyPeriodIndividualStaff = (r:any) => {
  413. const selectDate = new Date(r);
  414. const firstDayOfWeek = new Date;
  415. firstDayOfWeek.setDate(selectDate.getDate() - selectDate.getDay() + 0);
  416. const weekDates :any[] = [];
  417. for (let i = 0; i < 7; i++) {
  418. const currentDate = new Date(firstDayOfWeek);
  419. currentDate.setDate(firstDayOfWeek.getDate() + i);
  420. const formattedDate = dayjs(currentDate).format('DD MMM (ddd)');
  421. weekDates.push(formattedDate);
  422. }
  423. setIndividualStaffManhoursSpentPeriod(weekDates)
  424. setWeeklyValueByIndividualStaff(dayjs(firstDayOfWeek))
  425. }
  426. const selectMonthlyPeriodFrom = (r:any) => {
  427. const monthDates :any[] = [];
  428. const monthPlanData :any[] = [];
  429. const monthActualData :any[] = [];
  430. const selectFromDate = dayjs(r);
  431. for (let date = selectFromDate.clone(); date.isBefore(totalManHoursMonthlyToValue, 'month'); date = date.add(1, 'month')) {
  432. monthDates.push(date.format('MM-YYYY'));
  433. monthPlanData.push(840)
  434. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840))
  435. }
  436. monthDates.push(totalManHoursMonthlyToValue.format('MM-YYYY'));
  437. monthPlanData.push(840)
  438. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840))
  439. setTeamTotalManhoursSpentPlanData(monthPlanData)
  440. setTeamTotalManhoursSpentActualData(monthActualData)
  441. setTeamTotalManhoursSpentPeriod(monthDates)
  442. }
  443. const selectMonthlyPeriodTo = (r:any) => {
  444. const monthDates :any[] = [];
  445. const monthPlanData :any[] = [];
  446. const monthActualData :any[] = [];
  447. const selectToDate = dayjs(r);
  448. for (let date = totalManHoursMonthlyFromValue.clone(); date.isBefore(selectToDate, 'month'); date = date.add(1, 'month')) {
  449. monthDates.push(date.format('MM-YYYY'));
  450. monthPlanData.push(840)
  451. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840))
  452. }
  453. monthDates.push(selectToDate.format('MM-YYYY'));
  454. monthPlanData.push(840)
  455. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840))
  456. setTeamTotalManhoursSpentPlanData(monthPlanData)
  457. setTeamTotalManhoursSpentActualData(monthActualData)
  458. setTeamTotalManhoursSpentPeriod(monthDates)
  459. }
  460. const selectStaffGradeMonthlyPeriodFrom = (r:any) => {
  461. const monthDates :any[] = [];
  462. const monthPlanData :any[] = [];
  463. const monthActualData :any[] = [];
  464. const selectFromDate = dayjs(r);
  465. for (let date = selectFromDate.clone(); date.isBefore(totalManHoursMonthlyToValue, 'month'); date = date.add(1, 'month')) {
  466. monthDates.push(date.format('MM-YYYY'));
  467. monthPlanData.push(840)
  468. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840))
  469. }
  470. monthDates.push(totalManHoursMonthlyToValue.format('MM-YYYY'));
  471. monthPlanData.push(840)
  472. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840))
  473. // setTeamTotalManhoursSpentPlanData(monthPlanData)
  474. // setTeamTotalManhoursSpentActualData(monthActualData)
  475. setTeamTotalManhoursByStaffGrade(weekDates)
  476. }
  477. const selectStaffGradeMonthlyPeriodTo = (r:any) => {
  478. const monthDates :any[] = [];
  479. const monthPlanData :any[] = [];
  480. const monthActualData :any[] = [];
  481. const selectToDate = dayjs(r);
  482. for (let date = totalManHoursMonthlyFromValue.clone(); date.isBefore(selectToDate, 'month'); date = date.add(1, 'month')) {
  483. monthDates.push(date.format('MM-YYYY'));
  484. monthPlanData.push(840)
  485. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840))
  486. }
  487. monthDates.push(selectToDate.format('MM-YYYY'));
  488. monthPlanData.push(840)
  489. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840))
  490. // setTeamTotalManhoursSpentPlanData(monthPlanData)
  491. // setTeamTotalManhoursSpentActualData(monthActualData)
  492. setTeamTotalManhoursByStaffGrade(weekDates)
  493. }
  494. const selectIndividualStaffMonthlyPeriodFrom = (r:any) => {
  495. const monthDates :any[] = [];
  496. const monthPlanData :any[] = [];
  497. const monthActualData :any[] = [];
  498. const selectFromDate = dayjs(r);
  499. for (let date = selectFromDate.clone(); date.isBefore(totalManHoursMonthlyToValue, 'month'); date = date.add(1, 'month')) {
  500. monthDates.push(date.format('MM-YYYY'));
  501. monthPlanData.push(840)
  502. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840))
  503. }
  504. monthDates.push(totalManHoursMonthlyToValue.format('MM-YYYY'));
  505. monthPlanData.push(840)
  506. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840))
  507. // setTeamTotalManhoursSpentPlanData(monthPlanData)
  508. // setTeamTotalManhoursSpentActualData(monthActualData)
  509. setIndividualStaffManhoursSpentPeriod(weekDates)
  510. }
  511. const selectIndividualStaffMonthlyPeriodTo = (r:any) => {
  512. const monthDates :any[] = [];
  513. const monthPlanData :any[] = [];
  514. const monthActualData :any[] = [];
  515. const selectToDate = dayjs(r);
  516. for (let date = totalManHoursMonthlyFromValue.clone(); date.isBefore(selectToDate, 'month'); date = date.add(1, 'month')) {
  517. monthDates.push(date.format('MM-YYYY'));
  518. monthPlanData.push(840)
  519. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840))
  520. }
  521. monthDates.push(selectToDate.format('MM-YYYY'));
  522. monthPlanData.push(840)
  523. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840))
  524. // setTeamTotalManhoursSpentPlanData(monthPlanData)
  525. // setTeamTotalManhoursSpentActualData(monthActualData)
  526. setIndividualStaffManhoursSpentPeriod(weekDates)
  527. }
  528. return (
  529. <>
  530. <Grid item sm>
  531. <div style={{display:"inline-block",width:"40%"}}>
  532. <div>
  533. <Grid item xs={12} md={12} lg={12}>
  534. <Card>
  535. <CardHeader className="text-slate-500" title="Team Total Manhours Spent"/>
  536. <div style={{display:"inline-block",width:"99%"}}>
  537. <div className="w-fit align-top mr-5 float-right">
  538. {teamTotalManhoursSpentSelect === "Weekly" && (
  539. <>
  540. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid rounded-l-md w-32">Weekly</button>
  541. <button onClick={() => teamTotalManhoursSpentOnClick("Monthly") } className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-r-md w-32">Monthly</button>
  542. </>
  543. )}
  544. {teamTotalManhoursSpentSelect === "Monthly" && (
  545. <>
  546. <button onClick={() => teamTotalManhoursSpentOnClick("Weekly")} className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-l-md w-32">Weekly</button>
  547. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid rounded-r-md w-32">Monthly</button>
  548. </>
  549. )}
  550. </div>
  551. <div className="inline-block w-fit mt-2">
  552. <div className="inline-block ml-6">
  553. <Label className="text-slate-500 font-medium">
  554. Team:&nbsp;
  555. </Label>
  556. </div>
  557. <div className="inline-block ml-1 w-60">
  558. <Select
  559. placeholder= "All Team"
  560. options={teamOptions}
  561. isClearable={true}
  562. />
  563. </div>
  564. <div className="ml-6 mt-2" style={{verticalAlign:"top"}}>
  565. {/* <Label className="text-slate-500 font-medium ml-6">
  566. Period:&nbsp;
  567. </Label> */}
  568. {teamTotalManhoursSpentSelect === "Weekly" && (
  569. <LocalizationProvider dateAdapter={AdapterDayjs}>
  570. <DatePicker
  571. className="w-72 h-10 align-top"
  572. label="Period:"
  573. value={value}
  574. format="DD-MM-YYYY"
  575. onChange={(newValue) => selectWeeklyPeriod(newValue)}
  576. showDaysOutsideCurrentMonth
  577. displayWeekNumber
  578. slots={{ day: Day }}
  579. slotProps={{
  580. day: (ownerState) =>
  581. ({
  582. selectedDay: value,
  583. hoveredDay,
  584. onPointerEnter: () => setHoveredDay(ownerState.day),
  585. onPointerLeave: () => setHoveredDay(null),
  586. } as any),
  587. }}
  588. />
  589. </LocalizationProvider>
  590. )}
  591. {teamTotalManhoursSpentSelect === "Monthly" && (
  592. <LocalizationProvider dateAdapter={AdapterDayjs}>
  593. <DatePicker className="w-40 h-10 align-top" onChange={(newValue) => selectMonthlyPeriodFrom(newValue)} defaultValue={totalManHoursMonthlyFromValue} label={'Form'} views={['month', 'year']} />
  594. <DatePicker className="w-40 h-10 align-top" onChange={(newValue) => selectMonthlyPeriodTo(newValue)} defaultValue={totalManHoursMonthlyToValue} label={'To'} views={['month', 'year']} />
  595. </LocalizationProvider>
  596. )}
  597. </div>
  598. </div>
  599. <ReactApexChart
  600. options={options}
  601. series={options.series}
  602. type="line"
  603. height="400"
  604. />
  605. </div>
  606. </Card>
  607. </Grid>
  608. </div>
  609. <div className="mt-5">
  610. <Grid item xs={12} md={12} lg={12}>
  611. <Card>
  612. <CardHeader className="text-slate-500" title="Total Manhours Spent by Staff Grade"/>
  613. <div style={{display:"inline-block",width:"99%"}}>
  614. <div className="w-fit align-top mr-5 float-right">
  615. {staffGradeManhoursSpentSelect === "Weekly" && (
  616. <>
  617. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid rounded-l-md w-32">Weekly</button>
  618. <button onClick={() => setStaffGradeManhoursSpentSelect("Monthly") } className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-r-md w-48">Monthly</button>
  619. </>
  620. )}
  621. {staffGradeManhoursSpentSelect === "Monthly" && (
  622. <>
  623. <button onClick={() => setStaffGradeManhoursSpentSelect("Weekly")} className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-l-md w-32">Weekly</button>
  624. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid rounded-r-md w-48">Monthly</button>
  625. </>
  626. )}
  627. </div>
  628. <div className="inline-block w-fit mt-2">
  629. <div className="inline-block mt-2 ml-6">
  630. {staffGradeManhoursSpentSelect === "Weekly" && (
  631. <LocalizationProvider dateAdapter={AdapterDayjs}>
  632. <DatePicker
  633. className="w-72 h-10 align-top"
  634. label="Period:"
  635. value={value}
  636. format="DD-MM-YYYY"
  637. onChange={(newValue) => selectWeeklyPeriodByStaffGrade(newValue)}
  638. showDaysOutsideCurrentMonth
  639. displayWeekNumber
  640. slots={{ day: Day }}
  641. slotProps={{
  642. day: (ownerState) =>
  643. ({
  644. selectedDay: value,
  645. hoveredDay,
  646. onPointerEnter: () => setHoveredDay(ownerState.day),
  647. onPointerLeave: () => setHoveredDay(null),
  648. } as any),
  649. }}
  650. />
  651. </LocalizationProvider>
  652. )}
  653. {staffGradeManhoursSpentSelect === "Monthly" && (
  654. <LocalizationProvider dateAdapter={AdapterDayjs}>
  655. <DatePicker className="w-40 h-10 align-top" onChange={(newValue) => selectStaffGradeMonthlyPeriodFrom(newValue)} defaultValue={totalManHoursByStaffGradeMonthlyFromValue} label={'Form'} views={['month', 'year']} />
  656. <DatePicker className="w-40 h-10 align-top" onChange={(newValue) => selectStaffGradeMonthlyPeriodTo(newValue)} defaultValue={totalManHoursByStaffGradeMonthlyToValue} label={'To'} views={['month', 'year']} />
  657. </LocalizationProvider>
  658. )}
  659. {/* <Label className="text-slate-500 font-medium ml-6">
  660. Period:&nbsp;
  661. </Label>
  662. <Input
  663. id={'cashFlowYear'}
  664. value={manHoursSpentPeriod}
  665. readOnly={true}
  666. bsSize="lg"
  667. className="rounded-md text-base w-56 border-slate-200 border-solid text-slate-500 text-center"
  668. /> */}
  669. </div>
  670. </div>
  671. <ReactApexChart
  672. options={staffGradeOptions}
  673. series={staffGradeOptions.series}
  674. type="bar"
  675. height="400"
  676. />
  677. </div>
  678. </Card>
  679. </Grid>
  680. </div>
  681. </div>
  682. <div style={{display:"inline-block",width:"59%",verticalAlign:"top",marginLeft:10}}>
  683. <Grid item xs={12} md={12} lg={12}>
  684. <Card>
  685. <Card>
  686. <CardHeader className="text-slate-500" title="Manhours Spent by Individual Staff"/>
  687. <div style={{display:"inline-block",width:"99%"}}>
  688. <div className="w-fit align-top mr-5 float-right">
  689. {individualStaffManhoursSpentSelect === "Daily" && (
  690. <>
  691. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid rounded-l-md w-32">Daily</button>
  692. <button onClick={() => individualStaffManhoursSpentOnClick("Weekly")} className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid w-32">Weekly</button>
  693. <button onClick={() => individualStaffManhoursSpentOnClick("Monthly") } className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-r-md w-32">Monthly</button>
  694. </>
  695. )}
  696. {individualStaffManhoursSpentSelect === "Weekly" && (
  697. <>
  698. <button onClick={() => individualStaffManhoursSpentOnClick("Daily") } className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-l-md w-32">Daily</button>
  699. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid w-32">Weekly</button>
  700. <button onClick={() => individualStaffManhoursSpentOnClick("Monthly") } className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-r-md w-32">Monthly</button>
  701. </>
  702. )}
  703. {individualStaffManhoursSpentSelect === "Monthly" && (
  704. <>
  705. <button onClick={() => individualStaffManhoursSpentOnClick("Daily") } className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-l-md w-32">Daily</button>
  706. <button onClick={() => individualStaffManhoursSpentOnClick("Weekly")} className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid w-32">Weekly</button>
  707. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid rounded-r-md w-32">Monthly</button>
  708. </>
  709. )}
  710. </div>
  711. <div className="inline-block w-fit mt-2">
  712. <div className="inline-block ml-6">
  713. <Label className="text-slate-500 font-medium">
  714. Staff Code and Name:&nbsp;
  715. </Label>
  716. </div>
  717. <div className="inline-block ml-1 w-60">
  718. <Select
  719. placeholder= "00338-Chris Wong"
  720. options={teamOptions}
  721. isClearable={true}
  722. />
  723. </div>
  724. <div className="ml-6 mt-2" style={{verticalAlign:"top"}}>
  725. {/* <Label className="text-slate-500 font-medium ml-6">
  726. Period:&nbsp;
  727. </Label> */}
  728. {individualStaffManhoursSpentSelect === "Daily" && (
  729. <LocalizationProvider dateAdapter={AdapterDayjs}>
  730. <DatePicker className="w-40 h-10 align-top" onChange={(newValue) => selectIndividualStaffMonthlyPeriodFrom(newValue)} defaultValue={totalManHoursByIndividualStaffDailyFromValue} label={'Form'} views={['day','month', 'year']} />
  731. <DatePicker className="w-40 h-10 align-top" onChange={(newValue) => selectIndividualStaffMonthlyPeriodTo(newValue)} defaultValue={totalManHoursByIndividualStaffDailyToValue} label={'To'} views={['day','month', 'year']} />
  732. </LocalizationProvider>
  733. )}
  734. {individualStaffManhoursSpentSelect === "Weekly" && (
  735. <LocalizationProvider dateAdapter={AdapterDayjs}>
  736. <DatePicker
  737. className="w-72 h-10 align-top"
  738. label="Period:"
  739. value={value}
  740. format="DD-MM-YYYY"
  741. onChange={(newValue) => selectWeeklyPeriodIndividualStaff(newValue)}
  742. showDaysOutsideCurrentMonth
  743. displayWeekNumber
  744. slots={{ day: Day }}
  745. slotProps={{
  746. day: (ownerState) =>
  747. ({
  748. selectedDay: value,
  749. hoveredDay,
  750. onPointerEnter: () => setHoveredDay(ownerState.day),
  751. onPointerLeave: () => setHoveredDay(null),
  752. } as any),
  753. }}
  754. />
  755. </LocalizationProvider>
  756. )}
  757. {individualStaffManhoursSpentSelect === "Monthly" && (
  758. <LocalizationProvider dateAdapter={AdapterDayjs}>
  759. <DatePicker className="w-40 h-10 align-top" onChange={(newValue) => selectIndividualStaffMonthlyPeriodFrom(newValue)} defaultValue={totalManHoursByIndividualStaffMonthlyFromValue} label={'Form'} views={['month', 'year']} />
  760. <DatePicker className="w-40 h-10 align-top" onChange={(newValue) => selectIndividualStaffMonthlyPeriodTo(newValue)} defaultValue={totalManHoursByIndividualStaffMonthlyToValue} label={'To'} views={['month', 'year']} />
  761. </LocalizationProvider>
  762. )}
  763. </div>
  764. </div>
  765. <ReactApexChart
  766. options={individualStaffOptions}
  767. series={individualStaffOptions.series}
  768. type="bar"
  769. height="380"
  770. />
  771. </div>
  772. </Card>
  773. <div style={{display:"inline-block",width:"50%"}}>
  774. <div style={{display:"inline-block",width:"47%",marginTop:10,marginLeft:10}}>
  775. <Card style={{height:90}}>
  776. <div className="text-slate-500 text-center text-base">Total Normal Hours Spent</div>
  777. <div className="text-center w-full text-3xl font-bold" style={{color:"#92c1e9"}}>40.00</div>
  778. </Card>
  779. <Card style={{marginTop:10,height:90}}>
  780. <div className="text-slate-500 text-center text-base">Total Leave Hours</div>
  781. <div className="text-center w-full text-3xl font-bold" style={{color:"#898d8d",marginTop:10}}>0.00</div>
  782. </Card>
  783. </div>
  784. <div style={{display:"inline-block",width:"47%",marginTop:10,marginLeft:10}}>
  785. <Card style={{height:90}}>
  786. <div className="text-slate-500 text-center text-base">Total Other Hours Spent</div>
  787. <div className="text-center w-full text-3xl font-bold" style={{color:"#92c1e9"}}>7.00</div>
  788. </Card>
  789. <Card style={{marginTop:10,height:90}}>
  790. <div className="text-slate-500 text-center text-base">Remaining Hours</div>
  791. <div className="text-center w-full text-3xl font-bold" style={{color:"#898d8d",marginTop:10}}>0.00</div>
  792. </Card>
  793. </div>
  794. </div>
  795. </Card>
  796. </Grid>
  797. </div>
  798. </Grid>
  799. </>
  800. );
  801. };
  802. export default StaffUtilization;