選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

StaffUtilization.tsx 83 KiB

1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106
  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. import Holidays from "date-holidays";
  33. import moment from "moment";
  34. import { fetchTeamCombo, fetchweeklyTeamTotalManhours, fetchmonthlyTeamTotalManhours, fetchTotalManhoursByGrade, fetchWeeklyUnsubmit, fetchMonthlyUnsubmit, fetchStaffCombo, fetchDailyIndividualStaffManhours, fetchWeeklyIndividualStaffManhours, fetchMonthlyIndividualStaffManhours } from "@/app/api/staffUtilization";
  35. import { SessionStaff } from "@/config/authConfig";
  36. import { VIEW_DASHBOARD_ALL } from "@/middleware";
  37. import { QrCode } from "@mui/icons-material";
  38. dayjs.extend(isBetweenPlugin);
  39. interface CustomPickerDayProps extends PickersDayProps<Dayjs> {
  40. isSelected: boolean;
  41. isHovered: boolean;
  42. }
  43. const CustomPickersDay = styled(PickersDay, {
  44. shouldForwardProp: (prop) => prop !== "isSelected" && prop !== "isHovered",
  45. })<CustomPickerDayProps>(({ theme, isSelected, isHovered, day }) => ({
  46. borderRadius: 0,
  47. ...(isSelected && {
  48. backgroundColor: theme.palette.primary.main,
  49. color: theme.palette.primary.contrastText,
  50. "&:hover, &:focus": {
  51. backgroundColor: theme.palette.primary.main,
  52. },
  53. }),
  54. ...(isHovered && {
  55. backgroundColor: theme.palette.primary[theme.palette.mode],
  56. "&:hover, &:focus": {
  57. backgroundColor: theme.palette.primary[theme.palette.mode],
  58. },
  59. }),
  60. ...(day.day() === 0 && {
  61. borderTopLeftRadius: "50%",
  62. borderBottomLeftRadius: "50%",
  63. }),
  64. ...(day.day() === 6 && {
  65. borderTopRightRadius: "50%",
  66. borderBottomRightRadius: "50%",
  67. }),
  68. })) as React.ComponentType<CustomPickerDayProps>;
  69. const isInSameWeek = (dayA: Dayjs, dayB: Dayjs | null | undefined) => {
  70. if (dayB == null) {
  71. return false;
  72. }
  73. return dayA.isSame(dayB, "week");
  74. };
  75. function Day(
  76. props: PickersDayProps<Dayjs> & {
  77. selectedDay?: Dayjs | null;
  78. hoveredDay?: Dayjs | null;
  79. },
  80. ) {
  81. const { day, selectedDay, hoveredDay, ...other } = props;
  82. return (
  83. <CustomPickersDay
  84. {...other}
  85. day={day}
  86. sx={{ px: 2.5 }}
  87. disableMargin
  88. selected={false}
  89. isSelected={isInSameWeek(day, selectedDay)}
  90. isHovered={isInSameWeek(day, hoveredDay)}
  91. />
  92. );
  93. }
  94. interface Props {
  95. abilities: string[];
  96. staff: SessionStaff;
  97. }
  98. const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
  99. const abilityViewDashboardAll = abilities.includes(VIEW_DASHBOARD_ALL)
  100. const todayDate = new Date();
  101. const firstDayOfWeek = new Date();
  102. const lastDayOfWeek = new Date();
  103. firstDayOfWeek.setDate(todayDate.getDate() - todayDate.getDay() + 0);
  104. lastDayOfWeek.setDate(todayDate.getDate() - todayDate.getDay() + 6);
  105. const firstDayOfMonth = new Date(
  106. todayDate.getFullYear(),
  107. todayDate.getMonth(),
  108. 1,
  109. );
  110. const lastDayOfMonth = new Date(
  111. todayDate.getFullYear(),
  112. todayDate.getMonth() + 1,
  113. 0,
  114. );
  115. const [firstDayOfWeekString, setFirstDayOfWeekString] = React.useState(
  116. dayjs(firstDayOfWeek).format("DD MMM YYYY"),
  117. );
  118. const [lastDayOfWeekString, setLastDayOfWeekString] = React.useState(
  119. dayjs(lastDayOfWeek).format("DD MMM YYYY"),
  120. );
  121. const [firstDayOfMonthString, setFirstDayOfMonthString] = React.useState(
  122. dayjs(firstDayOfMonth).format("DD MMM YYYY"),
  123. );
  124. const [lastDayOfMonthString, setLastDayOfMonthString] = React.useState(
  125. dayjs(lastDayOfMonth).format("DD MMM YYYY"),
  126. );
  127. const [selectionModel, setSelectionModel]: any[] = React.useState([]);
  128. const [manHoursSpentPeriod, setManHoursSpentPeriod]: any[] = React.useState(
  129. firstDayOfWeekString + " to " + lastDayOfWeekString,
  130. );
  131. const [unsubmittedTimeSheetSelect, setUnsubmittedTimeSheetSelect]: any =
  132. React.useState("Monthly");
  133. const [teamTotalManhoursSpentSelect, setTeamTotalManhoursSpentSelect]: any =
  134. React.useState("Monthly");
  135. const [staffGradeManhoursSpentSelect, setStaffGradeManhoursSpentSelect]: any =
  136. React.useState("Monthly");
  137. const [
  138. individualStaffManhoursSpentSelect,
  139. setIndividualStaffManhoursSpentSelect,
  140. ]: any = React.useState("Monthly");
  141. const weekDates: any[] = [];
  142. const monthDates: any[] = [];
  143. const currentDate = dayjs();
  144. const sixMonthsAgo = currentDate.subtract(6, "month");
  145. for (let i = 0; i < 7; i++) {
  146. const currentDate = new Date(firstDayOfWeek);
  147. currentDate.setDate(firstDayOfWeek.getDate() + i);
  148. const formattedDate = dayjs(currentDate).format("DD MMM (ddd)");
  149. weekDates.push(formattedDate);
  150. }
  151. for (
  152. let date = sixMonthsAgo.clone();
  153. date.isBefore(currentDate, "month");
  154. date = date.add(1, "month")
  155. ) {
  156. monthDates.push(date.format("MM-YYYY"));
  157. }
  158. monthDates.push(currentDate.format("MM-YYYY"));
  159. // for (let i = firstDayOfMonth.getDate(); i <= lastDayOfMonth.getDate(); i++) {
  160. // const currentDate = new Date(todayDate.getFullYear(), todayDate.getMonth(), i);
  161. // const formattedDate = dayjs(currentDate).format('DD MMM');
  162. // monthDates.push(formattedDate);
  163. // }
  164. const [teamTotalManhoursSpentPeriod, setTeamTotalManhoursSpentPeriod]: any[] =
  165. React.useState(monthDates);
  166. const [
  167. teamTotalManhoursByStaffGrade,
  168. setTeamTotalManhoursByStaffGrade,
  169. ]: any[] = React.useState(weekDates);
  170. const [
  171. individualStaffManhoursSpentPeriod,
  172. setIndividualStaffManhoursSpentPeriod,
  173. ]: any[] = React.useState(weekDates);
  174. const [
  175. unsubmittedTimeSheetPeriod,
  176. setUnsubmittedTimeSheetPeriod,
  177. ]: any[] = React.useState(weekDates);
  178. const [
  179. teamTotalManhoursSpentPlanData,
  180. setTeamTotalManhoursSpentPlanData,
  181. ]: any[] = React.useState([0, 0, 0, 0, 0, 0, 0]);
  182. const [
  183. teamTotalManhoursSpentActualData,
  184. setTeamTotalManhoursSpentActualData,
  185. ]: any[] = React.useState([0, 0, 0, 0, 0, 0, 0]);
  186. const [hoveredDay, setHoveredDay] = React.useState<Dayjs | null>(null);
  187. const [value, setValue] = React.useState<Dayjs>(dayjs().startOf('week'));
  188. const [weeklyValueByStaffGrade, setWeeklyValueByStaffGrade] =
  189. React.useState<Dayjs>(dayjs().startOf('week'));
  190. const [weeklyToValueByStaffGrade, setWeeklyToValueByStaffGrade] =
  191. React.useState<Dayjs>(dayjs().startOf('week').add(6, 'day'));
  192. const [weeklyValueByIndividualStaff, setWeeklyValueByIndividualStaff] =
  193. React.useState<Dayjs>(dayjs().startOf('week'));
  194. const [weeklyUnsubmittedTimeSheet, setWeeklyUnsubmittedTimeSheet] =
  195. React.useState<Dayjs>(dayjs().startOf('week'));
  196. const [staffGradeManhoursSpentValue, setStaffGradeManhoursSpentValue] =
  197. React.useState<Dayjs>(dayjs());
  198. const [totalManHoursMonthlyFromValue, setTotalManHoursMonthlyFromValue] =
  199. React.useState<Dayjs>(dayjs(new Date()).subtract(6, "month"));
  200. const [totalManHoursMonthlyToValue, setTotalManHoursMonthlyToValue] =
  201. React.useState<Dayjs>(dayjs());
  202. const [unsubmitMonthlyFromValue, setUnsubmitMonthlyFromValue] =
  203. React.useState<Dayjs>(dayjs(new Date()));
  204. const [unsubmitMonthlyToValue, setUnsubmitMonthlyToValue] =
  205. React.useState<Dayjs>(dayjs());
  206. const [indivdualManHoursMonthlyFromValue, setIndivdualManHoursMonthlyFromValue] =
  207. React.useState<Dayjs>(dayjs());
  208. const [indivdualManHoursMonthlyToValue, setIndivdualManHoursMonthlyToValue] =
  209. React.useState<Dayjs>(dayjs());
  210. const [
  211. totalManHoursByStaffGradeMonthlyFromValue,
  212. setTotalManHoursByStaffGradeMonthlyFromValue,
  213. ] = React.useState<Dayjs>(dayjs(new Date()).subtract(6, "month"));
  214. const [
  215. totalManHoursByStaffGradeMonthlyToValue,
  216. setTotalManHoursByStaffGradeMonthlyToValue,
  217. ] = React.useState<Dayjs>(dayjs());
  218. const [
  219. totalManHoursByIndividualStaffMonthlyFromValue,
  220. setTotalManHoursByIndividualStaffMonthlyFromValue,
  221. ] = React.useState<Dayjs>(dayjs(new Date()).subtract(6, "month"));
  222. const [
  223. totalManHoursByIndividualStaffMonthlyToValue,
  224. setTotalManHoursByIndividualStaffMonthlyToValue,
  225. ] = React.useState<Dayjs>(dayjs());
  226. const [
  227. totalManHoursByIndividualStaffDailyFromValue,
  228. setTotalManHoursByIndividualStaffDailyFromValue,
  229. ] = React.useState<Dayjs>(dayjs(new Date()));
  230. const [
  231. totalManHoursByIndividualStaffDailyToValue,
  232. setTotalManHoursByIndividualStaffDailyToValue,
  233. ] = React.useState<Dayjs>(dayjs());
  234. const hd = new Holidays('HK');
  235. const currentYear = new Date().getFullYear();
  236. const years = [currentYear - 2, currentYear - 1, currentYear, currentYear + 1, currentYear + 2];
  237. let allHolidays: any[] = [];
  238. years.forEach(year => {
  239. const holidays = hd.getHolidays(year);
  240. allHolidays = allHolidays.concat(holidays);
  241. });
  242. const holidayDates = allHolidays.map(holiday => moment(holiday.date).format('YYYY-MM-DD')).join(',');
  243. const [totalManHoursMaxValue, setTotalManHoursMaxValue] = React.useState(5);
  244. const [totalManHoursByGradeMaxValue, setTotalManHoursByGradeMaxValue] = React.useState(5);
  245. const [individualManhoursMaxValue, setIndividualManhoursMaxValue] = React.useState(12);
  246. const [unsubmittedMaxValue, setUnsubmittedMaxValue] = React.useState(5);
  247. const [totalManhourByGradeActualManhours, setTotalManhourByGradeActualManhours]: any[] = React.useState([]);
  248. const [totalManhourByGradePlannedManhours, setTotalManhourByGradePlannedManhours]: any[] = React.useState([]);
  249. const [gradeNameList, setGradeNameList]: any[] = React.useState([]);
  250. const [teamManhoursTeamOptions, setTeamManhoursTeamOptions]: any[] = React.useState([]);
  251. const [staffOptions, setStaffOptions]: any[] = React.useState([]);
  252. const [teamManhoursTeamId, setTeamManhoursTeamId]: any[] = React.useState(abilityViewDashboardAll ? 0 : staff.teamId);
  253. const [teamUnsubmitTeamId, setTeamUnsubmitTeamId]: any[] = React.useState(abilityViewDashboardAll ? 0 : staff.teamId);
  254. const [staffGradeTeamId, setStaffGradeTeamId]: any[] = React.useState(abilityViewDashboardAll ? 0 : staff.teamId);
  255. const [staffId, setStaffId]: any[] = React.useState(0);
  256. const [unsubmitCount, setUnsubmitCount]: any[] = React.useState([]);
  257. const [currentPageUnsubmitStaffList, setCurrentPageUnsubmitStaffList]: any[] = React.useState([]);
  258. const [currentPageunsubmitCount, setCurrentPageUnsubmitCount]: any[] = React.useState([]);
  259. const [unsubmitStaffList, setUnsubmitStaffList]: any[] = React.useState([]);
  260. const [individualStaffProjectList, setIndividualStaffProjectList]: any[] = React.useState([]);
  261. const [individualStaffProjectCodeList, setIndividualStaffProjectCodeList]: any[] = React.useState([]);
  262. const [individualStaffManhours, setIndividualStaffManhours]: any[] = React.useState([]);
  263. const [individualStaffManhoursPercentage, setIndividualStaffManhoursPercentage]: any[] = React.useState([]);
  264. const [totalNormalConsumption, setTotalNormalConsumption]: any = React.useState('NA');
  265. const [totalOtConsumption, setTotalOtConsumption]: any = React.useState('NA');
  266. const [totalLeaveHours, setTotalLeaveHours]: any = React.useState('NA');
  267. const [currentPage, setCurrentPage] = useState(1);
  268. const recordsPerPage = 10;
  269. const fetchComboData = async () => {
  270. const staffComboList = []
  271. const teamComboList = []
  272. const teamCombo = await fetchTeamCombo();
  273. const staffCombo = await fetchStaffCombo();
  274. if (abilityViewDashboardAll) {
  275. for (var i = 0; i < teamCombo.records.length; i++) {
  276. teamComboList.push({ value: teamCombo.records[i].id, label: teamCombo.records[i].label })
  277. }
  278. } else {
  279. const tempTeam = teamCombo.records.find(team => team.id === staff.teamId)
  280. teamComboList.push({ value: tempTeam?.id, label: tempTeam?.label })
  281. }
  282. for (var i = 0; i < staffCombo.length; i++) {
  283. staffComboList.push({ value: staffCombo[i].id, label: staffCombo[i].label })
  284. }
  285. setTeamManhoursTeamOptions(teamComboList)
  286. setStaffOptions(staffComboList)
  287. }
  288. const fetchWeeklyTeamManhourSpentData = async () => {
  289. const fetchResult = await fetchweeklyTeamTotalManhours(teamManhoursTeamId, value.format('YYYY-MM-DD'));
  290. const weeklyActual = fetchResult[0].weeklyActualTeamTotalManhoursSpent
  291. const weeklyPlanned = fetchResult[0].weeklyPlannedTeamTotalManhoursSpent
  292. const weeklyActualList = []
  293. const weeklyPlannedList = []
  294. var chartMax = 5
  295. for (var i = 0; i < weeklyActual.length; i++) {
  296. if (chartMax < weeklyActual[i].TotalManhourConsumed) {
  297. chartMax = weeklyActual[i].TotalManhourConsumed
  298. }
  299. weeklyActualList.push(weeklyActual[i].TotalManhourConsumed)
  300. }
  301. if (weekDates.length > 0) {
  302. for (var i = 0; i < weeklyPlanned.length; i++) {
  303. const weeklyPlannedSubList = []
  304. const startCount = weeklyPlanned[i].startCount
  305. const endCount = weeklyPlanned[i].endCount
  306. for (var j = 0; j < weeklyPlanned[i].searchDuration; j++) {
  307. if (j >= startCount && j < endCount) {
  308. weeklyPlannedSubList.push(weeklyPlanned[i].AverageManhours)
  309. } else {
  310. weeklyPlannedSubList.push(0)
  311. }
  312. }
  313. weeklyPlannedList.push(weeklyPlannedSubList)
  314. }
  315. if (weeklyPlannedList.length > 0) {
  316. const result = new Array(weeklyPlannedList[0].length).fill(0);
  317. for (const arr of weeklyPlannedList) {
  318. for (let i = 0; i < arr.length; i++) {
  319. result[i] = Number((result[i] + arr[i]).toFixed(2));
  320. if (chartMax < result[i]) {
  321. chartMax = result[i]
  322. }
  323. }
  324. }
  325. setTeamTotalManhoursSpentPlanData(result)
  326. }
  327. else {
  328. const result = new Array(weekDates.length).fill(0);
  329. setTeamTotalManhoursSpentPlanData(result)
  330. }
  331. }
  332. setTeamTotalManhoursSpentActualData(weeklyActualList);
  333. setTotalManHoursMaxValue(chartMax)
  334. }
  335. const fetchMonthlyTeamManhourSpentData = async () => {
  336. const fetchResult = await fetchmonthlyTeamTotalManhours(teamManhoursTeamId, totalManHoursMonthlyFromValue.format('YYYY-MM-DD'), totalManHoursMonthlyToValue.endOf('month').format('YYYY-MM-DD'));
  337. const weeklyActual = fetchResult[0].monthlyActualTeamTotalManhoursSpent
  338. const weeklyPlanned = fetchResult[0].monthlyPlannedTeamTotalManhoursSpent
  339. const weeklyActualList = []
  340. const weeklyPlannedList = []
  341. var chartMax = 5
  342. for (var i = 0; i < weeklyActual.length; i++) {
  343. if (chartMax < weeklyActual[i].TotalManhourConsumed) {
  344. chartMax = weeklyActual[i].TotalManhourConsumed
  345. }
  346. weeklyActualList.push(weeklyActual[i].TotalManhourConsumed)
  347. }
  348. if (weekDates.length > 0) {
  349. for (var i = 0; i < weeklyPlanned.length; i++) {
  350. const weeklyPlannedSubList = []
  351. const startCount = weeklyPlanned[i].startCount
  352. const endCount = weeklyPlanned[i].endCount
  353. for (var j = 0; j < weeklyPlanned[i].searchDuration; j++) {
  354. if (j >= startCount && j < endCount) {
  355. weeklyPlannedSubList.push(weeklyPlanned[i].AverageManhours)
  356. } else {
  357. weeklyPlannedSubList.push(0)
  358. }
  359. }
  360. weeklyPlannedList.push(weeklyPlannedSubList)
  361. }
  362. if (weeklyPlannedList.length > 0) {
  363. const result = new Array(weeklyPlannedList[0].length).fill(0);
  364. for (const arr of weeklyPlannedList) {
  365. for (let i = 0; i < arr.length; i++) {
  366. result[i] = Number((result[i] + arr[i]).toFixed(2));
  367. if (chartMax < result[i]) {
  368. chartMax = result[i]
  369. }
  370. }
  371. }
  372. setTeamTotalManhoursSpentPlanData(result)
  373. } else {
  374. const result = new Array(weekDates.length).fill(0);
  375. setTeamTotalManhoursSpentPlanData(result)
  376. }
  377. }
  378. setTeamTotalManhoursSpentActualData(weeklyActualList);
  379. setTotalManHoursMaxValue(chartMax)
  380. }
  381. const fetchTotalManhoursByGradeData = async () => {
  382. const fetchResult = await fetchTotalManhoursByGrade(weeklyValueByStaffGrade.format('YYYY-MM-DD'), weeklyToValueByStaffGrade.format('YYYY-MM-DD'),staffGradeTeamId);
  383. const actualManhours = fetchResult[0].staffGradeTotalManhours
  384. const plannedManhours = fetchResult[0].staffGradeTotalPlannedManhours
  385. var chartMax = 5
  386. const gradeList = []
  387. const actualList = []
  388. const plannedList = []
  389. var manhours = 0
  390. for (var i = 0; i < actualManhours.length; i++) {
  391. actualList.push(actualManhours[i].manhours.toFixed(2))
  392. gradeList.push(actualManhours[i].gradeName)
  393. if (chartMax < actualManhours[i].manhours) {
  394. chartMax = actualManhours[i].manhours
  395. }
  396. }
  397. if (plannedManhours.length > 0) {
  398. var gradeId = plannedManhours[0].id
  399. for (var i = 0; i < plannedManhours.length; i++) {
  400. if (plannedManhours[i].id === gradeId) {
  401. manhours += (plannedManhours[i].searchDuration - plannedManhours[i].startDiff - plannedManhours[i].endDiff) * plannedManhours[i].avgGradeManhour
  402. if (chartMax < manhours) {
  403. chartMax = manhours
  404. }
  405. if (i === plannedManhours.length - 1) {
  406. plannedList.push(manhours.toFixed(2))
  407. }
  408. } else {
  409. plannedList.push(manhours.toFixed(2))
  410. manhours = 0
  411. gradeId = plannedManhours[i].id
  412. manhours += (plannedManhours[i].searchDuration - plannedManhours[i].startDiff - plannedManhours[i].endDiff) * plannedManhours[i].avgGradeManhour
  413. if (chartMax < manhours) {
  414. chartMax = manhours
  415. }
  416. if (i === plannedManhours.length - 1) {
  417. plannedList.push(manhours.toFixed(2))
  418. }
  419. }
  420. }
  421. }
  422. setGradeNameList(gradeList)
  423. setTotalManhourByGradePlannedManhours(plannedList)
  424. setTotalManhourByGradeActualManhours(actualList);
  425. setTotalManHoursByGradeMaxValue(chartMax)
  426. }
  427. const fetchMonthlyTotalManhoursByGradeData = async () => {
  428. const fetchResult = await fetchTotalManhoursByGrade(totalManHoursMonthlyFromValue.format('YYYY-MM-DD'), totalManHoursMonthlyToValue.endOf('month').format('YYYY-MM-DD'),staffGradeTeamId);
  429. const actualManhours = fetchResult[0].staffGradeTotalManhours
  430. const plannedManhours = fetchResult[0].staffGradeTotalPlannedManhours
  431. var chartMax = 5
  432. const gradeList = []
  433. const actualList = []
  434. const plannedList = []
  435. var manhours = 0
  436. for (var i = 0; i < actualManhours.length; i++) {
  437. actualList.push(actualManhours[i].manhours.toFixed(2))
  438. gradeList.push(actualManhours[i].gradeName)
  439. if (chartMax < actualManhours[i].manhours) {
  440. chartMax = actualManhours[i].manhours
  441. }
  442. }
  443. if (plannedManhours.length > 0) {
  444. var gradeId = plannedManhours[0].id
  445. for (var i = 0; i < plannedManhours.length; i++) {
  446. if (plannedManhours[i].id === gradeId) {
  447. manhours += (plannedManhours[i].searchDuration - plannedManhours[i].startDiff - plannedManhours[i].endDiff) * plannedManhours[i].avgGradeManhour
  448. if (chartMax < manhours) {
  449. chartMax = manhours
  450. }
  451. if (i === plannedManhours.length - 1) {
  452. plannedList.push(manhours.toFixed(2))
  453. }
  454. } else {
  455. plannedList.push(manhours.toFixed(2))
  456. manhours = 0
  457. gradeId = plannedManhours[i].id
  458. manhours += (plannedManhours[i].searchDuration - plannedManhours[i].startDiff - plannedManhours[i].endDiff) * plannedManhours[i].avgGradeManhour
  459. if (chartMax < manhours) {
  460. chartMax = manhours
  461. }
  462. if (i === plannedManhours.length - 1) {
  463. plannedList.push(manhours.toFixed(2))
  464. }
  465. }
  466. }
  467. }
  468. setGradeNameList(gradeList)
  469. setTotalManhourByGradePlannedManhours(plannedList)
  470. setTotalManhourByGradeActualManhours(actualList);
  471. setTotalManHoursByGradeMaxValue(chartMax)
  472. }
  473. const fetchWeeklyUnsubmittedData = async () => {
  474. const fetchResult = await fetchWeeklyUnsubmit(teamUnsubmitTeamId, weeklyUnsubmittedTimeSheet.format('YYYY-MM-DD'), holidayDates);
  475. const result = []
  476. const staffList = []
  477. var maxValue = 5
  478. for (var i = 0; i < fetchResult.length; i++) {
  479. if (maxValue < fetchResult[i].UnsubmittedCount) {
  480. maxValue = fetchResult[i].UnsubmittedCount
  481. }
  482. result.push(fetchResult[i].UnsubmittedCount)
  483. staffList.push(fetchResult[i].name)
  484. }
  485. setUnsubmittedMaxValue(maxValue)
  486. setUnsubmitCount(result)
  487. setUnsubmitStaffList(staffList)
  488. }
  489. const fetchMonthlyUnsubmittedData = async () => {
  490. const fetchResult = await fetchMonthlyUnsubmit(teamUnsubmitTeamId, unsubmitMonthlyFromValue.format('YYYY-MM-DD'), unsubmitMonthlyToValue.endOf('month').format('YYYY-MM-DD'), holidayDates);
  491. const result = []
  492. const staffList = []
  493. var maxValue = 5
  494. for (var i = 0; i < fetchResult.length; i++) {
  495. if (maxValue < fetchResult[i].UnsubmittedCount) {
  496. maxValue = fetchResult[i].UnsubmittedCount
  497. }
  498. result.push(fetchResult[i].UnsubmittedCount)
  499. staffList.push(fetchResult[i].name)
  500. }
  501. setUnsubmittedMaxValue(maxValue)
  502. setUnsubmitCount(result)
  503. setUnsubmitStaffList(staffList)
  504. }
  505. const fetchDailyIndividualManhoursData = async () => {
  506. console.log(weeklyValueByIndividualStaff.add(6, 'days').format('YYYY-MM-DD'))
  507. const fetchResult = await fetchDailyIndividualStaffManhours(staffId, totalManHoursByIndividualStaffDailyFromValue.format('YYYY-MM-DD'));
  508. console.log(fetchResult)
  509. const manhoursResult = fetchResult[0].individualStaffManhoursSpentByDay
  510. const totalResult = fetchResult[0].individualStaffTotalManhoursSpentByDay
  511. const leaveResult = fetchResult[0].individualStaffTotalLeaveHoursByDay
  512. const result = []
  513. const projectList = []
  514. const projectCodeList = []
  515. const percentageList = []
  516. var maxValue = 12
  517. console.log(manhoursResult)
  518. if (manhoursResult.length > 0) {
  519. for (var i = 0; i < manhoursResult.length; i++) {
  520. if (manhoursResult[i].id !== null) {
  521. if (maxValue < manhoursResult[i].manhours) {
  522. maxValue = manhoursResult[i].manhours
  523. }
  524. result.push(manhoursResult[i].manhours)
  525. projectCodeList.push(manhoursResult[i].projectNo)
  526. projectList.push(manhoursResult[i].projectName)
  527. percentageList.push(manhoursResult[i].manhours)
  528. }
  529. }
  530. setIndividualManhoursMaxValue(maxValue)
  531. setIndividualStaffProjectCodeList(projectCodeList)
  532. setIndividualStaffProjectList(projectList)
  533. setIndividualStaffManhours(result)
  534. setIndividualStaffManhoursPercentage(percentageList)
  535. setTotalNormalConsumption(totalResult[0].normalManhours)
  536. setTotalOtConsumption(totalResult[0].otManhours)
  537. setTotalLeaveHours(leaveResult[0].leaveHours)
  538. }
  539. }
  540. const fetchWeeklyIndividualManhoursData = async () => {
  541. console.log(weeklyValueByIndividualStaff)
  542. const fetchResult = await fetchWeeklyIndividualStaffManhours(staffId, weeklyValueByIndividualStaff.format('YYYY-MM-DD'), weeklyValueByIndividualStaff.add(6, 'days').format('YYYY-MM-DD'));
  543. console.log(fetchResult)
  544. const manhoursResult = fetchResult[0].individualStaffManhoursSpentWeekly
  545. const totalResult = fetchResult[0].individualStaffTotalManhoursSpentWeekly
  546. const leaveResult = fetchResult[0].individualStaffTotalLeaveHoursWeekly
  547. const result = []
  548. const projectList = []
  549. const projectCodeList = []
  550. const percentageList = []
  551. var maxValue = 12
  552. if (manhoursResult.length > 0) {
  553. for (var i = 0; i < manhoursResult.length; i++) {
  554. if (maxValue < manhoursResult[i].manhours) {
  555. maxValue = manhoursResult[i].manhours
  556. }
  557. result.push(manhoursResult[i].manhours)
  558. projectCodeList.push(manhoursResult[i].projectNo)
  559. projectList.push(manhoursResult[i].projectName)
  560. percentageList.push(manhoursResult[i].manhours)
  561. }
  562. setIndividualManhoursMaxValue(maxValue)
  563. setIndividualStaffProjectList(projectList)
  564. setIndividualStaffProjectCodeList(projectCodeList)
  565. setIndividualStaffManhours(result)
  566. setIndividualStaffManhoursPercentage(percentageList)
  567. setTotalNormalConsumption(totalResult[0].normalManhours)
  568. setTotalOtConsumption(totalResult[0].otManhours)
  569. setTotalLeaveHours(leaveResult[0].leaveHours)
  570. }
  571. }
  572. const fetchMonthlyIndividualManhoursData = async () => {
  573. const fetchResult = await fetchMonthlyIndividualStaffManhours(staffId, indivdualManHoursMonthlyFromValue.format('YYYY-MM-01'));
  574. const manhoursResult = fetchResult[0].individualStaffManhoursSpentByMonth
  575. const totalResult = fetchResult[0].individualStaffTotalManhoursSpentByMonth
  576. const leaveResult = fetchResult[0].individualStaffTotalLeaveHoursByMonth
  577. const result = []
  578. const projectList = []
  579. const projectCodeList = []
  580. const percentageList = []
  581. var maxValue = 12
  582. if (manhoursResult.length > 0) {
  583. for (var i = 0; i < manhoursResult.length; i++) {
  584. if (maxValue < manhoursResult[i].manhours) {
  585. maxValue = manhoursResult[i].manhours
  586. }
  587. result.push(manhoursResult[i].manhours)
  588. projectCodeList.push(manhoursResult[i].projectNo)
  589. projectList.push(manhoursResult[i].projectName)
  590. percentageList.push(manhoursResult[i].manhours)
  591. }
  592. setIndividualManhoursMaxValue(maxValue)
  593. setIndividualStaffProjectList(projectList)
  594. setIndividualStaffProjectCodeList(projectCodeList)
  595. setIndividualStaffManhours(result)
  596. setIndividualStaffManhoursPercentage(percentageList)
  597. setTotalNormalConsumption(totalResult[0].normalManhours)
  598. setTotalOtConsumption(totalResult[0].otManhours)
  599. setTotalLeaveHours(leaveResult[0].leaveHours)
  600. }
  601. }
  602. const startIndex = (currentPage - 1) * recordsPerPage;
  603. const endIndex = startIndex + recordsPerPage;
  604. useEffect(() => {
  605. const currentPageStaffData = unsubmitStaffList.slice(startIndex, endIndex)
  606. const currentPageData = unsubmitCount.slice(startIndex, endIndex);
  607. console.log(currentPage)
  608. console.log(Math.ceil(unsubmitStaffList.length / recordsPerPage))
  609. setCurrentPageUnsubmitStaffList(currentPageStaffData)
  610. setCurrentPageUnsubmitCount(currentPageData)
  611. }, [unsubmitCount,currentPage]);
  612. const handlePrevPage = () => {
  613. if (currentPage > 1) {
  614. setCurrentPage(currentPage - 1);
  615. }
  616. };
  617. const handleNextPage = () => {
  618. if (endIndex < unsubmitCount.length) {
  619. setCurrentPage(currentPage + 1);
  620. }
  621. };
  622. useEffect(() => {
  623. fetchComboData()
  624. }, []);
  625. useEffect(() => {
  626. if (teamTotalManhoursSpentSelect === "Weekly") {
  627. fetchWeeklyTeamManhourSpentData()
  628. }
  629. }, [value, teamManhoursTeamId]);
  630. useEffect(() => {
  631. if (teamTotalManhoursSpentSelect === "Monthly") {
  632. fetchMonthlyTeamManhourSpentData()
  633. }
  634. }, [totalManHoursMonthlyFromValue, totalManHoursMonthlyToValue, teamManhoursTeamId]);
  635. useEffect(() => {
  636. if (staffGradeManhoursSpentSelect === "Weekly") {
  637. fetchTotalManhoursByGradeData()
  638. }
  639. }, [staffGradeTeamId, weeklyValueByStaffGrade, weeklyToValueByStaffGrade]);
  640. useEffect(() => {
  641. if (staffGradeManhoursSpentSelect === "Monthly") {
  642. fetchMonthlyTotalManhoursByGradeData()
  643. }
  644. }, [staffGradeTeamId, totalManHoursMonthlyFromValue, totalManHoursMonthlyToValue]);
  645. useEffect(() => {
  646. if (unsubmittedTimeSheetSelect === "Weekly") {
  647. fetchWeeklyUnsubmittedData()
  648. }
  649. }, [teamUnsubmitTeamId, weeklyUnsubmittedTimeSheet]);
  650. useEffect(() => {
  651. if (unsubmittedTimeSheetSelect === "Monthly") {
  652. fetchMonthlyUnsubmittedData()
  653. }
  654. }, [teamUnsubmitTeamId, unsubmitMonthlyFromValue, unsubmitMonthlyToValue]);
  655. useEffect(() => {
  656. if (individualStaffManhoursSpentSelect === "Daily") {
  657. fetchDailyIndividualManhoursData()
  658. }
  659. }, [staffId, totalManHoursByIndividualStaffDailyFromValue, individualStaffManhoursSpentSelect]);
  660. useEffect(() => {
  661. if (individualStaffManhoursSpentSelect === "Weekly") {
  662. fetchWeeklyIndividualManhoursData()
  663. }
  664. }, [staffId, weeklyValueByIndividualStaff]);
  665. useEffect(() => {
  666. if (individualStaffManhoursSpentSelect === "Monthly") {
  667. fetchMonthlyIndividualManhoursData()
  668. }
  669. }, [staffId, indivdualManHoursMonthlyFromValue]);
  670. // useEffect(() => {
  671. // console.log(unsubmittedTimeSheetSelect)
  672. // if (unsubmittedTimeSheetSelect === "Monthly" || teamTotalManhoursSpentSelect === "Monthly" || staffGradeManhoursSpentSelect === "Monthly" || individualStaffManhoursSpentSelect === "Monthly") {
  673. // setUnsubmittedTimeSheetSelect("Monthly")
  674. // setTeamTotalManhoursSpentSelect("Monthly")
  675. // setStaffGradeManhoursSpentSelect("Monthly")
  676. // setIndividualStaffManhoursSpentSelect("Monthly")
  677. // } else if (unsubmittedTimeSheetSelect === "Weekly" || teamTotalManhoursSpentSelect === "Weekly" || staffGradeManhoursSpentSelect === "Weekly" || individualStaffManhoursSpentSelect === "Weekly") {
  678. // setUnsubmittedTimeSheetSelect("Weekly")
  679. // setTeamTotalManhoursSpentSelect("Weekly")
  680. // setStaffGradeManhoursSpentSelect("Weekly")
  681. // setIndividualStaffManhoursSpentSelect("Weekly")
  682. // }
  683. // }, [unsubmittedTimeSheetSelect, teamTotalManhoursSpentSelect, staffGradeManhoursSpentSelect, individualStaffManhoursSpentSelect]);
  684. const teamOptions = [
  685. { value: 1, label: "XXX Team" },
  686. { value: 2, label: "YYY Team" },
  687. { value: 3, label: "ZZZ Team" },
  688. ];
  689. const columns = [
  690. {
  691. id: "projectCode",
  692. field: "projectCode",
  693. headerName: "Project Code",
  694. flex: 1,
  695. },
  696. {
  697. id: "projectName",
  698. field: "projectName",
  699. headerName: "Project Name",
  700. flex: 1,
  701. },
  702. {
  703. id: "team",
  704. field: "team",
  705. headerName: "Team",
  706. flex: 1,
  707. },
  708. {
  709. id: "teamLeader",
  710. field: "teamLeader",
  711. headerName: "Team Leader",
  712. flex: 1,
  713. },
  714. {
  715. id: "startDate",
  716. field: "startDate",
  717. headerName: "Start Date",
  718. flex: 1,
  719. },
  720. {
  721. id: "targetEndDate",
  722. field: "targetEndDate",
  723. headerName: "Target End Date",
  724. flex: 1,
  725. },
  726. {
  727. id: "client",
  728. field: "client",
  729. headerName: "Client",
  730. flex: 1,
  731. },
  732. {
  733. id: "subsidiary",
  734. field: "subsidiary",
  735. headerName: "Subsidiary",
  736. flex: 1,
  737. },
  738. ];
  739. const options: ApexOptions = {
  740. tooltip: {
  741. y: {
  742. formatter: function (val) {
  743. return val.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
  744. }
  745. }
  746. },
  747. chart: {
  748. height: 350,
  749. type: "line",
  750. },
  751. stroke: {
  752. width: [2, 2],
  753. },
  754. plotOptions: {
  755. bar: {
  756. horizontal: false,
  757. distributed: false,
  758. },
  759. },
  760. dataLabels: {
  761. enabled: true,
  762. },
  763. xaxis: {
  764. categories: teamTotalManhoursSpentPeriod,
  765. },
  766. yaxis: [
  767. {
  768. title: {
  769. text: "Team Total Manhours Spent (Hour)",
  770. },
  771. min: 0,
  772. max: totalManHoursMaxValue,
  773. tickAmount: 5,
  774. labels: {
  775. formatter: function (val) {
  776. return val.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })
  777. }
  778. }
  779. },
  780. ],
  781. grid: {
  782. borderColor: "#f1f1f1",
  783. },
  784. annotations: {},
  785. series: [
  786. {
  787. name: "Planned",
  788. type: "line",
  789. color: "#efbe7d",
  790. data: teamTotalManhoursSpentPlanData,
  791. },
  792. {
  793. name: "Actual",
  794. type: "line",
  795. color: "#7cd3f2",
  796. data: teamTotalManhoursSpentActualData,
  797. },
  798. ],
  799. };
  800. const staffGradeOptions: ApexOptions = {
  801. chart: {
  802. height: 350,
  803. type: "bar",
  804. },
  805. stroke: {
  806. width: [2, 2],
  807. },
  808. plotOptions: {
  809. bar: {
  810. horizontal: true,
  811. distributed: false,
  812. },
  813. },
  814. dataLabels: {
  815. enabled: true,
  816. },
  817. xaxis: {
  818. categories: gradeNameList,
  819. },
  820. yaxis: [
  821. {
  822. title: {
  823. text: "Staff Grade",
  824. },
  825. min: 0,
  826. max: totalManHoursByGradeMaxValue,
  827. tickAmount: 5,
  828. },
  829. ],
  830. grid: {
  831. borderColor: "#f1f1f1",
  832. },
  833. annotations: {},
  834. series: [
  835. {
  836. name: "Planned",
  837. type: "bar",
  838. color: "#efbe7d",
  839. data: totalManhourByGradePlannedManhours,
  840. },
  841. {
  842. name: "Actual",
  843. type: "bar",
  844. color: "#00acb1",
  845. data: totalManhourByGradeActualManhours,
  846. },
  847. ],
  848. };
  849. const individualStaffOptions: ApexOptions = {
  850. chart: {
  851. height: 350,
  852. type: "line",
  853. },
  854. stroke: {
  855. width: [1],
  856. },
  857. plotOptions: {
  858. bar: {
  859. horizontal: true,
  860. distributed: false,
  861. },
  862. },
  863. dataLabels: {
  864. enabled: true,
  865. },
  866. xaxis: {
  867. categories: individualStaffProjectCodeList,
  868. },
  869. yaxis: [
  870. {
  871. title: {
  872. text: "Project",
  873. },
  874. min: 0,
  875. max: individualManhoursMaxValue,
  876. tickAmount: 5,
  877. },
  878. ],
  879. grid: {
  880. borderColor: "#f1f1f1",
  881. },
  882. annotations: {},
  883. tooltip: {
  884. x: {
  885. formatter: (value, { series, seriesIndex, dataPointIndex, w }) => {
  886. return individualStaffProjectList[dataPointIndex];
  887. },
  888. },
  889. },
  890. series: [
  891. {
  892. name: "Manhours(Hour)",
  893. type: "bar",
  894. color: "#00acb1",
  895. data: individualStaffManhours,
  896. },
  897. ],
  898. };
  899. const unsubmittedTimeSheetOptions: ApexOptions = {
  900. chart: {
  901. height: 350,
  902. type: "line",
  903. },
  904. stroke: {
  905. width: [1],
  906. },
  907. plotOptions: {
  908. bar: {
  909. horizontal: true,
  910. distributed: false,
  911. },
  912. },
  913. dataLabels: {
  914. enabled: true,
  915. },
  916. xaxis: {
  917. categories: currentPageUnsubmitStaffList,
  918. },
  919. yaxis: [
  920. {
  921. title: {
  922. text: "Staff",
  923. },
  924. min: 0,
  925. max: unsubmittedMaxValue,
  926. tickAmount: 5,
  927. },
  928. ],
  929. grid: {
  930. borderColor: "#f1f1f1",
  931. },
  932. annotations: {},
  933. series: [
  934. {
  935. name: "Unsubmitted Time Sheet",
  936. type: "bar",
  937. color: "#00acb1",
  938. data: currentPageunsubmitCount,
  939. },
  940. ],
  941. };
  942. const teamTotalManhoursSpentOnClick = (r: any) => {
  943. setTeamTotalManhoursSpentSelect(r);
  944. if (r === "Weekly") {
  945. fetchWeeklyTeamManhourSpentData()
  946. setValue(dayjs().startOf('week'));
  947. setTeamTotalManhoursSpentPeriod(weekDates);
  948. } else if (r === "Monthly") {
  949. fetchMonthlyTeamManhourSpentData()
  950. setTeamTotalManhoursSpentPeriod(monthDates);
  951. }
  952. };
  953. const individualStaffManhoursSpentOnClick = (r: any) => {
  954. setIndividualStaffManhoursSpentSelect(r);
  955. // if (r === "Weekly") {
  956. // setValue(dayjs(new Date))
  957. // setTeamTotalManhoursSpentPeriod(weekDates)
  958. // setTeamTotalManhoursSpentPlanData([42,42,42,42,42,0,0])
  959. // setTeamTotalManhoursSpentActualData([45,42,60,42,58,0,0])
  960. // setTotalManHoursMaxValue(75)
  961. // } else if (r === "Monthly") {
  962. // setTeamTotalManhoursSpentPeriod(monthDates)
  963. // setTeamTotalManhoursSpentPlanData([840,840,840,840,840,840])
  964. // setTeamTotalManhoursSpentActualData([900,840,1200,840,1160,840])
  965. // setTotalManHoursMaxValue(1250)
  966. // }
  967. };
  968. const unsubmittedTimeSheetOnClick = (r: any) => {
  969. setUnsubmittedTimeSheetSelect(r);
  970. };
  971. const selectWeeklyPeriod = (r: any) => {
  972. const selectDate = new Date(r);
  973. const firstDayOfWeek = selectDate;
  974. firstDayOfWeek.setDate(selectDate.getDate() - selectDate.getDay() + 0);
  975. const weekDates: any[] = [];
  976. const weekFirstDate = new Date(firstDayOfWeek);
  977. for (let i = 0; i < 7; i++) {
  978. const currentDate = new Date(firstDayOfWeek);
  979. currentDate.setDate(firstDayOfWeek.getDate() + i);
  980. const formattedDate = dayjs(currentDate).format("DD MMM (ddd)");
  981. weekDates.push(formattedDate);
  982. }
  983. setTeamTotalManhoursSpentPeriod(weekDates);
  984. setValue(dayjs(firstDayOfWeek));
  985. };
  986. const selectWeeklyPeriodByStaffGrade = (r: any) => {
  987. const selectDate = new Date(r);
  988. const firstDayOfWeek = selectDate
  989. firstDayOfWeek.setDate(selectDate.getDate() - selectDate.getDay() + 0);
  990. const weekDates: any[] = [];
  991. for (let i = 0; i < 7; i++) {
  992. const currentDate = new Date(firstDayOfWeek);
  993. currentDate.setDate(firstDayOfWeek.getDate() + i);
  994. const formattedDate = dayjs(currentDate).format("DD MMM (ddd)");
  995. weekDates.push(formattedDate);
  996. }
  997. setTeamTotalManhoursByStaffGrade(weekDates);
  998. setWeeklyValueByStaffGrade(dayjs(firstDayOfWeek));
  999. setWeeklyToValueByStaffGrade(dayjs(firstDayOfWeek).add(6, 'day'))
  1000. };
  1001. const selectWeeklyPeriodUnsubmittedTimeSheet = (r: any) => {
  1002. const selectDate = new Date(r);
  1003. const firstDayOfWeek = selectDate;
  1004. firstDayOfWeek.setDate(selectDate.getDate() - selectDate.getDay() + 0);
  1005. const weekDates: any[] = [];
  1006. for (let i = 0; i < 7; i++) {
  1007. const currentDate = new Date(firstDayOfWeek);
  1008. currentDate.setDate(firstDayOfWeek.getDate() + i);
  1009. const formattedDate = dayjs(currentDate).format("DD MMM (ddd)");
  1010. weekDates.push(formattedDate);
  1011. }
  1012. setUnsubmittedTimeSheetPeriod(weekDates);
  1013. setWeeklyUnsubmittedTimeSheet(dayjs(firstDayOfWeek));
  1014. };
  1015. const selectWeeklyPeriodIndividualStaff = (r: any) => {
  1016. const selectDate = new Date(r);
  1017. const firstDayOfWeek = selectDate;
  1018. firstDayOfWeek.setDate(selectDate.getDate() - selectDate.getDay() + 0);
  1019. const weekDates: any[] = [];
  1020. for (let i = 0; i < 7; i++) {
  1021. const currentDate = new Date(firstDayOfWeek);
  1022. currentDate.setDate(firstDayOfWeek.getDate() + i);
  1023. const formattedDate = dayjs(currentDate).format("DD MMM (ddd)");
  1024. weekDates.push(formattedDate);
  1025. }
  1026. setIndividualStaffManhoursSpentPeriod(weekDates);
  1027. setWeeklyValueByIndividualStaff(dayjs(firstDayOfWeek));
  1028. };
  1029. const selectMonthlyPeriodFrom = (r: any) => {
  1030. setTotalManHoursMonthlyFromValue(r)
  1031. const monthDates: any[] = [];
  1032. const monthPlanData: any[] = [];
  1033. const monthActualData: any[] = [];
  1034. const selectFromDate = dayjs(r);
  1035. for (
  1036. let date = selectFromDate.clone();
  1037. date.isBefore(totalManHoursMonthlyToValue, "month");
  1038. date = date.add(1, "month")
  1039. ) {
  1040. monthDates.push(date.format("MM-YYYY"));
  1041. monthPlanData.push(840);
  1042. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1043. }
  1044. monthDates.push(totalManHoursMonthlyToValue.format("MM-YYYY"));
  1045. monthPlanData.push(840);
  1046. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1047. setTeamTotalManhoursSpentPlanData(monthPlanData);
  1048. setTeamTotalManhoursSpentActualData(monthActualData);
  1049. setTeamTotalManhoursSpentPeriod(monthDates);
  1050. };
  1051. const selectMonthlyPeriodTo = (r: any) => {
  1052. setTotalManHoursMonthlyToValue(r)
  1053. const monthDates: any[] = [];
  1054. const monthPlanData: any[] = [];
  1055. const monthActualData: any[] = [];
  1056. const selectToDate = dayjs(r);
  1057. for (
  1058. let date = totalManHoursMonthlyFromValue.clone();
  1059. date.isBefore(selectToDate, "month");
  1060. date = date.add(1, "month")
  1061. ) {
  1062. monthDates.push(date.format("MM-YYYY"));
  1063. monthPlanData.push(840);
  1064. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1065. }
  1066. monthDates.push(selectToDate.format("MM-YYYY"));
  1067. monthPlanData.push(840);
  1068. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1069. setTeamTotalManhoursSpentPlanData(monthPlanData);
  1070. setTeamTotalManhoursSpentActualData(monthActualData);
  1071. setTeamTotalManhoursSpentPeriod(monthDates);
  1072. };
  1073. const selectStaffGradeMonthlyPeriodFrom = (r: any) => {
  1074. setTotalManHoursMonthlyFromValue(r)
  1075. const monthDates: any[] = [];
  1076. const monthPlanData: any[] = [];
  1077. const monthActualData: any[] = [];
  1078. const selectFromDate = dayjs(r);
  1079. for (
  1080. let date = selectFromDate.clone();
  1081. date.isBefore(totalManHoursMonthlyToValue, "month");
  1082. date = date.add(1, "month")
  1083. ) {
  1084. monthDates.push(date.format("MM-YYYY"));
  1085. monthPlanData.push(840);
  1086. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1087. }
  1088. monthDates.push(totalManHoursMonthlyToValue.format("MM-YYYY"));
  1089. monthPlanData.push(840);
  1090. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1091. // setTeamTotalManhoursSpentPlanData(monthPlanData)
  1092. // setTeamTotalManhoursSpentActualData(monthActualData)
  1093. setTeamTotalManhoursByStaffGrade(weekDates);
  1094. };
  1095. const selectStaffGradeMonthlyPeriodTo = (r: any) => {
  1096. setTotalManHoursMonthlyToValue(r)
  1097. const monthDates: any[] = [];
  1098. const monthPlanData: any[] = [];
  1099. const monthActualData: any[] = [];
  1100. const selectToDate = dayjs(r);
  1101. for (
  1102. let date = totalManHoursMonthlyFromValue.clone();
  1103. date.isBefore(selectToDate, "month");
  1104. date = date.add(1, "month")
  1105. ) {
  1106. monthDates.push(date.format("MM-YYYY"));
  1107. monthPlanData.push(840);
  1108. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1109. }
  1110. monthDates.push(selectToDate.format("MM-YYYY"));
  1111. monthPlanData.push(840);
  1112. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1113. // setTeamTotalManhoursSpentPlanData(monthPlanData)
  1114. // setTeamTotalManhoursSpentActualData(monthActualData)
  1115. setTeamTotalManhoursByStaffGrade(weekDates);
  1116. };
  1117. const selectUnsubmittedTimeSheetMonthlyPeriodFrom = (r: any) => {
  1118. setUnsubmitMonthlyFromValue(r)
  1119. const monthDates: any[] = [];
  1120. const monthPlanData: any[] = [];
  1121. const monthActualData: any[] = [];
  1122. const selectFromDate = dayjs(r);
  1123. for (
  1124. let date = selectFromDate.clone();
  1125. date.isBefore(unsubmitMonthlyToValue, "month");
  1126. date = date.add(1, "month")
  1127. ) {
  1128. monthDates.push(date.format("MM-YYYY"));
  1129. monthPlanData.push(840);
  1130. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1131. }
  1132. monthDates.push(selectFromDate.format("MM-YYYY"));
  1133. monthPlanData.push(840);
  1134. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1135. // setTeamTotalManhoursSpentPlanData(monthPlanData)
  1136. // setTeamTotalManhoursSpentActualData(monthActualData)
  1137. setUnsubmittedTimeSheetPeriod(weekDates);
  1138. };
  1139. const selectIndividualStaffMonthlyPeriodFrom = (r: any) => {
  1140. setIndivdualManHoursMonthlyFromValue(r)
  1141. const monthDates: any[] = [];
  1142. const monthPlanData: any[] = [];
  1143. const monthActualData: any[] = [];
  1144. const selectFromDate = dayjs(r);
  1145. for (
  1146. let date = selectFromDate.clone();
  1147. date.isBefore(indivdualManHoursMonthlyToValue, "month");
  1148. date = date.add(1, "month")
  1149. ) {
  1150. monthDates.push(date.format("MM-YYYY"));
  1151. // monthPlanData.push(840);
  1152. // monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1153. }
  1154. monthDates.push(selectFromDate.format("MM-YYYY"));
  1155. // monthPlanData.push(840);
  1156. // monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1157. // setTeamTotalManhoursSpentPlanData(monthPlanData)
  1158. // setTeamTotalManhoursSpentActualData(monthActualData)
  1159. setIndividualStaffManhoursSpentPeriod(weekDates);
  1160. };
  1161. const selectUnsubmittedTimeSheetMonthlyPeriodTo = (r: any) => {
  1162. setIndivdualManHoursMonthlyToValue(r)
  1163. const monthDates: any[] = [];
  1164. const monthPlanData: any[] = [];
  1165. const monthActualData: any[] = [];
  1166. const selectToDate = dayjs(r);
  1167. for (
  1168. let date = indivdualManHoursMonthlyToValue.clone();
  1169. date.isBefore(selectToDate, "month");
  1170. date = date.add(1, "month")
  1171. ) {
  1172. monthDates.push(date.format("MM-YYYY"));
  1173. monthPlanData.push(840);
  1174. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1175. }
  1176. monthDates.push(selectToDate.format("MM-YYYY"));
  1177. monthPlanData.push(840);
  1178. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1179. // setTeamTotalManhoursSpentPlanData(monthPlanData)
  1180. // setTeamTotalManhoursSpentActualData(monthActualData)
  1181. setUnsubmittedTimeSheetPeriod(weekDates);
  1182. };
  1183. const selectIndividualStaffMonthlyPeriodTo = (r: any) => {
  1184. setTotalManHoursMonthlyToValue(r)
  1185. const monthDates: any[] = [];
  1186. const monthPlanData: any[] = [];
  1187. const monthActualData: any[] = [];
  1188. const selectToDate = dayjs(r);
  1189. for (
  1190. let date = totalManHoursMonthlyFromValue.clone();
  1191. date.isBefore(selectToDate, "month");
  1192. date = date.add(1, "month")
  1193. ) {
  1194. monthDates.push(date.format("MM-YYYY"));
  1195. monthPlanData.push(840);
  1196. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1197. }
  1198. monthDates.push(selectToDate.format("MM-YYYY"));
  1199. monthPlanData.push(840);
  1200. monthActualData.push(Math.floor(Math.random() * (1200 - 840) + 840));
  1201. // setTeamTotalManhoursSpentPlanData(monthPlanData)
  1202. // setTeamTotalManhoursSpentActualData(monthActualData)
  1203. setIndividualStaffManhoursSpentPeriod(weekDates);
  1204. };
  1205. const options2: ApexOptions = {
  1206. chart: {
  1207. type: "donut",
  1208. },
  1209. colors: ['#f57f90', '#94f7d6', '#87c5f5', '#ab95f5', '#ab95f5'],
  1210. plotOptions: {
  1211. pie: {
  1212. donut: {
  1213. labels: {
  1214. show: false,
  1215. name: {
  1216. show: true,
  1217. },
  1218. value: {
  1219. show: false,
  1220. fontWeight: 500,
  1221. fontSize: "30px",
  1222. color: "#3e98c7",
  1223. },
  1224. total: {
  1225. show: false,
  1226. showAlways: false,
  1227. label: "Spent",
  1228. fontFamily: "sans-serif",
  1229. formatter: function (val) {
  1230. return val + "%";
  1231. },
  1232. },
  1233. },
  1234. },
  1235. },
  1236. },
  1237. series: individualStaffManhoursPercentage,
  1238. labels: individualStaffProjectList,
  1239. legend: {
  1240. show: false,
  1241. },
  1242. responsive: [
  1243. {
  1244. breakpoint: 480,
  1245. options: {
  1246. chart: {
  1247. width: 200,
  1248. },
  1249. legend: {
  1250. position: "bottom",
  1251. show: false,
  1252. },
  1253. },
  1254. },
  1255. ],
  1256. };
  1257. return (
  1258. <>
  1259. <Grid item sm>
  1260. <div style={{ display: "inline-block", width: "40%" }}>
  1261. <div>
  1262. <Grid item xs={12} md={12} lg={12}>
  1263. <Card>
  1264. <CardHeader
  1265. className="text-slate-500"
  1266. title="Team Total Manhours Spent"
  1267. />
  1268. <div style={{ display: "inline-block", width: "99%" }}>
  1269. <div className="w-fit align-top mr-5 float-right">
  1270. {teamTotalManhoursSpentSelect === "Weekly" && (
  1271. <>
  1272. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid rounded-l-md w-32">
  1273. Weekly
  1274. </button>
  1275. <button
  1276. onClick={() => {
  1277. teamTotalManhoursSpentOnClick("Monthly")
  1278. setUnsubmittedTimeSheetSelect("Monthly")
  1279. fetchMonthlyUnsubmittedData()
  1280. setStaffGradeManhoursSpentSelect("Monthly")
  1281. fetchMonthlyTotalManhoursByGradeData()
  1282. setIndividualStaffManhoursSpentSelect("Monthly")
  1283. fetchMonthlyIndividualManhoursData()
  1284. }
  1285. }
  1286. 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"
  1287. >
  1288. Monthly
  1289. </button>
  1290. </>
  1291. )}
  1292. {teamTotalManhoursSpentSelect === "Monthly" && (
  1293. <>
  1294. <button
  1295. onClick={() => {
  1296. teamTotalManhoursSpentOnClick("Weekly")
  1297. setUnsubmittedTimeSheetSelect("Weekly")
  1298. fetchWeeklyUnsubmittedData()
  1299. setStaffGradeManhoursSpentSelect("Weekly")
  1300. fetchTotalManhoursByGradeData()
  1301. setIndividualStaffManhoursSpentSelect("Weekly")
  1302. fetchWeeklyIndividualManhoursData()
  1303. }
  1304. }
  1305. 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"
  1306. >
  1307. Weekly
  1308. </button>
  1309. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid rounded-r-md w-32">
  1310. Monthly
  1311. </button>
  1312. </>
  1313. )}
  1314. </div>
  1315. <div className="inline-block w-fit mt-2">
  1316. {abilityViewDashboardAll &&
  1317. <div className="inline-block">
  1318. <div className="inline-block ml-6">
  1319. <Label className="text-slate-500 font-medium">
  1320. Team:&nbsp;
  1321. </Label>
  1322. </div>
  1323. <div className="inline-block ml-1 w-60">
  1324. <Select
  1325. placeholder="Please select a team"
  1326. options={teamManhoursTeamOptions}
  1327. isClearable={true}
  1328. onChange={(selectedOption: any) => {
  1329. if (selectedOption === null) {
  1330. setTeamManhoursTeamId(null);
  1331. } else {
  1332. setTeamManhoursTeamId(selectedOption.value);
  1333. }
  1334. }}
  1335. />
  1336. </div>
  1337. </div>}
  1338. <div className="ml-6 mt-2" style={{ verticalAlign: "top" }}>
  1339. {/* <Label className="text-slate-500 font-medium ml-6">
  1340. Period:&nbsp;
  1341. </Label> */}
  1342. {teamTotalManhoursSpentSelect === "Weekly" && (
  1343. <LocalizationProvider dateAdapter={AdapterDayjs}>
  1344. <DatePicker
  1345. className="w-72 h-10 align-top"
  1346. label="Period:"
  1347. value={value}
  1348. format="DD-MM-YYYY"
  1349. onChange={(newValue) => {
  1350. selectWeeklyPeriod(newValue)
  1351. }
  1352. }
  1353. showDaysOutsideCurrentMonth
  1354. displayWeekNumber
  1355. slots={{ day: Day }}
  1356. slotProps={{
  1357. day: (ownerState) =>
  1358. ({
  1359. selectedDay: value,
  1360. hoveredDay,
  1361. onPointerEnter: () =>
  1362. setHoveredDay(ownerState.day),
  1363. onPointerLeave: () => setHoveredDay(null),
  1364. }) as any,
  1365. }}
  1366. />
  1367. </LocalizationProvider>
  1368. )}
  1369. {teamTotalManhoursSpentSelect === "Monthly" && (
  1370. <LocalizationProvider dateAdapter={AdapterDayjs}>
  1371. <DatePicker
  1372. className="w-44 h-10 align-top"
  1373. onChange={(newValue) =>
  1374. selectMonthlyPeriodFrom(newValue)
  1375. }
  1376. defaultValue={totalManHoursMonthlyFromValue}
  1377. label={"From"}
  1378. views={["month", "year"]}
  1379. />
  1380. <DatePicker
  1381. className="w-40 h-10 align-top"
  1382. onChange={(newValue) =>
  1383. selectMonthlyPeriodTo(newValue)
  1384. }
  1385. defaultValue={totalManHoursMonthlyToValue}
  1386. label={"To"}
  1387. views={["month", "year"]}
  1388. />
  1389. </LocalizationProvider>
  1390. )}
  1391. </div>
  1392. </div>
  1393. <ReactApexChart
  1394. options={options}
  1395. series={options.series}
  1396. type="line"
  1397. height="400"
  1398. />
  1399. </div>
  1400. </Card>
  1401. </Grid>
  1402. </div>
  1403. <div className="mt-5">
  1404. <Grid item xs={12} md={12} lg={12}>
  1405. <Card>
  1406. <CardHeader
  1407. className="text-slate-500"
  1408. title="Total Manhours Spent by Staff Grade"
  1409. />
  1410. <div style={{ display: "inline-block", width: "99%" }}>
  1411. <div className="w-fit align-top mr-5 float-right">
  1412. {staffGradeManhoursSpentSelect === "Weekly" && (
  1413. <>
  1414. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid rounded-l-md w-32">
  1415. Weekly
  1416. </button>
  1417. <button
  1418. onClick={() => {
  1419. teamTotalManhoursSpentOnClick("Monthly")
  1420. setUnsubmittedTimeSheetSelect("Monthly")
  1421. fetchMonthlyUnsubmittedData()
  1422. setStaffGradeManhoursSpentSelect("Monthly")
  1423. fetchMonthlyTotalManhoursByGradeData()
  1424. setIndividualStaffManhoursSpentSelect("Monthly")
  1425. fetchMonthlyIndividualManhoursData()
  1426. }
  1427. }
  1428. 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"
  1429. >
  1430. Monthly
  1431. </button>
  1432. </>
  1433. )}
  1434. {staffGradeManhoursSpentSelect === "Monthly" && (
  1435. <>
  1436. <button
  1437. onClick={() => {
  1438. teamTotalManhoursSpentOnClick("Weekly")
  1439. setUnsubmittedTimeSheetSelect("Weekly")
  1440. fetchWeeklyUnsubmittedData()
  1441. setStaffGradeManhoursSpentSelect("Weekly")
  1442. fetchTotalManhoursByGradeData()
  1443. setIndividualStaffManhoursSpentSelect("Weekly")
  1444. fetchWeeklyIndividualManhoursData()
  1445. }
  1446. }
  1447. 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"
  1448. >
  1449. Weekly
  1450. </button>
  1451. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid rounded-r-md w-48">
  1452. Monthly
  1453. </button>
  1454. </>
  1455. )}
  1456. </div>
  1457. <div className="inline-block w-fit mt-2">
  1458. <div className="inline-block mt-2 ml-6">
  1459. {abilityViewDashboardAll &&
  1460. <div className="inline-block">
  1461. <div className="inline-block ml-6">
  1462. <Label className="text-slate-500 font-medium">
  1463. Team:&nbsp;
  1464. </Label>
  1465. </div>
  1466. <div className="inline-block ml-1 w-60">
  1467. <Select
  1468. placeholder="Please select a team"
  1469. options={teamManhoursTeamOptions}
  1470. isClearable={true}
  1471. onChange={(selectedOption: any) => {
  1472. if (selectedOption === null) {
  1473. setStaffGradeTeamId(null);
  1474. } else {
  1475. setStaffGradeTeamId(selectedOption.value);
  1476. }
  1477. }}
  1478. />
  1479. </div>
  1480. </div>}
  1481. {staffGradeManhoursSpentSelect === "Weekly" && (
  1482. <LocalizationProvider dateAdapter={AdapterDayjs}>
  1483. <DatePicker
  1484. className="w-72 h-10 align-top"
  1485. label="Period:"
  1486. value={weeklyValueByStaffGrade}
  1487. format="DD-MM-YYYY"
  1488. onChange={(newValue) =>
  1489. selectWeeklyPeriodByStaffGrade(newValue)
  1490. }
  1491. showDaysOutsideCurrentMonth
  1492. displayWeekNumber
  1493. slots={{ day: Day }}
  1494. slotProps={{
  1495. day: (ownerState) =>
  1496. ({
  1497. selectedDay: value,
  1498. hoveredDay,
  1499. onPointerEnter: () =>
  1500. setHoveredDay(ownerState.day),
  1501. onPointerLeave: () => setHoveredDay(null),
  1502. }) as any,
  1503. }}
  1504. />
  1505. </LocalizationProvider>
  1506. )}
  1507. {staffGradeManhoursSpentSelect === "Monthly" && (
  1508. <LocalizationProvider dateAdapter={AdapterDayjs}>
  1509. <DatePicker
  1510. className="w-44 h-10 align-top"
  1511. onChange={(newValue) =>
  1512. selectStaffGradeMonthlyPeriodFrom(newValue)
  1513. }
  1514. defaultValue={
  1515. totalManHoursByStaffGradeMonthlyFromValue
  1516. }
  1517. label={"From"}
  1518. views={["month", "year"]}
  1519. />
  1520. <DatePicker
  1521. className="w-40 h-10 align-top"
  1522. onChange={(newValue) =>
  1523. selectStaffGradeMonthlyPeriodTo(newValue)
  1524. }
  1525. defaultValue={
  1526. totalManHoursByStaffGradeMonthlyToValue
  1527. }
  1528. label={"To"}
  1529. views={["month", "year"]}
  1530. />
  1531. </LocalizationProvider>
  1532. )}
  1533. {/* <Label className="text-slate-500 font-medium ml-6">
  1534. Period:&nbsp;
  1535. </Label>
  1536. <Input
  1537. id={'cashFlowYear'}
  1538. value={manHoursSpentPeriod}
  1539. readOnly={true}
  1540. bsSize="lg"
  1541. className="rounded-md text-base w-56 border-slate-200 border-solid text-slate-500 text-center"
  1542. /> */}
  1543. </div>
  1544. </div>
  1545. <ReactApexChart
  1546. options={staffGradeOptions}
  1547. series={staffGradeOptions.series}
  1548. type="bar"
  1549. height="400"
  1550. />
  1551. </div>
  1552. </Card>
  1553. </Grid>
  1554. </div>
  1555. </div>
  1556. <div
  1557. style={{
  1558. display: "inline-block",
  1559. width: "59%",
  1560. verticalAlign: "top",
  1561. marginLeft: 10,
  1562. }}
  1563. >
  1564. <Grid item xs={12} md={12} lg={12}>
  1565. <Card className="mb-5">
  1566. <CardHeader
  1567. className="text-slate-500"
  1568. title="Unsubmitted Time Sheet by Staff"
  1569. />
  1570. <div style={{ display: "inline-block", width: "99%" }}>
  1571. <div className="w-fit align-top mr-5 float-right">
  1572. {unsubmittedTimeSheetSelect === "Weekly" && (
  1573. <>
  1574. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid w-32">
  1575. Weekly
  1576. </button>
  1577. <button
  1578. onClick={() => {
  1579. teamTotalManhoursSpentOnClick("Monthly")
  1580. setUnsubmittedTimeSheetSelect("Monthly")
  1581. fetchMonthlyUnsubmittedData()
  1582. setStaffGradeManhoursSpentSelect("Monthly")
  1583. fetchMonthlyTotalManhoursByGradeData()
  1584. setIndividualStaffManhoursSpentSelect("Monthly")
  1585. fetchMonthlyIndividualManhoursData()
  1586. }
  1587. }
  1588. 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"
  1589. >
  1590. Monthly
  1591. </button>
  1592. </>
  1593. )}
  1594. {unsubmittedTimeSheetSelect === "Monthly" && (
  1595. <>
  1596. <button
  1597. onClick={() => {
  1598. teamTotalManhoursSpentOnClick("Weekly")
  1599. setUnsubmittedTimeSheetSelect("Weekly")
  1600. fetchWeeklyUnsubmittedData()
  1601. setStaffGradeManhoursSpentSelect("Weekly")
  1602. fetchTotalManhoursByGradeData()
  1603. setIndividualStaffManhoursSpentSelect("Weekly")
  1604. fetchWeeklyIndividualManhoursData()
  1605. }
  1606. }
  1607. className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid w-32"
  1608. >
  1609. Weekly
  1610. </button>
  1611. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid rounded-r-md w-32">
  1612. Monthly
  1613. </button>
  1614. </>
  1615. )}
  1616. </div>
  1617. <div className="inline-block w-fit mt-2">
  1618. {abilityViewDashboardAll && <div className="inline-block">
  1619. <div className="inline-block ml-6">
  1620. <Label className="text-slate-500 font-medium">
  1621. Team:&nbsp;
  1622. </Label>
  1623. </div>
  1624. <div className="inline-block ml-1 w-60">
  1625. <Select
  1626. placeholder="Please select a team"
  1627. options={teamManhoursTeamOptions}
  1628. isClearable={true}
  1629. onChange={(selectedOption: any) => {
  1630. if (selectedOption === null) {
  1631. setTeamUnsubmitTeamId(null);
  1632. } else {
  1633. setTeamUnsubmitTeamId(selectedOption.value);
  1634. }
  1635. }}
  1636. />
  1637. </div>
  1638. </div>}
  1639. <div className="ml-6 mt-2" style={{ verticalAlign: "top" }}>
  1640. {/* <Label className="text-slate-500 font-medium ml-6">
  1641. Period:&nbsp;
  1642. </Label> */}
  1643. {unsubmittedTimeSheetSelect === "Weekly" && (
  1644. <LocalizationProvider dateAdapter={AdapterDayjs}>
  1645. <DatePicker
  1646. className="w-72 h-10 align-top"
  1647. label="Period:"
  1648. value={value}
  1649. format="DD-MM-YYYY"
  1650. onChange={(newValue) =>
  1651. selectWeeklyPeriodUnsubmittedTimeSheet(newValue)
  1652. }
  1653. showDaysOutsideCurrentMonth
  1654. displayWeekNumber
  1655. slots={{ day: Day }}
  1656. slotProps={{
  1657. day: (ownerState) =>
  1658. ({
  1659. selectedDay: value,
  1660. hoveredDay,
  1661. onPointerEnter: () =>
  1662. setHoveredDay(ownerState.day),
  1663. onPointerLeave: () => setHoveredDay(null),
  1664. }) as any,
  1665. }}
  1666. />
  1667. </LocalizationProvider>
  1668. )}
  1669. {unsubmittedTimeSheetSelect === "Monthly" && (
  1670. <LocalizationProvider dateAdapter={AdapterDayjs}>
  1671. <DatePicker
  1672. className="w-40 h-10 align-top"
  1673. onChange={(newValue) =>
  1674. selectUnsubmittedTimeSheetMonthlyPeriodFrom(newValue)
  1675. }
  1676. defaultValue={
  1677. unsubmitMonthlyFromValue
  1678. }
  1679. label={"On"}
  1680. views={["month", "year"]}
  1681. />
  1682. {/* <DatePicker
  1683. className="w-40 h-10 align-top"
  1684. onChange={(newValue) =>
  1685. selectUnsubmittedTimeSheetMonthlyPeriodTo(newValue)
  1686. }
  1687. defaultValue={
  1688. totalManHoursByIndividualStaffMonthlyToValue
  1689. }
  1690. label={"To"}
  1691. views={["month", "year"]}
  1692. /> */}
  1693. </LocalizationProvider>
  1694. )}
  1695. </div>
  1696. </div>
  1697. <ReactApexChart
  1698. options={unsubmittedTimeSheetOptions}
  1699. series={unsubmittedTimeSheetOptions.series}
  1700. type="bar"
  1701. height="380"
  1702. />
  1703. <div className="float-right mr-4 mb-10">
  1704. {currentPage === 1 && (
  1705. <button className="bg-blue-500 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-l">
  1706. Pervious
  1707. </button>
  1708. )}
  1709. {currentPage !== 1 && (
  1710. <button onClick={handlePrevPage} className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 outline-none rounded-l">
  1711. Previous
  1712. </button>
  1713. )}
  1714. {endIndex >= unsubmitCount.length && (
  1715. <button className="bg-blue-500 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-r mr-2">
  1716. Next
  1717. </button>
  1718. )}
  1719. {endIndex < unsubmitCount.length && (
  1720. <button onClick={handleNextPage} className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 outline-none rounded-r mr-2">
  1721. Next
  1722. </button>
  1723. )}
  1724. Page&nbsp;
  1725. {unsubmitCount.length === 0 && (
  1726. 0
  1727. )}
  1728. {unsubmitCount.length > 0 && (
  1729. currentPage
  1730. )}
  1731. &nbsp;of&nbsp;
  1732. {Math.ceil(unsubmitCount.length / recordsPerPage)}
  1733. </div>
  1734. </div>
  1735. </Card>
  1736. <Card>
  1737. <Card>
  1738. <CardHeader
  1739. className="text-slate-500"
  1740. title="Manhours Spent by Individual Staff"
  1741. />
  1742. <div style={{ display: "inline-block", width: "99%" }}>
  1743. <div className="w-fit align-top mr-5 float-right">
  1744. {individualStaffManhoursSpentSelect === "Daily" && (
  1745. <>
  1746. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid rounded-l-md w-32">
  1747. Daily
  1748. </button>
  1749. <button
  1750. onClick={() => {
  1751. individualStaffManhoursSpentOnClick("Weekly")
  1752. fetchWeeklyIndividualManhoursData()
  1753. }
  1754. }
  1755. className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid w-32"
  1756. >
  1757. Weekly
  1758. </button>
  1759. <button
  1760. onClick={() => {
  1761. individualStaffManhoursSpentOnClick("Monthly")
  1762. fetchMonthlyIndividualManhoursData()
  1763. }
  1764. }
  1765. 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"
  1766. >
  1767. Monthly
  1768. </button>
  1769. </>
  1770. )}
  1771. {individualStaffManhoursSpentSelect === "Weekly" && (
  1772. <>
  1773. {/* <button
  1774. onClick={() => {
  1775. individualStaffManhoursSpentOnClick("Daily")
  1776. fetchDailyIndividualManhoursData()
  1777. }
  1778. }
  1779. 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"
  1780. >
  1781. Daily
  1782. </button> */}
  1783. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid w-32">
  1784. Weekly
  1785. </button>
  1786. <button
  1787. onClick={() => {
  1788. teamTotalManhoursSpentOnClick("Monthly")
  1789. setUnsubmittedTimeSheetSelect("Monthly")
  1790. fetchMonthlyUnsubmittedData()
  1791. setStaffGradeManhoursSpentSelect("Monthly")
  1792. fetchMonthlyTotalManhoursByGradeData()
  1793. setIndividualStaffManhoursSpentSelect("Monthly")
  1794. fetchMonthlyIndividualManhoursData()
  1795. }
  1796. }
  1797. 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"
  1798. >
  1799. Monthly
  1800. </button>
  1801. </>
  1802. )}
  1803. {individualStaffManhoursSpentSelect === "Monthly" && (
  1804. <>
  1805. {/* <button
  1806. onClick={() => {
  1807. individualStaffManhoursSpentOnClick("Daily")
  1808. fetchDailyIndividualManhoursData()
  1809. }
  1810. }
  1811. 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"
  1812. >
  1813. Daily
  1814. </button> */}
  1815. <button
  1816. onClick={() => {
  1817. teamTotalManhoursSpentOnClick("Weekly")
  1818. setUnsubmittedTimeSheetSelect("Weekly")
  1819. fetchWeeklyUnsubmittedData()
  1820. setStaffGradeManhoursSpentSelect("Weekly")
  1821. fetchTotalManhoursByGradeData()
  1822. setIndividualStaffManhoursSpentSelect("Weekly")
  1823. fetchWeeklyIndividualManhoursData()
  1824. }
  1825. }
  1826. className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid w-32"
  1827. >
  1828. Weekly
  1829. </button>
  1830. <button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid rounded-r-md w-32">
  1831. Monthly
  1832. </button>
  1833. </>
  1834. )}
  1835. </div>
  1836. <div className="inline-block w-fit mt-2">
  1837. <div className="inline-block ml-6">
  1838. <Label className="text-slate-500 font-medium">
  1839. Staff Code and Name:&nbsp;
  1840. </Label>
  1841. </div>
  1842. <div className="inline-block ml-1 w-60">
  1843. <Select
  1844. placeholder="Please select a staff"
  1845. options={staffOptions}
  1846. isClearable={true}
  1847. onChange={(selectedOption: any) => {
  1848. if (selectedOption === null) {
  1849. setStaffId(null);
  1850. } else {
  1851. setStaffId(selectedOption.value);
  1852. }
  1853. }}
  1854. />
  1855. </div>
  1856. <div className="ml-6 mt-2" style={{ verticalAlign: "top" }}>
  1857. {/* <Label className="text-slate-500 font-medium ml-6">
  1858. Period:&nbsp;
  1859. </Label> */}
  1860. {individualStaffManhoursSpentSelect === "Daily" && (
  1861. <LocalizationProvider dateAdapter={AdapterDayjs}>
  1862. <DatePicker
  1863. className="w-40 h-10 align-top"
  1864. format="DD-MM-YYYY"
  1865. onChange={(newValue: any) =>
  1866. setTotalManHoursByIndividualStaffDailyFromValue(newValue)
  1867. // selectIndividualStaffMonthlyPeriodFrom(newValue)
  1868. }
  1869. defaultValue={
  1870. totalManHoursByIndividualStaffDailyFromValue
  1871. }
  1872. label={"On"}
  1873. views={["day"]}
  1874. />
  1875. {/* <DatePicker
  1876. className="w-40 h-10 align-top"
  1877. onChange={(newValue) =>
  1878. selectIndividualStaffMonthlyPeriodTo(newValue)
  1879. }
  1880. defaultValue={
  1881. totalManHoursByIndividualStaffDailyToValue
  1882. }
  1883. label={"To"}
  1884. views={["day", "month", "year"]}
  1885. /> */}
  1886. </LocalizationProvider>
  1887. )}
  1888. {individualStaffManhoursSpentSelect === "Weekly" && (
  1889. <LocalizationProvider dateAdapter={AdapterDayjs}>
  1890. <DatePicker
  1891. className="w-72 h-10 align-top"
  1892. label="Period:"
  1893. value={value}
  1894. format="DD-MM-YYYY"
  1895. onChange={(newValue) =>
  1896. selectWeeklyPeriodIndividualStaff(newValue)
  1897. }
  1898. showDaysOutsideCurrentMonth
  1899. displayWeekNumber
  1900. slots={{ day: Day }}
  1901. slotProps={{
  1902. day: (ownerState) =>
  1903. ({
  1904. selectedDay: value,
  1905. hoveredDay,
  1906. onPointerEnter: () =>
  1907. setHoveredDay(ownerState.day),
  1908. onPointerLeave: () => setHoveredDay(null),
  1909. }) as any,
  1910. }}
  1911. />
  1912. </LocalizationProvider>
  1913. )}
  1914. {individualStaffManhoursSpentSelect === "Monthly" && (
  1915. <LocalizationProvider dateAdapter={AdapterDayjs}>
  1916. <DatePicker
  1917. className="w-40 h-10 align-top"
  1918. onChange={(newValue: any) => {
  1919. console.log(newValue)
  1920. setIndivdualManHoursMonthlyFromValue(newValue)
  1921. }
  1922. // selectIndividualStaffMonthlyPeriodFrom(newValue)
  1923. }
  1924. defaultValue={
  1925. indivdualManHoursMonthlyFromValue
  1926. }
  1927. label={"On"}
  1928. views={["month", "year"]}
  1929. />
  1930. {/* <DatePicker
  1931. className="w-40 h-10 align-top"
  1932. onChange={(newValue) =>
  1933. selectIndividualStaffMonthlyPeriodTo(newValue)
  1934. }
  1935. defaultValue={
  1936. totalManHoursByIndividualStaffMonthlyToValue
  1937. }
  1938. label={"To"}
  1939. views={["month", "year"]}
  1940. /> */}
  1941. </LocalizationProvider>
  1942. )}
  1943. </div>
  1944. </div>
  1945. <ReactApexChart
  1946. options={individualStaffOptions}
  1947. series={individualStaffOptions.series}
  1948. type="bar"
  1949. height="380"
  1950. />
  1951. </div>
  1952. </Card>
  1953. <div style={{ display: "inline-block", width: "50%" }}>
  1954. <div
  1955. style={{
  1956. display: "inline-block",
  1957. width: "47%",
  1958. marginTop: 10,
  1959. marginLeft: 10,
  1960. }}
  1961. >
  1962. <Card style={{ height: 90 }}>
  1963. <div className="text-slate-500 text-center text-base">
  1964. Total Normal Hours Spent
  1965. </div>
  1966. <div
  1967. className="text-center w-full text-3xl font-bold"
  1968. style={{ color: "#92c1e9" }}
  1969. >
  1970. {totalNormalConsumption.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
  1971. </div>
  1972. </Card>
  1973. <Card style={{ marginTop: 10, height: 90 }}>
  1974. <div className="text-slate-500 text-center text-base">
  1975. Total Leave Hours
  1976. </div>
  1977. <div
  1978. className="text-center w-full text-3xl font-bold"
  1979. style={{ color: "#898d8d", marginTop: 10 }}
  1980. >
  1981. {totalLeaveHours.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
  1982. </div>
  1983. </Card>
  1984. </div>
  1985. <div
  1986. style={{
  1987. display: "inline-block",
  1988. width: "47%",
  1989. marginTop: 10,
  1990. marginLeft: 10,
  1991. verticalAlign: "top"
  1992. }}
  1993. >
  1994. <Card style={{ height: 90 }}>
  1995. <div className="text-slate-500 text-center text-base">
  1996. Total Other Hours Spent
  1997. </div>
  1998. <div
  1999. className="text-center w-full text-3xl font-bold"
  2000. style={{ color: "#92c1e9" }}
  2001. >
  2002. {totalOtConsumption.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
  2003. </div>
  2004. </Card>
  2005. {/* <Card style={{ marginTop: 10, height: 90 }}>
  2006. <div className="text-slate-500 text-center text-base">
  2007. Remaining Hours
  2008. </div>
  2009. <div
  2010. className="text-center w-full text-3xl font-bold"
  2011. style={{ color: "#898d8d", marginTop: 10 }}
  2012. >
  2013. 0.00
  2014. </div>
  2015. </Card> */}
  2016. </div>
  2017. </div>
  2018. <div style={{ display: "inline-block", width: "50%", verticalAlign: "top", marginTop: 10 }}>
  2019. <Card>
  2020. <CardHeader className="text-slat-500" title="Effort Proportion for individual Staff" />
  2021. <ReactApexChart
  2022. options={options2}
  2023. series={options2.series}
  2024. type="donut"
  2025. />
  2026. </Card>
  2027. </div>
  2028. </Card>
  2029. </Grid>
  2030. </div>
  2031. </Grid>
  2032. </>
  2033. );
  2034. };
  2035. export default StaffUtilization;