Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 

621 Zeilen
18 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 ProgressByTeamSearch from "@/components/ProgressByTeamSearch";
  20. import { Suspense } from "react";
  21. const ProgressByTeam: React.FC = () => {
  22. const [activeTab, setActiveTab] = useState("financialSummary");
  23. const [SearchCriteria, setSearchCriteria] = React.useState({});
  24. const { t } = useTranslation("dashboard");
  25. const [teamCode, setTeamCode] = useState("");
  26. const [teamName, setTeamName] = useState("");
  27. const [projectArray, setProjectArray]: any[] = useState([]);
  28. const [percentageArray, setPercentageArray]: any[] = useState([]);
  29. const [colorArray, setColorArray]: any[] = useState([]);
  30. const [selectionModel, setSelectionModel]: any[] = React.useState([]);
  31. const [pieChartColor, setPieChartColor]: any[] = React.useState([]);
  32. const [totalSpentPercentage, setTotalSpentPercentage]: any = React.useState();
  33. const [projectBudgetManhour, setProjectBudgetManhour]: any =
  34. React.useState("-");
  35. const [actualManhourSpent, setActualManhourSpent]: any = React.useState("-");
  36. const [remainedManhour, setRemainedManhour]: any = React.useState("-");
  37. const [lastUpdate, setLastUpdate]: any = React.useState("-");
  38. const [dropdownDemo, setDropdownDemo] = useState("");
  39. const [dateDemo, setDateDemo] = useState(null);
  40. const [checkboxDemo, setCheckboxDemo] = useState(false);
  41. const [receiptFromDate, setReceiptFromDate] = useState(null);
  42. const [receiptToDate, setReceiptToDate] = useState(null);
  43. const [selectedRows, setSelectedRows] = useState([]);
  44. const rows = [
  45. {
  46. id: 1,
  47. teamCode: "TEAM-001",
  48. teamName: "Team A",
  49. noOfProjects: "5",
  50. },
  51. {
  52. id: 2,
  53. teamCode: "TEAM-001",
  54. teamName: "Team B",
  55. noOfProjects: "5",
  56. },
  57. {
  58. id: 3,
  59. teamCode: "TEAM-001",
  60. teamName: "Team C",
  61. noOfProjects: "3",
  62. },
  63. {
  64. id: 4,
  65. teamCode: "TEAM-001",
  66. teamName: "Team D",
  67. noOfProjects: "1",
  68. },
  69. ];
  70. //['#f57f90', '#94f7d6', '#87c5f5', '#ab95f5', '#fcd68b']
  71. const rows2 = [
  72. {
  73. id: 1,
  74. project: "Consultancy Project 123",
  75. team: "XXX",
  76. teamLeader: "XXX",
  77. currentStage: "Contract Documentation",
  78. budgetedManhour: "200.00",
  79. spentManhour: "120.00",
  80. remainedManhour: "80.00",
  81. comingPaymentMilestone: "31/03/2024",
  82. alert: false,
  83. color: "#f57f90",
  84. },
  85. {
  86. id: 2,
  87. project: "Consultancy Project 456",
  88. team: "XXX",
  89. teamLeader: "XXX",
  90. currentStage: "Report Preparation",
  91. budgetedManhour: "400.00",
  92. spentManhour: "200.00",
  93. remainedManhour: "200.00",
  94. comingPaymentMilestone: "20/02/2024",
  95. alert: false,
  96. color: "#94f7d6",
  97. },
  98. {
  99. id: 3,
  100. project: "Construction Project A",
  101. team: "YYY",
  102. teamLeader: "YYY",
  103. currentStage: "Construction",
  104. budgetedManhour: "187.50",
  105. spentManhour: "200.00",
  106. remainedManhour: "12.50",
  107. comingPaymentMilestone: "13/12/2023",
  108. alert: true,
  109. color: "#87c5f5",
  110. },
  111. {
  112. id: 4,
  113. project: "Construction Project B",
  114. team: "XXX",
  115. teamLeader: "XXX",
  116. currentStage: "Post Construction",
  117. budgetedManhour: "100.00",
  118. spentManhour: "40.00",
  119. remainedManhour: "60.00",
  120. comingPaymentMilestone: "05/01/2024",
  121. alert: false,
  122. color: "#ab95f5",
  123. },
  124. {
  125. id: 5,
  126. project: "Construction Project C",
  127. team: "YYY",
  128. teamLeader: "YYY",
  129. currentStage: "Construction",
  130. budgetedManhour: "300.00",
  131. spentManhour: "150.00",
  132. remainedManhour: "150.00",
  133. comingPaymentMilestone: "31/03/2024",
  134. alert: false,
  135. color: "#fcd68b",
  136. },
  137. ];
  138. const columns = [
  139. {
  140. id: "clientCode",
  141. field: "clientCode",
  142. headerName: "Client Code",
  143. flex: 1,
  144. },
  145. {
  146. id: "clientName",
  147. field: "clientName",
  148. headerName: "Client Name",
  149. flex: 1,
  150. },
  151. {
  152. id: "clientSubsidiaryCode",
  153. field: "clientSubsidiaryCode",
  154. headerName: "Client Subsidiary Code",
  155. flex: 1,
  156. },
  157. {
  158. id: "noOfProjects",
  159. field: "noOfProjects",
  160. headerName: "No. of Projects",
  161. flex: 1,
  162. },
  163. ];
  164. const columns2 = [
  165. {
  166. id: "color",
  167. field: "color",
  168. headerName: "",
  169. renderCell: (params: any) => {
  170. return (
  171. <span
  172. className="dot"
  173. style={{
  174. height: "15px",
  175. width: "15px",
  176. borderRadius: "50%",
  177. backgroundColor: `${params.row.color}`,
  178. display: "inline-block",
  179. }}
  180. ></span>
  181. );
  182. },
  183. flex: 0.1,
  184. },
  185. {
  186. id: "project",
  187. field: "project",
  188. headerName: "Project",
  189. flex: 1,
  190. },
  191. {
  192. id: "team",
  193. field: "team",
  194. headerName: "Team",
  195. flex: 0.8,
  196. },
  197. {
  198. id: "teamLeader",
  199. field: "teamLeader",
  200. headerName: "Team Leader",
  201. flex: 0.8,
  202. },
  203. {
  204. id: "currentStage",
  205. field: "currentStage",
  206. headerName: "Current Stage",
  207. flex: 1,
  208. },
  209. {
  210. id: "budgetedManhour",
  211. field: "budgetedManhour",
  212. headerName: "Budgeted Manhour",
  213. flex: 0.8,
  214. },
  215. {
  216. id: "spentManhour",
  217. field: "spentManhour",
  218. headerName: "Spent Manhour",
  219. renderCell: (params: any) => {
  220. if (params.row.budgetedManhour - params.row.spentManhour <= 0) {
  221. return (
  222. <span className="text-red-300">{params.row.spentManhour}</span>
  223. );
  224. } else {
  225. return <span>{params.row.spentManhour}</span>;
  226. }
  227. },
  228. flex: 0.8,
  229. },
  230. {
  231. id: "remainedManhour",
  232. field: "remainedManhour",
  233. headerName: "Remained Manhour",
  234. renderCell: (params: any) => {
  235. if (params.row.budgetedManhour - params.row.spentManhour <= 0) {
  236. return (
  237. <span className="text-red-300">({params.row.remainedManhour})</span>
  238. );
  239. } else {
  240. return <span>{params.row.remainedManhour}</span>;
  241. }
  242. },
  243. flex: 1,
  244. },
  245. {
  246. id: "comingPaymentMilestone",
  247. field: "comingPaymentMilestone",
  248. headerName: "Coming Payment Milestone",
  249. flex: 1,
  250. },
  251. {
  252. id: "alert",
  253. field: "alert",
  254. headerName: "Alert",
  255. renderCell: (params: any) => {
  256. if (params.row.alert === true) {
  257. return (
  258. <span className="text-red-300 text-center">
  259. <ReportProblemIcon />
  260. </span>
  261. );
  262. } else {
  263. return <span></span>;
  264. }
  265. },
  266. flex: 0.2,
  267. },
  268. ];
  269. const InputFields = [
  270. {
  271. id: "teamCode",
  272. label: "Team Code",
  273. type: "text",
  274. value: teamCode,
  275. setValue: setTeamCode,
  276. },
  277. {
  278. id: "teamName",
  279. label: "Team Name",
  280. type: "text",
  281. value: teamName,
  282. setValue: setTeamName,
  283. },
  284. // { id: 'dropdownDemo', label: "dropdownDemo", type: 'dropdown', options: [{id:"1", label:"1"}], value: dropdownDemo, setValue: setDropdownDemo },
  285. // { id: 'dateDemo', label:'dateDemo', type: 'date', value: dateDemo, setValue: setDateDemo },
  286. // { id: 'checkboxDemo', label:'checkboxDemo', type: 'checkbox', value: checkboxDemo, setValue: setCheckboxDemo },
  287. // { id: ['receiptFromDate','receiptToDate'], label: ["收貨日期","收貨日期"], value: [receiptFromDate ? receiptFromDate : null, receiptToDate ? receiptToDate : null],
  288. // setValue: [setReceiptFromDate, setReceiptToDate],type: 'dateRange' },
  289. ];
  290. const stageDeadline = [
  291. "31/03/2024",
  292. "20/02/2024",
  293. "01/12/2023",
  294. "05/01/2024",
  295. "31/03/2023",
  296. ];
  297. const series2: ApexAxisChartSeries | ApexNonAxisChartSeries = [
  298. {
  299. data: [17.1, 28.6, 5.7, 48.6],
  300. },
  301. ];
  302. const series: ApexAxisChartSeries | ApexNonAxisChartSeries = [
  303. {
  304. name: "Project Resource Consumption Percentage",
  305. data: [80, 55, 40, 65, 70],
  306. },
  307. ];
  308. const options2: ApexOptions = {
  309. chart: {
  310. type: "donut",
  311. },
  312. colors: colorArray,
  313. plotOptions: {
  314. pie: {
  315. donut: {
  316. labels: {
  317. show: true,
  318. name: {
  319. show: true,
  320. },
  321. value: {
  322. show: true,
  323. fontWeight: 500,
  324. fontSize: "30px",
  325. color: "#3e98c7",
  326. },
  327. total: {
  328. show: true,
  329. showAlways: true,
  330. label: "Spent",
  331. fontFamily: "sans-serif",
  332. formatter: function (val) {
  333. return totalSpentPercentage + "%";
  334. },
  335. },
  336. },
  337. },
  338. },
  339. },
  340. labels: projectArray,
  341. legend: {
  342. show: false,
  343. },
  344. responsive: [
  345. {
  346. breakpoint: 480,
  347. options: {
  348. chart: {
  349. width: 200,
  350. },
  351. legend: {
  352. position: "bottom",
  353. show: false,
  354. },
  355. },
  356. },
  357. ],
  358. };
  359. const options: ApexOptions = {
  360. chart: {
  361. type: "bar",
  362. height: 350,
  363. },
  364. colors: ["#f57f90", "#94f7d6", "#87c5f5", "#ab95f5", "#fcd68b"],
  365. plotOptions: {
  366. bar: {
  367. horizontal: true,
  368. distributed: true,
  369. },
  370. },
  371. dataLabels: {
  372. enabled: false,
  373. },
  374. xaxis: {
  375. categories: [
  376. "Consultancy Project 123",
  377. "Consultancy Project 456",
  378. "Construction Project A",
  379. "Construction Project B",
  380. "Construction Project C",
  381. ],
  382. },
  383. yaxis: {
  384. title: {
  385. text: "Projects",
  386. },
  387. labels: {
  388. maxWidth: 200,
  389. style: {
  390. cssClass: "apexcharts-yaxis-label",
  391. },
  392. },
  393. },
  394. title: {
  395. text: "Project Resource Consumption Percentage",
  396. align: "center",
  397. },
  398. grid: {
  399. borderColor: "#f1f1f1",
  400. },
  401. annotations: {},
  402. };
  403. const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => {
  404. const selectedRowsData = rows2.filter((row) =>
  405. newSelectionModel.includes(row.id),
  406. );
  407. console.log(selectedRowsData);
  408. const projectArray = [];
  409. const pieChartColorArray = [];
  410. let totalSpent = 0;
  411. let totalBudgetManhour = 0;
  412. const percentageArray = [];
  413. for (let i = 0; i <= selectedRowsData.length; i++) {
  414. if (i === selectedRowsData.length && i > 0) {
  415. projectArray.push("Remained");
  416. } else if (selectedRowsData.length > 0) {
  417. projectArray.push(selectedRowsData[i].project);
  418. totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour);
  419. totalSpent += Number(selectedRowsData[i].spentManhour);
  420. pieChartColorArray.push(selectedRowsData[i].color);
  421. }
  422. }
  423. for (let i = 0; i <= selectedRowsData.length; i++) {
  424. if (i === selectedRowsData.length && i > 0) {
  425. const remainedManhour = totalBudgetManhour - totalSpent;
  426. percentageArray.push(
  427. Number(((remainedManhour / totalBudgetManhour) * 100).toFixed(1)),
  428. );
  429. } else if (selectedRowsData.length > 0) {
  430. const percentage = (
  431. (Number(selectedRowsData[i].spentManhour) / totalBudgetManhour) *
  432. 100
  433. ).toFixed(1);
  434. percentageArray.push(Number(percentage));
  435. }
  436. }
  437. setProjectBudgetManhour(totalBudgetManhour.toFixed(2));
  438. setActualManhourSpent(totalSpent.toFixed(2));
  439. setRemainedManhour((totalBudgetManhour - totalSpent).toFixed(2));
  440. setLastUpdate(new Date().toLocaleDateString("en-GB"));
  441. setSelectionModel(newSelectionModel);
  442. console.log(projectArray);
  443. setProjectArray(projectArray);
  444. setPercentageArray(percentageArray);
  445. console.log(percentageArray);
  446. setTotalSpentPercentage(
  447. ((totalSpent / totalBudgetManhour) * 100).toFixed(1),
  448. );
  449. if (projectArray.length > 0 && projectArray.includes("Remained")) {
  450. const nonLastRecordColors = pieChartColorArray;
  451. setColorArray([
  452. ...nonLastRecordColors.slice(0, projectArray.length - 1),
  453. "#a3a3a3",
  454. ]);
  455. } else {
  456. setColorArray(pieChartColorArray);
  457. }
  458. };
  459. const applySearch = (data: any) => {
  460. console.log(data);
  461. setSearchCriteria(data);
  462. };
  463. return (
  464. <Grid item sm>
  465. {/* <CustomSearchForm applySearch={applySearch} fields={InputFields}/> */}
  466. {/* <CustomDatagrid rows={rows} columns={columns} columnWidth={200} dataGridHeight={300}/> */}
  467. <div style={{ display: "inline-block", width: "70%" }}>
  468. <Grid item xs={12} md={12} lg={12}>
  469. <Card>
  470. <CardHeader className="text-slate-500" title="Project Resource Consumption" />
  471. <div style={{ display: "inline-block", width: "99%" }}>
  472. <ReactApexChart
  473. options={options}
  474. series={series}
  475. type="bar"
  476. height={350}
  477. />
  478. </div>
  479. {/* <div style={{display:"inline-block",width:"20%",verticalAlign:"top",textAlign:"center"}}>
  480. <p><strong><u>Stage Deadline</u></strong></p>
  481. {stageDeadline.map((date, index) => {
  482. const marginTop = index === 0 ? 25 : 20;
  483. return (
  484. <p style={{marginTop:marginTop}} key={index}>{date}</p>
  485. );
  486. })}
  487. </div> */}
  488. <CardHeader
  489. className="text-slate-500"
  490. title="Current Stage Due Date"
  491. />
  492. <div
  493. style={{ display: "inline-block", width: "99%", marginLeft: 10 }}
  494. >
  495. <CustomDatagrid
  496. rows={rows2}
  497. columns={columns2}
  498. columnWidth={200}
  499. dataGridHeight={300}
  500. checkboxSelection={true}
  501. onRowSelectionModelChange={handleSelectionChange}
  502. selectionModel={selectionModel}
  503. />
  504. </div>
  505. </Card>
  506. </Grid>
  507. </div>
  508. <div
  509. style={{
  510. display: "inline-block",
  511. width: "30%",
  512. verticalAlign: "top",
  513. marginLeft: 0,
  514. }}
  515. >
  516. <Grid item xs={12} md={12} lg={12}>
  517. <Card style={{ marginLeft: 15, marginRight: 20 }}>
  518. <CardHeader
  519. className="text-slate-500"
  520. title="Overall Progress per Project"
  521. />
  522. {percentageArray.length === 0 && (
  523. <div
  524. className="mt-10 mb-10 ml-5 mr-5 text-lg font-medium text-center"
  525. style={{ color: "#898d8d" }}
  526. >
  527. Please select the project you want to check.
  528. </div>
  529. )}
  530. {percentageArray.length > 0 && (
  531. <ReactApexChart
  532. options={options2}
  533. series={percentageArray}
  534. type="donut"
  535. />
  536. )}
  537. </Card>
  538. </Grid>
  539. <Grid item xs={12} md={12} lg={12}>
  540. <Card style={{ marginLeft: 15, marginRight: 20, marginTop: 20 }}>
  541. <div>
  542. <div
  543. className="mt-5 text-lg font-medium"
  544. style={{ color: "#898d8d" }}
  545. >
  546. <span style={{ marginLeft: "5%" }}>Project Budget Manhour</span>
  547. </div>
  548. <div
  549. className="mt-2 text-2xl font-extrabold"
  550. style={{ color: "#6b87cf" }}
  551. >
  552. <span style={{ marginLeft: "5%" }}>{projectBudgetManhour}</span>
  553. </div>
  554. </div>
  555. <hr />
  556. <div>
  557. <div
  558. className="mt-2 text-lg font-medium"
  559. style={{ color: "#898d8d" }}
  560. >
  561. <span style={{ marginLeft: "5%" }}>Actual Manhour Spent</span>
  562. </div>
  563. <div
  564. className="mt-2 text-2xl font-extrabold"
  565. style={{ color: "#6b87cf" }}
  566. >
  567. <span style={{ marginLeft: "5%" }}>{actualManhourSpent}</span>
  568. </div>
  569. </div>
  570. <hr />
  571. <div>
  572. <div
  573. className="mt-2 text-lg font-medium"
  574. style={{ color: "#898d8d" }}
  575. >
  576. <span style={{ marginLeft: "5%" }}>Remained Manhour</span>
  577. </div>
  578. <div
  579. className="mt-2 text-2xl font-extrabold"
  580. style={{ color: "#6b87cf" }}
  581. >
  582. <span style={{ marginLeft: "5%" }}>{remainedManhour}</span>
  583. </div>
  584. </div>
  585. <hr />
  586. <div>
  587. <div
  588. className="mt-2 text-lg font-medium"
  589. style={{ color: "#898d8d" }}
  590. >
  591. <span style={{ marginLeft: "5%" }}>Last Update</span>
  592. </div>
  593. <div
  594. className="mt-2 mb-5 text-2xl font-extrabold"
  595. style={{ color: "#6b87cf" }}
  596. >
  597. <span style={{ marginLeft: "5%" }}>{lastUpdate}</span>
  598. </div>
  599. </div>
  600. </Card>
  601. </Grid>
  602. </div>
  603. </Grid>
  604. );
  605. };
  606. export default ProgressByTeam;