You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

649 lines
16 KiB

  1. "use client";
  2. import * as React from "react";
  3. import Grid from "@mui/material/Grid";
  4. import { useState, useEffect, useMemo } from "react";
  5. import Paper from "@mui/material/Paper";
  6. import { TFunction } from "i18next";
  7. import { useTranslation } from "react-i18next";
  8. import { Card, CardHeader } from "@mui/material";
  9. import CustomSearchForm from "../CustomSearchForm/CustomSearchForm";
  10. import CustomDatagrid from "../CustomDatagrid/CustomDatagrid";
  11. import ReactApexChart from "react-apexcharts";
  12. import { ApexOptions } from "apexcharts";
  13. import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid";
  14. import ReportProblemIcon from "@mui/icons-material/ReportProblem";
  15. import dynamic from "next/dynamic";
  16. import "../../app/global.css";
  17. import { AnyARecord, AnyCnameRecord } from "dns";
  18. import SearchBox, { Criterion } from "../SearchBox";
  19. import ProgressByClientSearch from "@/components/ProgressByClientSearch";
  20. import { Suspense } from "react";
  21. import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch";
  22. import { Input, Label } from "reactstrap";
  23. const ProjectCashFlow: React.FC = () => {
  24. const todayDate = new Date();
  25. const [selectionModel, setSelectionModel]: any[] = React.useState([]);
  26. const [cashFlowYear, setCashFlowYear]: any[] = React.useState(
  27. todayDate.getFullYear(),
  28. );
  29. const columns = [
  30. {
  31. id: "projectCode",
  32. field: "projectCode",
  33. headerName: "Project Code",
  34. flex: 1,
  35. },
  36. {
  37. id: "projectName",
  38. field: "projectName",
  39. headerName: "Project Name",
  40. flex: 1,
  41. },
  42. {
  43. id: "team",
  44. field: "team",
  45. headerName: "Team",
  46. flex: 1,
  47. },
  48. {
  49. id: "teamLeader",
  50. field: "teamLeader",
  51. headerName: "Team Leader",
  52. flex: 1,
  53. },
  54. {
  55. id: "startDate",
  56. field: "startDate",
  57. headerName: "Start Date",
  58. flex: 1,
  59. },
  60. {
  61. id: "targetEndDate",
  62. field: "targetEndDate",
  63. headerName: "Target End Date",
  64. flex: 1,
  65. },
  66. {
  67. id: "client",
  68. field: "client",
  69. headerName: "Client",
  70. flex: 1,
  71. },
  72. {
  73. id: "subsidiary",
  74. field: "subsidiary",
  75. headerName: "Subsidiary",
  76. flex: 1,
  77. },
  78. ];
  79. const ledgerColumns = [
  80. {
  81. id: "date",
  82. field: "date",
  83. headerName: "Date",
  84. flex: 0.5,
  85. },
  86. {
  87. id: "expenditure",
  88. field: "expenditure",
  89. headerName: "Expenditure (HKD)",
  90. flex: 0.6,
  91. },
  92. {
  93. id: "income",
  94. field: "income",
  95. headerName: "Income (HKD)",
  96. flex: 0.6,
  97. },
  98. {
  99. id: "cashFlowBalance",
  100. field: "cashFlowBalance",
  101. headerName: "Cash Flow Balance (HKD)",
  102. flex: 0.6,
  103. },
  104. {
  105. id: "remarks",
  106. field: "remarks",
  107. headerName: "Remarks",
  108. flex: 1,
  109. },
  110. ];
  111. const options: ApexOptions = {
  112. chart: {
  113. height: 350,
  114. type: "line",
  115. },
  116. stroke: {
  117. width: [0, 0, 2, 2],
  118. },
  119. plotOptions: {
  120. bar: {
  121. horizontal: false,
  122. distributed: false,
  123. },
  124. },
  125. dataLabels: {
  126. enabled: false,
  127. },
  128. xaxis: {
  129. categories: [
  130. "Q1",
  131. "Q2",
  132. "Q3",
  133. "Q4",
  134. "Q5",
  135. "Q6",
  136. "Q7",
  137. "Q8",
  138. "Q9",
  139. "Q10",
  140. "Q11",
  141. "Q12",
  142. ],
  143. },
  144. yaxis: [
  145. {
  146. title: {
  147. text: "Monthly Income and Expenditure(HKD)",
  148. },
  149. min: 0,
  150. max: 350000,
  151. tickAmount: 5,
  152. labels: {
  153. formatter: function (val) {
  154. return val.toLocaleString()
  155. }
  156. }
  157. },
  158. {
  159. show: false,
  160. seriesName: "Monthly_Expenditure",
  161. title: {
  162. text: "Monthly Expenditure (HKD)",
  163. },
  164. min: 0,
  165. max: 350000,
  166. tickAmount: 5,
  167. },
  168. {
  169. seriesName: "Cumulative_Income",
  170. opposite: true,
  171. title: {
  172. text: "Cumulative Income and Expenditure(HKD)",
  173. },
  174. min: 0,
  175. max: 850000,
  176. tickAmount: 5,
  177. labels: {
  178. formatter: function (val) {
  179. return val.toLocaleString()
  180. }
  181. }
  182. },
  183. {
  184. show: false,
  185. seriesName: "Cumulative_Expenditure",
  186. opposite: true,
  187. title: {
  188. text: "Cumulative Expenditure (HKD)",
  189. },
  190. min: 0,
  191. max: 850000,
  192. tickAmount: 5,
  193. },
  194. ],
  195. grid: {
  196. borderColor: "#f1f1f1",
  197. },
  198. annotations: {},
  199. series: [
  200. {
  201. name: "Monthly_Income",
  202. type: "column",
  203. color: "#ffde91",
  204. data: [0, 110000, 0, 0, 185000, 0, 0, 189000, 0, 0, 300000, 0],
  205. },
  206. {
  207. name: "Monthly_Expenditure",
  208. type: "column",
  209. color: "#82b59a",
  210. data: [
  211. 0, 160000, 120000, 120000, 55000, 55000, 55000, 55000, 55000, 70000,
  212. 55000, 55000,
  213. ],
  214. },
  215. {
  216. name: "Cumulative_Income",
  217. type: "line",
  218. color: "#EE6D7A",
  219. data: [
  220. 0, 100000, 100000, 100000, 300000, 300000, 300000, 500000, 500000,
  221. 500000, 800000, 800000,
  222. ],
  223. },
  224. {
  225. name: "Cumulative_Expenditure",
  226. type: "line",
  227. color: "#7cd3f2",
  228. data: [
  229. 0, 198000, 240000, 400000, 410000, 430000, 510000, 580000, 600000,
  230. 710000, 730000, 790000,
  231. ],
  232. },
  233. ],
  234. };
  235. const accountsReceivableOptions: ApexOptions = {
  236. colors: ["#20E647"],
  237. series: [80],
  238. chart: {
  239. height: 350,
  240. type: "radialBar",
  241. },
  242. plotOptions: {
  243. radialBar: {
  244. hollow: {
  245. size: "70%",
  246. background: "#ffffff",
  247. },
  248. track: {
  249. dropShadow: {
  250. enabled: true,
  251. top: 2,
  252. left: 0,
  253. blur: 4,
  254. opacity: 0.15,
  255. },
  256. },
  257. dataLabels: {
  258. name: {
  259. show: false,
  260. },
  261. value: {
  262. color: "#3e98c7",
  263. fontSize: "3em",
  264. show: true,
  265. },
  266. },
  267. },
  268. },
  269. fill: {
  270. type: "gradient",
  271. gradient: {
  272. shade: "dark",
  273. type: "vertical",
  274. gradientToColors: ["#87D4F9"],
  275. stops: [0, 100],
  276. },
  277. },
  278. stroke: {
  279. lineCap: "round",
  280. },
  281. labels: ["AccountsReceivable"],
  282. };
  283. const expenditureOptions: ApexOptions = {
  284. colors: ["#20E647"],
  285. series: [95],
  286. chart: {
  287. height: 350,
  288. type: "radialBar",
  289. },
  290. plotOptions: {
  291. radialBar: {
  292. hollow: {
  293. size: "70%",
  294. background: "#ffffff",
  295. },
  296. track: {
  297. dropShadow: {
  298. enabled: true,
  299. top: 2,
  300. left: 0,
  301. blur: 4,
  302. opacity: 0.15,
  303. },
  304. },
  305. dataLabels: {
  306. name: {
  307. show: false,
  308. },
  309. value: {
  310. color: "#3e98c7",
  311. fontSize: "3em",
  312. show: true,
  313. },
  314. },
  315. },
  316. },
  317. fill: {
  318. type: "gradient",
  319. gradient: {
  320. shade: "dark",
  321. type: "vertical",
  322. gradientToColors: ["#87D4F9"],
  323. stops: [0, 100],
  324. },
  325. },
  326. stroke: {
  327. lineCap: "round",
  328. },
  329. labels: ["AccountsReceivable"],
  330. };
  331. const rows = [
  332. {
  333. id: 1,
  334. projectCode: "M1001",
  335. projectName: "Consultancy Project A",
  336. team: "XXX",
  337. teamLeader: "XXX",
  338. startDate: "01/07/2022",
  339. targetEndDate: "01/04/2024",
  340. client: "Client B",
  341. subsidiary: "N/A",
  342. },
  343. {
  344. id: 2,
  345. projectCode: "M1301",
  346. projectName: "Consultancy Project AAAA",
  347. team: "XXX",
  348. teamLeader: "XXX",
  349. startDate: "01/09/2022",
  350. targetEndDate: "20/02/2024",
  351. client: "Client C",
  352. subsidiary: "Subsidiary A",
  353. },
  354. {
  355. id: 3,
  356. projectCode: "M1354",
  357. projectName: "Consultancy Project BBB",
  358. team: "YYY",
  359. teamLeader: "YYY",
  360. startDate: "01/02/2023",
  361. targetEndDate: "31/01/2024",
  362. client: "Client D",
  363. subsidiary: "Subsidiary C",
  364. },
  365. ];
  366. const ledgerRows = [
  367. {
  368. id: 1,
  369. date: "Feb 2023",
  370. expenditure: "-",
  371. income: "100,000.00",
  372. cashFlowBalance: "100,000.00",
  373. remarks: "Payment Milestone 1 (10%)",
  374. },
  375. {
  376. id: 2,
  377. date: "Feb 2023",
  378. expenditure: "160,000.00",
  379. income: "-",
  380. cashFlowBalance: "(60,000.00)",
  381. remarks: "Monthly Manpower Expenditure",
  382. },
  383. {
  384. id: 3,
  385. date: "Mar 2023",
  386. expenditure: "160,000.00",
  387. income: "-",
  388. cashFlowBalance: "(180,000.00)",
  389. remarks: "Monthly Manpower Expenditure",
  390. },
  391. {
  392. id: 4,
  393. date: "Apr 2023",
  394. expenditure: "120,000.00",
  395. income: "-",
  396. cashFlowBalance: "(300,000.00)",
  397. remarks: "Monthly Manpower Expenditure",
  398. },
  399. {
  400. id: 5,
  401. date: "May 2023",
  402. expenditure: "-",
  403. income: "200,000.00",
  404. cashFlowBalance: "(100,000.00)",
  405. remarks: "Payment Milestone 2 (20%)",
  406. },
  407. {
  408. id: 6,
  409. date: "May 2023",
  410. expenditure: "40,000.00",
  411. income: "-",
  412. cashFlowBalance: "(140,000.00)",
  413. remarks: "Monthly Manpower Expenditure",
  414. },
  415. ];
  416. const [projectData, setProjectData]: any[] = React.useState(rows);
  417. const [ledgerData, setLedgerData]: any[] = React.useState(ledgerRows);
  418. const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => {
  419. const selectedRowsData = projectData.filter((row: any) =>
  420. newSelectionModel.includes(row.id),
  421. );
  422. console.log(selectedRowsData);
  423. };
  424. return (
  425. <>
  426. <Suspense fallback={<ProgressCashFlowSearch.Loading />}>
  427. <ProgressCashFlowSearch />
  428. </Suspense>
  429. <CustomDatagrid
  430. rows={projectData}
  431. columns={columns}
  432. columnWidth={200}
  433. dataGridHeight={300}
  434. checkboxSelection={true}
  435. onRowSelectionModelChange={handleSelectionChange}
  436. selectionModel={selectionModel}
  437. />
  438. <Grid item sm>
  439. <div style={{ display: "inline-block", width: "50%" }}>
  440. <Grid item xs={12} md={12} lg={12}>
  441. <Card>
  442. <CardHeader
  443. className="text-slate-500"
  444. title="Project Cash Flow by Month"
  445. />
  446. <div style={{ display: "inline-block", width: "99%" }}>
  447. <div className="inline-block">
  448. <Label className="text-slate-500 font-medium ml-6">
  449. Period:&nbsp;
  450. </Label>
  451. <Input
  452. id={"cashFlowYear"}
  453. value={cashFlowYear}
  454. readOnly={true}
  455. bsSize="lg"
  456. className="rounded-md text-base w-12"
  457. />
  458. </div>
  459. <div className="inline-block ml-1">
  460. <button
  461. onClick={() => setCashFlowYear(cashFlowYear - 1)}
  462. className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base"
  463. >
  464. &lt;
  465. </button>
  466. </div>
  467. <div className="inline-block ml-1">
  468. <button
  469. onClick={() => setCashFlowYear(cashFlowYear + 1)}
  470. className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base"
  471. >
  472. &gt;
  473. </button>
  474. </div>
  475. <ReactApexChart
  476. options={options}
  477. series={options.series}
  478. type="line"
  479. height="auto"
  480. />
  481. </div>
  482. </Card>
  483. </Grid>
  484. </div>
  485. <div
  486. style={{
  487. display: "inline-block",
  488. width: "24%",
  489. verticalAlign: "top",
  490. marginLeft: 10,
  491. }}
  492. >
  493. <Grid item xs={12} md={12} lg={12}>
  494. <Card>
  495. <CardHeader
  496. className="text-slate-500"
  497. title="Accounts Receivable (HKD)"
  498. />
  499. <ReactApexChart
  500. options={accountsReceivableOptions}
  501. series={accountsReceivableOptions.series}
  502. type="radialBar"
  503. />
  504. <Card className="ml-2 mr-2 mb-4 rounded-none border-solid border-slate-100">
  505. <div
  506. className="text-sm font-medium ml-5 mt-2"
  507. style={{ color: "#898d8d" }}
  508. >
  509. Total Invoiced Amount
  510. </div>
  511. <div
  512. className="text-lg font-medium ml-5"
  513. style={{ color: "#6b87cf" }}
  514. >
  515. 1,000,000.00
  516. </div>
  517. <hr />
  518. <div
  519. className="text-sm font-medium ml-5"
  520. style={{ color: "#898d8d" }}
  521. >
  522. Total Received Amount
  523. </div>
  524. <div
  525. className="text-lg font-medium ml-5"
  526. style={{ color: "#6b87cf" }}
  527. >
  528. 800,000.00
  529. </div>
  530. <hr />
  531. <div
  532. className="text-sm font-medium ml-5"
  533. style={{ color: "#898d8d" }}
  534. >
  535. Accounts Receivable
  536. </div>
  537. <div
  538. className="text-lg font-medium ml-5 mb-2"
  539. style={{ color: "#6b87cf" }}
  540. >
  541. 200,000.00
  542. </div>
  543. </Card>
  544. </Card>
  545. </Grid>
  546. </div>
  547. <div
  548. style={{
  549. display: "inline-block",
  550. width: "24%",
  551. verticalAlign: "top",
  552. marginLeft: 10,
  553. }}
  554. >
  555. <Grid item xs={12} md={12} lg={12}>
  556. <Card>
  557. <CardHeader
  558. className="text-slate-500"
  559. title="Expenditure (HKD)"
  560. />
  561. <ReactApexChart
  562. options={expenditureOptions}
  563. series={expenditureOptions.series}
  564. type="radialBar"
  565. />
  566. <Card className="ml-2 mr-2 mb-4 rounded-none border-solid border-slate-100">
  567. <div
  568. className="text-sm font-medium ml-5 mt-2"
  569. style={{ color: "#898d8d" }}
  570. >
  571. Total Budget
  572. </div>
  573. <div
  574. className="text-lg font-medium ml-5"
  575. style={{ color: "#6b87cf" }}
  576. >
  577. 800,000.00
  578. </div>
  579. <hr />
  580. <div
  581. className="text-sm font-medium ml-5"
  582. style={{ color: "#898d8d" }}
  583. >
  584. Total Cumulative Expenditure
  585. </div>
  586. <div
  587. className="text-lg font-medium ml-5"
  588. style={{ color: "#6b87cf" }}
  589. >
  590. 760,000.00
  591. </div>
  592. <hr />
  593. <div
  594. className="text-sm font-medium ml-5"
  595. style={{ color: "#898d8d" }}
  596. >
  597. Accounts Receivable
  598. </div>
  599. <div
  600. className="text-lg font-medium ml-5 mb-2"
  601. style={{ color: "#6b87cf" }}
  602. >
  603. 40,000.00
  604. </div>
  605. </Card>
  606. </Card>
  607. </Grid>
  608. </div>
  609. <div
  610. className="mt-5"
  611. style={{
  612. display: "inline-block",
  613. width: "100%",
  614. verticalAlign: "top",
  615. }}
  616. >
  617. <Grid item xs={12} md={12} lg={12}>
  618. <Card>
  619. <CardHeader
  620. className="text-slate-500"
  621. title="Cash Flow Ledger by Month"
  622. />
  623. <div className="ml-4 mr-4">
  624. <CustomDatagrid
  625. rows={ledgerData}
  626. columns={ledgerColumns}
  627. columnWidth={200}
  628. dataGridHeight={300}
  629. />
  630. </div>
  631. </Card>
  632. </Grid>
  633. </div>
  634. </Grid>
  635. </>
  636. );
  637. };
  638. export default ProjectCashFlow;