Sfoglia il codice sorgente

dashboard update

tags/Baseline_30082024_FRONTEND_UAT
MSI\User 1 anno fa
parent
commit
dc3989a73d
7 ha cambiato i file con 685 aggiunte e 47 eliminazioni
  1. +90
    -1
      package-lock.json
  2. +3
    -1
      package.json
  3. +28
    -0
      src/app/(main)/dashboard/CompanyTeamCashFlow/page.tsx
  4. +285
    -0
      src/components/CompanyTeamCashFlow/CompanyTeamCashFlow.tsx
  5. +1
    -0
      src/components/CompanyTeamCashFlow/index.ts
  6. +7
    -3
      src/components/NavigationContent/NavigationContent.tsx
  7. +271
    -42
      src/components/ProjectCashFlow/ProjectCashFlow.tsx

+ 90
- 1
package-lock.json Vedi File

@@ -31,7 +31,9 @@
"react-dom": "^18",
"react-hook-form": "^7.49.2",
"react-i18next": "^13.5.0",
"react-intl": "^6.5.5"
"react-intl": "^6.5.5",
"react-select": "^5.8.0",
"reactstrap": "^9.2.2"
},
"devDependencies": {
"@types/lodash": "^4.14.202",
@@ -2194,6 +2196,11 @@
"node": ">= 6"
}
},
"node_modules/classnames": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
},
"node_modules/client-only": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
@@ -4433,6 +4440,11 @@
"node": ">=10"
}
},
"node_modules/memoize-one": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
},
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -5455,6 +5467,11 @@
"react": "^18.2.0"
}
},
"node_modules/react-fast-compare": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
},
"node_modules/react-hook-form": {
"version": "7.49.2",
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.49.2.tgz",
@@ -5523,6 +5540,40 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/react-popper": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz",
"integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==",
"dependencies": {
"react-fast-compare": "^3.0.1",
"warning": "^4.0.2"
},
"peerDependencies": {
"@popperjs/core": "^2.0.0",
"react": "^16.8.0 || ^17 || ^18",
"react-dom": "^16.8.0 || ^17 || ^18"
}
},
"node_modules/react-select": {
"version": "5.8.0",
"resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz",
"integrity": "sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==",
"dependencies": {
"@babel/runtime": "^7.12.0",
"@emotion/cache": "^11.4.0",
"@emotion/react": "^11.8.1",
"@floating-ui/dom": "^1.0.1",
"@types/react-transition-group": "^4.4.0",
"memoize-one": "^6.0.0",
"prop-types": "^15.6.0",
"react-transition-group": "^4.3.0",
"use-isomorphic-layout-effect": "^1.1.2"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -5538,6 +5589,23 @@
"react-dom": ">=16.6.0"
}
},
"node_modules/reactstrap": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-9.2.2.tgz",
"integrity": "sha512-4KroiGOdqZLAnMGzHjpErW3G7bLB+QbKzzMLIDXydPIV0y74lpdL7WtXHkLWAGInd97WCPNx4+R0NQDPyzIfhw==",
"dependencies": {
"@babel/runtime": "^7.12.5",
"@popperjs/core": "^2.6.0",
"classnames": "^2.2.3",
"prop-types": "^15.5.8",
"react-popper": "^2.2.4",
"react-transition-group": "^4.4.2"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -6561,6 +6629,19 @@
"browserslist": ">= 4.21.0"
}
},
"node_modules/use-isomorphic-layout-effect": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
"integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -6583,6 +6664,14 @@
"node": ">=0.10.0"
}
},
"node_modules/warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/watchpack": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",


+ 3
- 1
package.json Vedi File

