您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 

598 行
23 KiB

  1. "use client";
  2. import * as React from "react";
  3. import Grid from "@mui/material/Grid";
  4. import { useState, useEffect, useMemo } from "react";
  5. import Paper from "@mui/material/Paper";
  6. import { TFunction } from "i18next";
  7. import { useTranslation } from "react-i18next";
  8. import { Card, CardHeader } from "@mui/material";
  9. import CustomSearchForm from "../CustomSearchForm/CustomSearchForm";
  10. import CustomDatagrid from "../CustomDatagrid/CustomDatagrid";
  11. import ReactApexChart from "react-apexcharts";
  12. import { ApexOptions } from "apexcharts";
  13. import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid";
  14. import ReportProblemIcon from "@mui/icons-material/ReportProblem";
  15. import dynamic from "next/dynamic";
  16. import "../../app/global.css";
  17. import { AnyARecord, AnyCnameRecord } from "dns";
  18. import SearchBox, { Criterion } from "../SearchBox";
  19. import ProgressByClientSearch from "@/components/ProgressByClientSearch";
  20. import { Suspense } from "react";
  21. import { fetchFinancialSummaryCard } from "@/app/api/financialsummary";
  22. import { exportFinancialSummaryByClientExcel, exportFinancialSummaryByProjectExcel, FinancialSummaryByProjectResult, FinancialSummaryByClientResult, searchFinancialSummaryByClient,searchFinancialSummaryByProject } from "@/app/api/financialsummary/actions";
  23. import ProjectFinancialCard from "./ProjectFinancialCard";
  24. import VisibilityIcon from '@mui/icons-material/Visibility';
  25. import { downloadFile } from "@/app/utils/commonUtil";
  26. type SearchProjectQuery = Partial<Omit<FinancialSummaryByProjectResult, "id">>;
  27. type SearchClientQuery = Partial<Omit<FinancialSummaryByClientResult, "id">>;
  28. type SearchProjectParamNames = keyof SearchProjectQuery;
  29. type SearchClientParamNames = keyof SearchClientQuery;
  30. const ProjectFinancialSummary: React.FC = () => {
  31. const [SearchCriteria, setSearchCriteria] = React.useState({});
  32. const { t } = useTranslation("dashboard");
  33. const [selectionModel, setSelectionModel]: any[] = React.useState([]);
  34. const [projectFinancialData, setProjectFinancialData]: any[] = React.useState([]);
  35. const [clientFinancialRows, setClientFinancialRows]: any[] = React.useState([]);
  36. const [projectFinancialRows, setProjectFinancialRows]: any[] = React.useState([]);
  37. const [filteredProjectResult, setFilteredProjectResult]:any[] = useState([]);
  38. const [filteredClientResult, setFilteredClientResult]:any[] = useState([]);
  39. const projectSearchCriteria: Criterion<SearchProjectParamNames>[] = useMemo(
  40. () => [
  41. { label: "Project Code", paramName: "projectCode", type: "text" },
  42. { label: "Project Name", paramName: "projectName", type: "text" },
  43. ],
  44. [t],
  45. );
  46. const clientSearchCriteria: Criterion<SearchClientParamNames>[] = useMemo(
  47. () => [
  48. { label: "Client Code", paramName: "customerCode", type: "text" },
  49. { label: "Client Name", paramName: "customerName", type: "text" },
  50. ],
  51. [t],
  52. );
  53. const fetchData = async () => {
  54. const financialSummaryCard = await fetchFinancialSummaryCard();
  55. setProjectFinancialData(financialSummaryCard)
  56. }
  57. const fetchTableData = async (teamId?:any) => {
  58. const financialSummaryByClient = await searchFinancialSummaryByClient(teamId);
  59. console.log(financialSummaryByClient)
  60. // console.log(financialSummaryByProject)
  61. setClientFinancialRows(financialSummaryByClient)
  62. setFilteredClientResult(financialSummaryByClient)
  63. }
  64. useEffect(() => {
  65. fetchData()
  66. // fetchTableData(undefined)
  67. }, []);
  68. const rows0 = [{id: 1,projectCode:"M1201",projectName:"Consultancy Project C", team:"XXX", teamLeader:"XXX", startDate:"01/08/2022", targetEndDate: "01/05/2024", client:"Client A", subsidiary:"N/A"},
  69. {id: 2,projectCode:"M1321",projectName:"Consultancy Project CCC", team:"XXX", teamLeader:"XXX", startDate:"01/08/2022", targetEndDate: "20/01/2024", client:"Client E", subsidiary:"Subsidiary B"},
  70. {id: 3,projectCode:"M1001",projectName:"Consultancy Project A", team:"YYY", teamLeader:"YYY", startDate:"01/07/2022", targetEndDate: "01/04/2024", client:"Client B", subsidiary:"N/A"},
  71. {id: 4,projectCode:"M1301",projectName:"Consultancy Project AAAA", team:"YYY", teamLeader:"YYY", startDate:"01/09/2022", targetEndDate: "20/02/2024", client:"Client C", subsidiary:"Subsidiary A"},
  72. {id: 5,projectCode:"M1354",projectName:"Consultancy Project BBB", team:"YYY", teamLeader:"YYY", startDate:"01/02/2023", targetEndDate: "31/01/2024", client:"Client D", subsidiary:"Subsidiary C"}
  73. ]
  74. const rows1 = [{id: 1,projectCode:"M1201",projectName:"Consultancy Project C", team:"XXX", teamLeader:"XXX", startDate:"01/08/2022", targetEndDate: "01/05/2024", client:"Client A", subsidiary:"N/A"},
  75. {id: 2,projectCode:"M1321",projectName:"Consultancy Project CCC", team:"XXX", teamLeader:"XXX", startDate:"01/08/2022", targetEndDate: "20/01/2024", client:"Client E", subsidiary:"Subsidiary B"},
  76. ]
  77. const rows2 = [{id: 3,projectCode:"M1001",projectName:"Consultancy Project A", team:"YYY", teamLeader:"YYY", startDate:"01/07/2022", targetEndDate: "01/04/2024", client:"Client B", subsidiary:"N/A"},
  78. {id: 4,projectCode:"M1301",projectName:"Consultancy Project AAAA", team:"YYY", teamLeader:"YYY", startDate:"01/09/2022", targetEndDate: "20/02/2024", client:"Client C", subsidiary:"Subsidiary A"},
  79. {id: 5,projectCode:"M1354",projectName:"Consultancy Project BBB", team:"YYY", teamLeader:"YYY", startDate:"01/02/2023", targetEndDate: "31/01/2024", client:"Client D", subsidiary:"Subsidiary C"}
  80. ]
  81. // const projectFinancialRows = [{id: 1,projectCode:"M1354",projectName:"Consultanct Project BBB",clientName:"Client D",cashFlowStatus:"Positive",cpi:"1.25", totalFees:"500,000.00", totalBudget:"400,000.00", totalCumulativeExpenditure:"280,000.00", totalInvoicedAmount: "350,000.00", totalUnInvoicedAmount:"150,000.00", totalReceivedAmount:"350,000.00"}
  82. // ]
  83. // const clientFinancialRows =[{id: 1,clientCode:"Cust-02",clientName:"Client B",totalProjectInvolved:"1",cashFlowStatus:"Positive",cpi:"1.25", totalFees:"500,000.00", totalBudget:"400,000.00", totalCumulativeExpenditure:"280,000.00", totalInvoicedAmount: "350,000.00", totalUnInvoicedAmount:"150,000.00", totalReceivedAmount:"350,000.00"},
  84. // {id: 2,clientCode:"Cust-03",clientName:"Client C",totalProjectInvolved:"1",cashFlowStatus:"Positive",cpi:"1.25", totalFees:"500,000.00", totalBudget:"400,000.00", totalCumulativeExpenditure:"280,000.00", totalInvoicedAmount: "350,000.00", totalUnInvoicedAmount:"150,000.00", totalReceivedAmount:"350,000.00"},
  85. // {id: 3,clientCode:"Cust-04",clientName:"Client D",totalProjectInvolved:"4",cashFlowStatus:"Positive",cpi:"1.25", totalFees:"500,000.00", totalBudget:"400,000.00", totalCumulativeExpenditure:"280,000.00", totalInvoicedAmount: "350,000.00", totalUnInvoicedAmount:"150,000.00", totalReceivedAmount:"350,000.00"}
  86. // ]
  87. const [isCardClickedIndex, setIsCardClickedIndex] = React.useState(0);
  88. const [selectedTeamData, setSelectedTeamData]: any[] = React.useState(rows0);
  89. const handleCardClick = (r: any, index:any) => {
  90. fetchTableData(r.teamId)
  91. fetchProjectTableData(r.teamId)
  92. setIsCardClickedIndex(index)
  93. };
  94. const columns = [
  95. {
  96. id: 'customerCode',
  97. field: 'customerCode',
  98. headerName: "Client Code",
  99. minWidth:50
  100. },
  101. {
  102. id: 'customerName',
  103. field: 'customerName',
  104. headerName: "Client Name",
  105. minWidth:80
  106. },
  107. {
  108. id: 'projectNo',
  109. field: 'projectNo',
  110. headerName: "Total Project Involved",
  111. minWidth:80
  112. },
  113. {
  114. id: 'cashFlowStatus',
  115. field: 'cashFlowStatus',
  116. headerName: "Cash Flow Status",
  117. minWidth:100,
  118. renderCell: (params:any) => {
  119. console.log(params.row)
  120. if (params.row.cashFlowStatus === "Positive") {
  121. return (
  122. <span className="text-lime-500">{params.row.cashFlowStatus}</span>
  123. )
  124. } else if (params.row.cashFlowStatus === "Negative") {
  125. return (
  126. <span className="text-red-500">{params.row.cashFlowStatus}</span>
  127. )
  128. }
  129. },
  130. },
  131. {
  132. id: 'cpi',
  133. field: 'cpi',
  134. headerName: "CPI",
  135. minWidth:50,
  136. renderCell: (params:any) => {
  137. if (params.row.cpi >= 1) {
  138. return (
  139. <span className="text-lime-500">{params.row.cpi}</span>
  140. )
  141. } else if (params.row.cpi < 1) {
  142. return (
  143. <span className="text-red-500">{params.row.cpi}</span>
  144. )
  145. }
  146. },
  147. },
  148. {
  149. id: 'projectedCashFlowStatus',
  150. field: 'projectedCashFlowStatus',
  151. headerName: "Projected Cash Flow Status",
  152. minWidth:100,
  153. renderCell: (params:any) => {
  154. if (params.row.projectedCashFlowStatus === "Positive") {
  155. return (
  156. <span className="text-lime-500">{params.row.projectedCashFlowStatus}</span>
  157. )
  158. } else if (params.row.projectedCashFlowStatus === "Negative") {
  159. return (
  160. <span className="text-red-500">{params.row.projectedCashFlowStatus}</span>
  161. )
  162. }
  163. },
  164. },
  165. {
  166. id: 'projectedCpi',
  167. field: 'projectedCpi',
  168. headerName: "Projected CPI",
  169. minWidth:50,
  170. renderCell: (params:any) => {
  171. if (params.row.projectedCpi >= 1) {
  172. return (
  173. <span className="text-lime-500">{params.row.projectedCpi}</span>
  174. )
  175. } else if (params.row.projectedCpi < 1) {
  176. return (
  177. <span className="text-red-500">{params.row.projectedCpi}</span>
  178. )
  179. }
  180. },
  181. },
  182. {
  183. id: 'totalFee',
  184. field: 'totalFee',
  185. headerName: "Total Fees (HKD)",
  186. minWidth:50,
  187. renderCell: (params:any) => {
  188. return (
  189. <span>${params.row.totalFee.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
  190. )
  191. },
  192. },
  193. {
  194. id: 'totalBudget',
  195. field: 'totalBudget',
  196. headerName: "Total Budget (HKD)",
  197. minWidth:50,
  198. renderCell: (params:any) => {
  199. return (
  200. <span>${params.row.totalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
  201. )
  202. },
  203. },
  204. {
  205. id: 'cumulativeExpenditure',
  206. field: 'cumulativeExpenditure',
  207. headerName: "Total Cumulative Expenditure (HKD)",
  208. minWidth:280,
  209. renderCell: (params:any) => {
  210. return (
  211. <span>${params.row.cumulativeExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
  212. )
  213. },
  214. },
  215. {
  216. id: 'totalInvoiced',
  217. field: 'totalInvoiced',
  218. headerName: "Total Invoiced Amount (HKD)",
  219. minWidth:250,
  220. renderCell: (params:any) => {
  221. return (
  222. <span>${params.row.totalInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
  223. )
  224. },
  225. },
  226. {
  227. id: 'totalUnInvoiced',
  228. field: 'totalUnInvoiced',
  229. headerName: "Total Un-invoiced Amount (HKD)",
  230. minWidth:250,
  231. renderCell: (params:any) => {
  232. return (
  233. <span>${params.row.totalUninvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
  234. )
  235. },
  236. },
  237. {
  238. id: 'totalReceived',
  239. field: 'totalReceived',
  240. headerName: "Total Received Amount (HKD)",
  241. minWidth:250,
  242. renderCell: (params:any) => {
  243. return (
  244. <span>${params.row.totalReceived.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
  245. )
  246. },
  247. },
  248. // {
  249. // id: 'projectCode',
  250. // field: 'projectCode',
  251. // headerName: "Project Code",
  252. // flex: 1,
  253. // },
  254. // {
  255. // id: 'projectName',
  256. // field: 'projectName',
  257. // headerName: "Project Name",
  258. // flex: 1,
  259. // },
  260. // {
  261. // id: 'team',
  262. // field: 'team',
  263. // headerName: "Team",
  264. // flex: 1,
  265. // },
  266. // {
  267. // id: 'teamLeader',
  268. // field: 'teamLeader',
  269. // headerName: "Team Leader",
  270. // flex: 1,
  271. // },
  272. // {
  273. // id: 'startDate',
  274. // field: 'startDate',
  275. // headerName: "Start Date",
  276. // flex: 1,
  277. // },
  278. // {
  279. // id: 'targetEndDate',
  280. // field: 'targetEndDate',
  281. // headerName: "Target End Date",
  282. // flex: 1,
  283. // },
  284. // {
  285. // id: 'client',
  286. // field: 'client',
  287. // headerName: "Client",
  288. // flex: 1,
  289. // },
  290. // {
  291. // id: 'subsidiary',
  292. // field: 'subsidiary',
  293. // headerName: "Subsidiary",
  294. // flex: 1,
  295. // },
  296. ];
  297. const columns2 = [
  298. {
  299. id: 'projectCode',
  300. field: 'projectCode',
  301. headerName: "Project Code",
  302. minWidth:50,
  303. },
  304. {
  305. id: 'projectName',
  306. field: 'projectName',
  307. headerName: "Project Name",
  308. minWidth:50,
  309. },
  310. {
  311. id: 'customerName',
  312. field: 'customerName',
  313. headerName: "Client Name",
  314. minWidth:50,
  315. },
  316. {
  317. id: 'subsidiaryName',
  318. field: 'subsidiaryName',
  319. headerName: "Subsidiary",
  320. minWidth:50,
  321. },
  322. {
  323. id: 'cashFlowStatus',
  324. field: 'cashFlowStatus',
  325. headerName: "Cash Flow Status",
  326. minWidth:80,
  327. renderCell: (params:any) => {
  328. if (params.row.cashFlowStatus === "Positive") {
  329. return (
  330. <span className="text-lime-500">{params.row.cashFlowStatus}</span>
  331. )
  332. } else if (params.row.cashFlowStatus === "Negative") {
  333. return (
  334. <span className="text-red-500">{params.row.cashFlowStatus}</span>
  335. )
  336. }
  337. },
  338. },
  339. {
  340. id: "cpi",
  341. field: "cpi",
  342. headerName: "CPI",
  343. minWidth:50,
  344. renderCell: (params: any) => {
  345. if (params.row.cpi >= 1) {
  346. return <span className="text-lime-500">{params.row.cpi}</span>;
  347. } else if (params.row.cpi < 1) {
  348. return <span className="text-red-500">{params.row.cpi}</span>;
  349. }
  350. },
  351. },
  352. {
  353. id: 'projectedCashFlowStatus',
  354. field: 'projectedCashFlowStatus',
  355. headerName: "Projected Cash Flow Status",
  356. minWidth:100,
  357. renderCell: (params:any) => {
  358. if (params.row.projectedCashFlowStatus === "Positive") {
  359. return (
  360. <span className="text-lime-500">{params.row.projectedCashFlowStatus}</span>
  361. )
  362. } else if (params.row.projectedCashFlowStatus === "Negative") {
  363. return (
  364. <span className="text-red-500">{params.row.projectedCashFlowStatus}</span>
  365. )
  366. }
  367. },
  368. },
  369. {
  370. id: 'projectedCpi',
  371. field: 'projectedCpi',
  372. headerName: "Projected CPI",
  373. minWidth:50,
  374. renderCell: (params:any) => {
  375. if (params.row.projectedCpi >= 1) {
  376. return (
  377. <span className="text-lime-500">{params.row.projectedCpi}</span>
  378. )
  379. } else if (params.row.projectedCpi < 1) {
  380. return (
  381. <span className="text-red-500">{params.row.projectedCpi}</span>
  382. )
  383. }
  384. },
  385. },
  386. {
  387. id: 'totalFees',
  388. field: 'totalFees',
  389. headerName: "Total Fees (HKD)",
  390. minWidth:50,
  391. renderCell: (params:any) => {
  392. return (
  393. <span>${params.row.totalFee.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
  394. )
  395. },
  396. },
  397. {
  398. id: 'totalBudget',
  399. field: 'totalBudget',
  400. headerName: "Total Budget (HKD)",
  401. minWidth:50,
  402. renderCell: (params:any) => {
  403. return (
  404. <span>${params.row.totalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
  405. )
  406. },
  407. },
  408. {
  409. id: 'totalCumulativeExpenditure',
  410. field: 'totalCumulativeExpenditure',
  411. headerName: "Total Cumulative Expenditure (HKD)",
  412. minWidth:250,
  413. renderCell: (params:any) => {
  414. return (
  415. <span>${params.row.cumulativeExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
  416. )
  417. },
  418. },
  419. {
  420. id: 'totalInvoicedAmount',
  421. field: 'totalInvoicedAmount',
  422. headerName: "Total Invoiced Amount (HKD)",
  423. minWidth:250,
  424. renderCell: (params:any) => {
  425. return (
  426. <span>${params.row.totalInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
  427. )
  428. },
  429. },
  430. {
  431. id: 'totalUnInvoicedAmount',
  432. field: 'totalUnInvoicedAmount',
  433. headerName: "Total Un-invoiced Amount (HKD)",
  434. minWidth:250,
  435. renderCell: (params:any) => {
  436. return (
  437. <span>${params.row.totalUninvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
  438. )
  439. },
  440. },
  441. {
  442. id: 'totalReceivedAmount',
  443. field: 'totalReceivedAmount',
  444. headerName: "Total Received Amount (HKD)",
  445. minWidth:250,
  446. renderCell: (params:any) => {
  447. return (
  448. <span>${params.row.totalReceived.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
  449. )
  450. },
  451. },
  452. ];
  453. const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => {
  454. const selectedRowsData = selectedTeamData.filter((row: any) =>
  455. newSelectionModel.includes(row.id),
  456. );
  457. console.log(selectedRowsData);
  458. };
  459. const fetchProjectTableData = async (teamId?:any,customerId?:any) => {
  460. const financialSummaryByProject = await searchFinancialSummaryByProject(teamId);
  461. setProjectFinancialRows(financialSummaryByProject)
  462. setFilteredProjectResult(financialSummaryByProject)
  463. }
  464. const handleRowClick = (params:any) => {
  465. console.log(params.row.teamId);
  466. // fetchProjectTableData(params.row.teamId,params.row.cid)
  467. };
  468. const handleExportByClient = async () => {
  469. const response = await exportFinancialSummaryByClientExcel({financialSummaryByClients: clientFinancialRows})
  470. if (response) {
  471. downloadFile(new Uint8Array(response.blobValue), response.filename!!)
  472. }
  473. console.log(clientFinancialRows)
  474. };
  475. const handleExportByProject = async () => {
  476. const response = await exportFinancialSummaryByProjectExcel({financialSummaryByProjects: projectFinancialRows})
  477. if (response) {
  478. downloadFile(new Uint8Array(response.blobValue), response.filename!!)
  479. }
  480. console.log(projectFinancialRows)
  481. };
  482. return (
  483. <Grid item sm>
  484. <Card>
  485. <CardHeader className="text-slate-500" title="Active Project Financial Status"/>
  486. <div className="ml-10 mr-10" style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'start'}}>
  487. {projectFinancialData.map((record:any, index:any) => (
  488. <div className="hover:cursor-pointer ml-4 mt-5 mb-4 inline-block" key={index} onClick={(r) => handleCardClick(record,index)}>
  489. <ProjectFinancialCard Title={record.teamName} TotalActiveProjectNumber={record.projectNo} TotalFees={record.totalFee} TotalBudget={record.totalBudget} TotalCumulative={record.cumulativeExpenditure ?? 0} TotalInvoicedAmount={record.totalInvoiced ?? 0} TotalUnInvoicedAmount={record.unInvoiced ?? 0} TotalReceivedAmount={record.totalReceived ?? 0} CashFlowStatus={record.cashFlowStatus ?? "Negative"} CostPerformanceIndex={record.cpi ?? 0} ProjectedCashFlowStatus={record.projectedCashFlowStatus ?? "Negative"} ProjectedCPI={record.projectedCpi ?? 0} ClickedIndex={isCardClickedIndex} Index={index}/>
  490. </div>
  491. ))}
  492. </div>
  493. <hr></hr>
  494. <div className="ml-10 text-base"><strong>-Formula-</strong></div>
  495. <div className="ml-10 text-sm"><strong>CPI:</strong> Invoiced Amount / Cumulative Expenditure</div>
  496. <div className="ml-10 text-sm"><strong>Cash Flow Status: </strong>{`Positive when CPI >= 1`}</div>
  497. <div className="ml-10 text-sm"><strong>Projected CPI:</strong> Project Fee / Cumulative Expenditure</div>
  498. <div className="ml-10 text-sm mb-5"><strong>Cash Flow Status: </strong>{`Positive when Projected CPI >= 1`}</div>
  499. </Card>
  500. <Card className="mt-5">
  501. <div style={{display:"inline-block"}}>
  502. <CardHeader className="text-slate-500" title="Financial Status (by Project)"/>
  503. </div>
  504. <div style={{display:"inline-block"}}>
  505. {projectFinancialRows.length > 0 && (
  506. <button onClick={handleExportByProject} className="hover:cursor-pointer hover:bg-violet-50 text-base bg-transparent border-violet-500 text-violet-500 border-solid rounded-md w-36">
  507. Export Excel
  508. </button>
  509. )}
  510. </div>
  511. {projectFinancialRows.length > 0 && (
  512. <SearchBox
  513. criteria={projectSearchCriteria}
  514. onSearch={(query) => {
  515. setFilteredProjectResult(
  516. projectFinancialRows.filter(
  517. (cp:any) =>
  518. cp.projectCode.toLowerCase().includes(query.projectCode.toLowerCase()) &&
  519. cp.projectName.toLowerCase().includes(query.projectName.toLowerCase())
  520. ),
  521. );
  522. }}
  523. />
  524. )}
  525. <div style={{display:"inline-block",width:"99%",marginLeft:10}}>
  526. <CustomDatagrid rows={filteredProjectResult} columns={columns2} columnWidth={200} dataGridHeight={300}/>
  527. </div>
  528. {/* <hr></hr>
  529. <div className="ml-10 text-base"><strong>-Formula-</strong></div>
  530. <div className="ml-10 text-sm"><strong>CPI:</strong> Invoiced Amount / Cumulative Expenditure</div>
  531. <div className="ml-10 text-sm"><strong>Cash Flow Status: </strong>{`Positive when CPI >= 1`}</div>
  532. <div className="ml-10 text-sm"><strong>Projected CPI:</strong> Project Fee / Cumulative Expenditure</div>
  533. <div className="ml-10 text-sm mb-5"><strong>Cash Flow Status: </strong>{`Positive when Projected CPI >= 1`}</div> */}
  534. </Card>
  535. <Card className="mt-5">
  536. <div style={{display:"inline-block"}}>
  537. <CardHeader className="text-slate-500" title="Financial Status (by Client)"/>
  538. </div>
  539. <div style={{display:"inline-block"}}>
  540. {clientFinancialRows.length > 0 && (
  541. <button onClick={handleExportByClient} className="hover:cursor-pointer hover:bg-violet-50 text-base bg-transparent border-violet-500 text-violet-500 border-solid rounded-md w-36">
  542. Export Excel
  543. </button>
  544. )}
  545. </div>
  546. {clientFinancialRows.length > 0 && (
  547. <SearchBox
  548. criteria={clientSearchCriteria}
  549. onSearch={(query) => {
  550. setFilteredClientResult(
  551. clientFinancialRows.filter(
  552. (cp:any) =>
  553. cp.customerCode.toLowerCase().includes(query.customerCode.toLowerCase()) &&
  554. cp.customerName.toLowerCase().includes(query.customerName.toLowerCase())
  555. ),
  556. );
  557. }}
  558. />
  559. )}
  560. <div style={{display:"inline-block",width:"99%",marginLeft:10}}>
  561. {/* <CustomDatagrid rows={clientFinancialRows} columns={columns} columnWidth={200} dataGridHeight={300} checkboxSelection={true} onRowSelectionModelChange={handleSelectionChange} selectionModel={selectionModel}/> */}
  562. <CustomDatagrid onRowClick={handleRowClick} rows={filteredClientResult} columns={columns} columnWidth={200} dataGridHeight={300}/>
  563. </div>
  564. {/* <hr></hr>
  565. <div className="ml-10 text-base"><strong>-Formula-</strong></div>
  566. <div className="ml-10 text-sm"><strong>CPI:</strong> Invoiced Amount / Cumulative Expenditure</div>
  567. <div className="ml-10 text-sm"><strong>Cash Flow Status: </strong>{`Positive when CPI >= 1`}</div>
  568. <div className="ml-10 text-sm"><strong>Projected CPI:</strong> Project Fee / Cumulative Expenditure</div>
  569. <div className="ml-10 text-sm mb-5"><strong>Cash Flow Status: </strong>{`Positive when Projected CPI >= 1`}</div> */}
  570. </Card>
  571. </Grid>
  572. );
  573. };
  574. export default ProjectFinancialSummary;