@@ -32,7 +32,9 @@
"react-dom": "^18",
"react-hook-form": "^7.49.2",
"react-i18next": "^13.5.0",
"react-intl": "^6.5.5"
"react-intl": "^6.5.5",
"react-select": "^5.8.0",
"reactstrap": "^9.2.2"
},
"devDependencies": {
"@types/lodash": "^4.14.202",


+ 28
- 0
src/app/(main)/dashboard/CompanyTeamCashFlow/page.tsx Vedi File

@@ -0,0 +1,28 @@
import { Metadata } from "next";
import { I18nProvider } from "@/i18n";
import DashboardPage from "@/components/DashboardPage/DashboardPage";
import DashboardPageButton from "@/components/DashboardPage/DashboardTabButton";
import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch";
import { Suspense} from "react";
import Tabs, { TabsProps } from "@mui/material/Tabs";
import Tab from "@mui/material/Tab";
import Typography from "@mui/material/Typography";
import CompanyTeamCashFlowComponent from '@/components/CompanyTeamCashFlow'

export const metadata: Metadata = {
title: "Project Status by Client",
};


const CompanyTeamCashFlow: React.FC = () => {

return (
<I18nProvider namespaces={["dashboard"]}>
<Typography variant="h4" marginInlineEnd={2}>
Company / Team Cash Flow
</Typography>
<CompanyTeamCashFlowComponent/>
</I18nProvider>
);
};
export default CompanyTeamCashFlow;

+ 285
- 0
src/components/CompanyTeamCashFlow/CompanyTeamCashFlow.tsx Vedi File

@@ -0,0 +1,285 @@
"use client";
import * as React from "react";
import Grid from "@mui/material/Grid";
import { useState,useEffect, useMemo } from 'react'
import Paper from "@mui/material/Paper";
import { TFunction } from "i18next";
import { useTranslation } from "react-i18next";
import {Card,CardHeader} from '@mui/material';
import CustomSearchForm from "../CustomSearchForm/CustomSearchForm";
import CustomDatagrid from '../CustomDatagrid/CustomDatagrid';
import ReactApexChart from 'react-apexcharts';
import { ApexOptions } from 'apexcharts';
import { GridColDef, GridRowSelectionModel} from '@mui/x-data-grid';
import ReportProblemIcon from '@mui/icons-material/ReportProblem';
import dynamic from 'next/dynamic';
import '../../app/global.css';
import { AnyARecord, AnyCnameRecord } from "dns";
import SearchBox, { Criterion } from "../SearchBox";
import ProgressByClientSearch from "@/components/ProgressByClientSearch";
import { Suspense } from "react";
import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch";
import {Input,Label} from "reactstrap";
import Select, {components} from 'react-select'

const CompanyTeamCashFlow: React.FC = () => {
const todayDate = new Date;
const [selectionModel, setSelectionModel] : any[] = React.useState([]);
const [cashFlowYear, setCashFlowYear] : any[] = React.useState(todayDate.getFullYear());

const teamOptions = [
{ value: 1, label: 'XXX Team' },
{ value: 2, label: 'YYY Team' },
{ value: 3, label: 'ZZZ Team' }
]

const columns = [
{
id: 'projectCode',
field: 'projectCode',
headerName: "Project Code",
flex: 1,
},
{
id: 'projectName',
field: 'projectName',
headerName: "Project Name",
flex: 1,
},
{
id: 'team',
field: 'team',
headerName: "Team",
flex: 1,
},
{
id: 'teamLeader',
field: 'teamLeader',
headerName: "Team Leader",
flex: 1,
},
{
id: 'startDate',
field: 'startDate',
headerName: "Start Date",
flex: 1,
},
{
id: 'targetEndDate',
field: 'targetEndDate',
headerName: "Target End Date",
flex: 1,
},
{
id: 'client',
field: 'client',
headerName: "Client",
flex: 1,
},
{
id: 'subsidiary',
field: 'subsidiary',
headerName: "Subsidiary",
flex: 1,
},
];

const ledgerColumns = [
{
id: 'date',
field: 'date',
headerName: "Date",
flex: 0.5,
},
{
id: 'expenditure',
field: 'expenditure',
headerName: "Expenditure (HKD)",
flex: 0.6,
},
{
id: 'income',
field: 'income',
headerName: "Income (HKD)",
flex: 0.6,
},
{
id: 'cashFlowBalance',
field: 'cashFlowBalance',
headerName: "Cash Flow Balance (HKD)",
flex: 0.6,
},
{
id: 'remarks',
field: 'remarks',
headerName: "Remarks",
flex: 1,
},
];

const options: ApexOptions = {
chart: {
height: 350,
type: 'line',
},
stroke: {
width: [0, 0, 2, 2]
},
plotOptions: {
bar: {
horizontal: false,
distributed: false,
},
},
dataLabels: {
enabled: false
},
xaxis: {
categories: [
'Q1',
'Q2',
'Q3',
'Q4',
'Q5',
'Q6',
'Q7',
'Q8',
'Q9',
'Q10',
'Q11',
'Q12',
],
},
yaxis: [

{
title: {
text: 'Monthly Income and Expenditure(HKD)'
},
min: 0,
max: 3700000,
tickAmount: 5
},
{
show:false,
seriesName: 'Monthly_Expenditure',
title: {
text: 'Monthly Expenditure (HKD)'
},
min: 0,
max: 3700000,
tickAmount: 5
},
{
seriesName: 'Cumulative_Income',
opposite: true,
title: {
text: 'Cumulative Income and Expenditure(HKD)'
},
min: 0,
max: 21000000,
tickAmount: 5
},
{
show:false,
seriesName: 'Cumulative_Expenditure',
opposite: true,
title: {
text: 'Cumulative Expenditure (HKD)'
},
min: 0,
max: 21000000,
tickAmount: 5
}
],
grid: {
borderColor: '#f1f1f1',
},
annotations: {
},
series:[
{
name:"Monthly_Income",
type:"column",
color: "#ffde91",
data:[1280000,170000,3600000,2400000,1000000,1800000,1800000,1200000,1250000,1200000,600000,2400000],
},
{
name:"Monthly_Expenditure",
type:"column",
color: "#82b59a",
data:[1200000,1400000,2000000,1400000,1450000,1800000,1200000,1400000,1200000,1600000,2000000,1600000]
},
{
name:"Cumulative_Income",
type:"line",
color: "#EE6D7A",
data:[500000,3000000,7000000,9000000,10000000,13000000,14000000,16000000,17000000,17500000,18000000,20000000]
},
{
name:"Cumulative_Expenditure",
type:"line",
color: "#7cd3f2",
data:[400000,2800000,4000000,5200000,7100000,8000000,10000000,11000000,12100000,14000000,15400000,17200000]
}
]
};

return (
<>
<Grid item sm>
<div style={{display:"inline-block",width:"100%"}}>
<Grid item xs={12} md={12} lg={12}>
<Card>
<CardHeader className="text-slate-500" title="Company and Team Cash Flow by Month"/>
<div style={{display:"inline-block",width:"99%"}}>
<div className="inline-block">
<Label className="text-slate-500 font-medium ml-6">
Period:&nbsp;
</Label>
<Input
id={'cashFlowYear'}
value={cashFlowYear}
readOnly={true}
bsSize="lg"
className="rounded-md text-base w-12"
/>
</div>
<div className="inline-block ml-1">
<button onClick={() => setCashFlowYear(cashFlowYear - 1)} className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base">
&lt;
</button>
</div>
<div className="inline-block ml-1">
<button onClick={() => setCashFlowYear(cashFlowYear + 1)} className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base">
&gt;
</button>
</div>
<div className="inline-block ml-2">
<Label className="text-slate-500 font-medium">
Team:&nbsp;
</Label>
</div>
<div className="inline-block ml-1 w-60">
<Select
placeholder= "All Team"
options={teamOptions}
isClearable={true}
/>
</div>
<ReactApexChart
options={options}
series={options.series}
type="line"
height="500"
/>
</div>
</Card>
</Grid>
</div>
</Grid>
</>
);
};

export default CompanyTeamCashFlow;

+ 1
- 0
src/components/CompanyTeamCashFlow/index.ts Vedi File

@@ -0,0 +1 @@
export { default } from "./CompanyTeamCashFlow";

+ 7
- 3
src/components/NavigationContent/NavigationContent.tsx Vedi File

@@ -7,6 +7,9 @@ import ListItemText from "@mui/material/ListItemText";
import ListItemIcon from "@mui/material/ListItemIcon";
import WorkHistory from "@mui/icons-material/WorkHistory";
import Dashboard from "@mui/icons-material/Dashboard";
import SummarizeIcon from '@mui/icons-material/Summarize';
import PaymentsIcon from '@mui/icons-material/Payments';
import AccountTreeIcon from '@mui/icons-material/AccountTree';
import RequestQuote from "@mui/icons-material/RequestQuote";
import Task from "@mui/icons-material/Task";
import Assignment from "@mui/icons-material/Assignment";
@@ -31,9 +34,10 @@ interface NavigationItem {
const navigationItems: NavigationItem[] = [
{ icon: <WorkHistory />, label: "User Workspace", path: "/home" },
{ icon: <Dashboard />, label: "Dashboard", path: "", children: [
{ icon: <Dashboard />, label: "Project Financial Summary", path: "/dashboard/ProjectFinancialSummary" },
{ icon: <Dashboard />, label: "Project Cash Flow", path: "/dashboard/ProjectCashFlow" },
{ icon: <Dashboard />, label: "Project Status by Client", path: "/dashboard/ProjectStatusByClient" },
{ icon: <SummarizeIcon />, label: "Project Financial Summary", path: "/dashboard/ProjectFinancialSummary" },
{ icon: <PaymentsIcon />, label: "Company / Team Cash Flow", path: "/dashboard/CompanyTeamCashFlow" },
{ icon: <PaymentsIcon />, label: "Project Cash Flow", path: "/dashboard/ProjectCashFlow" },
{ icon: <AccountTreeIcon />, label: "Project Status by Client", path: "/dashboard/ProjectStatusByClient" },
]},
{ icon: <RequestQuote />, label: "Staff Reimbursement", path: "/staffReimbursement", children: [
{ icon: <RequestQuote />, label: "ClaimApproval", path: "/staffReimbursement/ClaimApproval"},


+ 271
- 42
src/components/ProjectCashFlow/ProjectCashFlow.tsx Vedi File

@@ -19,20 +19,12 @@ import SearchBox, { Criterion } from "../SearchBox";
import ProgressByClientSearch from "@/components/ProgressByClientSearch";
import { Suspense } from "react";
import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch";
import {Input,Label} from "reactstrap";

const ProjectCashFlow: React.FC = () => {
const todayDate = new Date;
const [selectionModel, setSelectionModel] : any[] = React.useState([]);
// const series: ApexAxisChartSeries | ApexNonAxisChartSeries = [{
// name: 'Monthly Income',
// type: 'line',
// data: [80, 55, 40, 65, 70],
// },
// {
// name: 'Monthly Incomess',
// type: 'column',
// data: [80, 55, 40, 65, 70],
// }
// ];
const [cashFlowYear, setCashFlowYear] : any[] = React.useState(todayDate.getFullYear());
const columns = [
{
id: 'projectCode',
@@ -84,11 +76,47 @@ const ProjectCashFlow: React.FC = () => {
},
];

const ledgerColumns = [
{
id: 'date',
field: 'date',
headerName: "Date",
flex: 0.5,
},
{
id: 'expenditure',
field: 'expenditure',
headerName: "Expenditure (HKD)",
flex: 0.6,
},
{
id: 'income',
field: 'income',
headerName: "Income (HKD)",
flex: 0.6,
},
{
id: 'cashFlowBalance',
field: 'cashFlowBalance',
headerName: "Cash Flow Balance (HKD)",
flex: 0.6,
},
{
id: 'remarks',
field: 'remarks',
headerName: "Remarks",
flex: 1,
},
];

const options: ApexOptions = {
chart: {
height: 350,
type: 'line',
},
stroke: {
width: [0, 0, 2, 2]
},
plotOptions: {
bar: {
horizontal: false,
@@ -114,27 +142,48 @@ const ProjectCashFlow: React.FC = () => {
'Q12',
],
},
yaxis: [{
title: {
text: 'Monthly Income and Expenditure (HKD)'
yaxis: [

{
title: {
text: 'Monthly Income and Expenditure(HKD)'
},
min: 0,
max: 350000,
tickAmount: 5
},
labels: {
maxWidth: 300,
style: {
cssClass: 'apexcharts-yaxis-label',
{
show:false,
seriesName: 'Monthly_Expenditure',
title: {
text: 'Monthly Expenditure (HKD)'
},
min: 0,
max: 350000,
tickAmount: 5
},
},
{
opposite: true,
title: {
text: 'Cumulative Income and Expenditure (HKD)'
}}
{
seriesName: 'Cumulative_Income',
opposite: true,
title: {
text: 'Cumulative Income and Expenditure(HKD)'
},
min: 0,
max: 850000,
tickAmount: 5
},
{
show:false,
seriesName: 'Cumulative_Expenditure',
opposite: true,
title: {
text: 'Cumulative Expenditure (HKD)'
},
min: 0,
max: 850000,
tickAmount: 5
}
],
title: {
text: 'Current Stage Completion Percentage',
align: 'center'
},
grid: {
borderColor: '#f1f1f1',
},
@@ -142,40 +191,147 @@ const ProjectCashFlow: React.FC = () => {
},
series:[
{
name:"Monthly Income",
name:"Monthly_Income",
type:"column",
color: "#ffde91",
data:[0,110000,0,0,185000,0,0,189000,0,0,300000,0]
data:[0,110000,0,0,185000,0,0,189000,0,0,300000,0],
},
{
name:"Monthly Expenditure",
name:"Monthly_Expenditure",
type:"column",
color: "#82b59d",
color: "#82b59a",
data:[0,160000,120000,120000,55000,55000,55000,55000,55000,70000,55000,55000]
},
{
name:"Cumulative Income",
name:"Cumulative_Income",
type:"line",
color: "#EE6D7A",
data:[1,2,3,5,6,9,8,5,6,1,16,15]
data:[0,100000,100000,100000,300000,300000,300000,500000,500000,500000,800000,800000]
},
{
name:"Cumulative Expenditure",
name:"Cumulative_Expenditure",
type:"line",
color: "#EE6D7A",
data:[1,2,3,5,6,9,8,5,6,1,16,15]
color: "#7cd3f2",
data:[0,198000,240000,400000,410000,430000,510000,580000,600000,710000,730000,790000]
}
]
};

const accountsReceivableOptions: ApexOptions = {
colors: ["#20E647"],
series: [80],
chart: {
height: 350,
type: 'radialBar',
},
plotOptions: {
radialBar: {
hollow: {
size: '70%',
background: "#ffffff"
},
track: {
dropShadow: {
enabled: true,
top: 2,
left: 0,
blur: 4,
opacity: 0.15
}
},
dataLabels: {
name:{
show:false,
},
value: {
color: "#3e98c7",
fontSize: "3em",
show: true
}
},
},
},
fill: {
type: "gradient",
gradient: {
shade: "dark",
type: "vertical",
gradientToColors: ["#87D4F9"],
stops: [0, 100]
}
},
stroke: {
lineCap: "round"
},
labels: ['AccountsReceivable'],
};

const expenditureOptions: ApexOptions = {
colors: ["#20E647"],
series: [95],
chart: {
height: 350,
type: 'radialBar',
},
plotOptions: {
radialBar: {
hollow: {
size: '70%',
background: "#ffffff"
},
track: {
dropShadow: {
enabled: true,
top: 2,
left: 0,
blur: 4,
opacity: 0.15
}
},
dataLabels: {
name:{
show:false,
},
value: {
color: "#3e98c7",
fontSize: "3em",
show: true
}
},
},
},
fill: {
type: "gradient",
gradient: {
shade: "dark",
type: "vertical",
gradientToColors: ["#87D4F9"],
stops: [0, 100]
}
},
stroke: {
lineCap: "round"
},
labels: ['AccountsReceivable'],
};

const rows = [{id: 1,projectCode:"M1001",projectName:"Consultancy Project A", team:"XXX", teamLeader:"XXX", startDate:"01/07/2022", targetEndDate: "01/04/2024", client:"Client B", subsidiary:"N/A"},
{id: 2,projectCode:"M1301",projectName:"Consultancy Project AAAA", team:"XXX", teamLeader:"XXX", startDate:"01/09/2022", targetEndDate: "20/02/2024", client:"Client C", subsidiary:"Subsidiary A"},
{id: 3,projectCode:"M1354",projectName:"Consultancy Project BBB", team:"YYY", teamLeader:"YYY", startDate:"01/02/2023", targetEndDate: "31/01/2024", client:"Client D", subsidiary:"Subsidiary C"}
]
const [selectedTeamData, setSelectedTeamData] : any[] = React.useState(rows);

const ledgerRows = [{id: 1,date:"Feb 2023",expenditure:"-", income:"100,000.00", cashFlowBalance:"100,000.00", remarks:"Payment Milestone 1 (10%)"},
{id: 2,date:"Feb 2023",expenditure:"160,000.00", income:"-", cashFlowBalance:"(60,000.00)", remarks:"Monthly Manpower Expenditure"},
{id: 3,date:"Mar 2023",expenditure:"160,000.00", income:"-", cashFlowBalance:"(180,000.00)", remarks:"Monthly Manpower Expenditure"},
{id: 4,date:"Apr 2023",expenditure:"120,000.00", income:"-", cashFlowBalance:"(300,000.00)", remarks:"Monthly Manpower Expenditure"},
{id: 5,date:"May 2023",expenditure:"-", income:"200,000.00", cashFlowBalance:"(100,000.00)", remarks:"Payment Milestone 2 (20%)"},
{id: 6,date:"May 2023",expenditure:"40,000.00", income:"-", cashFlowBalance:"(140,000.00)", remarks:"Monthly Manpower Expenditure"}
]

const [projectData, setProjectData] : any[] = React.useState(rows);
const [ledgerData, setLedgerData] : any[] = React.useState(ledgerRows);
const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => {
const selectedRowsData = selectedTeamData.filter((row:any) =>
const selectedRowsData = projectData.filter((row:any) =>
newSelectionModel.includes(row.id)
);
console.log(selectedRowsData)
@@ -186,22 +342,95 @@ const ProjectCashFlow: React.FC = () => {
<Suspense fallback={<ProgressCashFlowSearch.Loading />}>
<ProgressCashFlowSearch/>
</Suspense>
<CustomDatagrid rows={selectedTeamData} columns={columns} columnWidth={200} dataGridHeight={300} checkboxSelection={true} onRowSelectionModelChange={handleSelectionChange} selectionModel={selectionModel}/>
<CustomDatagrid rows={projectData} columns={columns} columnWidth={200} dataGridHeight={300} checkboxSelection={true} onRowSelectionModelChange={handleSelectionChange} selectionModel={selectionModel}/>
<Grid item sm>
<div style={{display:"inline-block",width:"50%"}}>
<Grid item xs={12} md={12} lg={12}>
<Card>
<CardHeader className="text-slate-500" title="Project Cash Flow by Month"/>
<div style={{display:"inline-block",width:"99%"}}>
<div className="inline-block">
<Label className="text-slate-500 font-medium ml-6">
Period:&nbsp;
</Label>
<Input
id={'cashFlowYear'}
value={cashFlowYear}
readOnly={true}
bsSize="lg"
className="rounded-md text-base w-12"
/>
</div>
<div className="inline-block ml-1">
<button onClick={() => setCashFlowYear(cashFlowYear - 1)} className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base">
&lt;
</button>
</div>
<div className="inline-block ml-1">
<button onClick={() => setCashFlowYear(cashFlowYear + 1)} className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base">
&gt;
</button>
</div>
<ReactApexChart
options={options}
series={options.series}
height={350}
type="line"
height="auto"
/>
</div>
</Card>
</Grid>
</div>
<div style={{display:"inline-block",width:"24%", verticalAlign:"top", marginLeft:10}}>
<Grid item xs={12} md={12} lg={12}>
<Card>
<CardHeader className="text-slate-500" title="Accounts Receivable (HKD)"/>
<ReactApexChart
options={accountsReceivableOptions}
series={accountsReceivableOptions.series}
type="radialBar"
/>
<Card className="ml-2 mr-2 mb-4 rounded-none border-solid border-slate-100">
<div className="text-sm font-medium ml-5 mt-2" style={{color:"#898d8d"}}>Total A. Receivable</div>
<div className="text-lg font-medium ml-5" style={{color:"#6b87cf"}}>1,000,000.00</div><hr/>
<div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Amount Received</div>
<div className="text-lg font-medium ml-5" style={{color:"#6b87cf"}}>800,000.00</div><hr/>
<div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Remaining Balance</div>
<div className="text-lg font-medium ml-5 mb-2" style={{color:"#6b87cf"}}>200,000.00</div>
</Card>
</Card>
</Grid>
</div>
<div style={{display:"inline-block",width:"24%", verticalAlign:"top", marginLeft:10}}>
<Grid item xs={12} md={12} lg={12}>
<Card>
<CardHeader className="text-slate-500" title="Expenditure (HKD)"/>
<ReactApexChart
options={expenditureOptions}
series={expenditureOptions.series}
type="radialBar"
/>
<Card className="ml-2 mr-2 mb-4 rounded-none border-solid border-slate-100">
<div className="text-sm font-medium ml-5 mt-2" style={{color:"#898d8d"}}>Budgeted Expenditure</div>
<div className="text-lg font-medium ml-5" style={{color:"#6b87cf"}}>800,000.00</div><hr/>
<div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Actual Expenditure</div>
<div className="text-lg font-medium ml-5" style={{color:"#6b87cf"}}>760,000.00</div><hr/>
<div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Remaining Balance</div>
<div className="text-lg font-medium ml-5 mb-2" style={{color:"#6b87cf"}}>40,000.00</div>
</Card>
</Card>
</Grid>
</div>
<div className="mt-5" style={{display:"inline-block",width:"100%", verticalAlign:"top"}}>
<Grid item xs={12} md={12} lg={12}>
<Card>
<CardHeader className="text-slate-500" title="Cash Flow Ledger by Month"/>
<div className="ml-4 mr-4">
<CustomDatagrid rows={ledgerData} columns={ledgerColumns} columnWidth={200} dataGridHeight={300}/>
</div>
</Card>
</Grid>
</div>
</Grid>
</>
);


Caricamento…
Annulla
Salva