@@ -56,6 +56,14 @@ export interface CashFlowAnticipatedChartResult { | |||
AverageManhours: number; | |||
teamLead: number; | |||
totalManhour: number; | |||
aniticipateExpenditure: number; | |||
} | |||
export interface CashFlowLedgerResult { | |||
date: string; | |||
income: number; | |||
expenditure: number; | |||
balance: number; | |||
remarks: string; | |||
} | |||
export const preloadProjects = () => { | |||
@@ -98,3 +106,14 @@ export const fetchProjectsCashFlowAnticipate = cache(async (projectIdList: numbe | |||
} | |||
}); | |||
export const fetchProjectsCashFlowLedger = cache(async (projectIdList: number[]) => { | |||
if (projectIdList.length !== 0) { | |||
const queryParams = new URLSearchParams(); | |||
queryParams.append('projectIdList', projectIdList.join(',')); | |||
return serverFetchJson<CashFlowLedgerResult[]>(`${BASE_API_URL}/dashboard/searchCashFlowLedger?${queryParams.toString()}`); | |||
} else { | |||
return []; | |||
} | |||
}); |
@@ -0,0 +1,36 @@ | |||
"use server"; | |||
import { cache } from "react"; | |||
import { serverFetchJson } from "@/app/utils/fetchUtil"; | |||
import { BASE_API_URL } from "@/config/api"; | |||
export interface comboProp { | |||
id: any; | |||
label: string; | |||
} | |||
export interface teamCombo { | |||
records: comboProp[]; | |||
} | |||
export interface teamCashFlow { | |||
monthInvoice: string; | |||
invoiceMonth: string; | |||
income: number; | |||
cumulativeIncome: number; | |||
monthExpenditure: string; | |||
recordMonth: string; | |||
expenditure: number; | |||
cumulativeExpenditure: number; | |||
} | |||
export const fetchTeamCombo = cache(async () => { | |||
return serverFetchJson<teamCombo>(`${BASE_API_URL}/team/combo`); | |||
}); | |||
export const fetchTeamCashFlowChartData = cache(async (year:number,teamId?:number,) => { | |||
if (teamId === null) { | |||
return serverFetchJson<teamCashFlow>(`${BASE_API_URL}/dashboard/searchTeamCashFlow?year=${year}`); | |||
} else { | |||
return serverFetchJson<teamCashFlow>(`${BASE_API_URL}/dashboard/searchTeamCashFlow?teamId=${teamId}&year=${year}`); | |||
} | |||
}); |
@@ -14,6 +14,13 @@ const pathToLabelMap: { [path: string]: string } = { | |||
"": "Overview", | |||
"/home": "User Workspace", | |||
"/dashboard": "Dashboard", | |||
"/dashboard/CompanyTeamCashFlow": "Company Team Cash Flow", | |||
"/dashboard/ProjectCashFlow": "Project Cash Flow", | |||
"/dashboard/ProjectFinancialSummary": "Project Finanical Summary", | |||
"/dashboard/ProjectResourceSummary": "Project Resource Summary", | |||
"/dashboard/ProjectStatusByClient": "Project Status by Client", | |||
"/dashboard/ProjectStatusByTeam": "Project Status by Team", | |||
"/dashboard/StaffUtilization": "Staff Utilization", | |||
"/projects": "Projects", | |||
"/projects/create": "Create Project", | |||
"/projects/createSub": "Sub Project", | |||
@@ -21,19 +21,77 @@ import { Suspense } from "react"; | |||
import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch"; | |||
import { Input, Label } from "reactstrap"; | |||
import Select, { components } from "react-select"; | |||
import {fetchTeamCombo,fetchTeamCashFlowChartData} from "@/app/api/teamCashflow"; | |||
const CompanyTeamCashFlow: React.FC = () => { | |||
const todayDate = new Date(); | |||
const [selectionModel, setSelectionModel]: any[] = React.useState([]); | |||
const [teamOptions, setTeamOptions]: any[] = React.useState([]); | |||
const [teamId, setTeamId]:any = React.useState(null); | |||
const [monthlyIncomeList, setMonthlyIncomeList]: any[] = React.useState([]); | |||
const [monthlyCumulativeIncomeList, setMonthlyCumulativeIncomeList]: any[] = React.useState([]); | |||
const [monthlyExpenditureList, setMonthlyExpenditureList]: any[] = React.useState([]); | |||
const [monthlyCumulativeExpenditureList, setMonthlyCumulativeExpenditureList]: any[] = React.useState([]); | |||
const [monthlyChartLeftMax, setMonthlyChartLeftMax]: any[] = React.useState(0); | |||
const [monthlyChartRightMax, setMonthlyChartRightMax]: any[] = React.useState(0); | |||
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 fetchChartData = async () => { | |||
const cashFlowMonthlyChartData:any = await fetchTeamCashFlowChartData(cashFlowYear,teamId); | |||
console.log(cashFlowMonthlyChartData[0]) | |||
const monthlyIncome = [] | |||
const cumulativeIncome = [] | |||
const monthlyExpenditure = [] | |||
const cumulativeExpenditure = [] | |||
var leftMax = 0 | |||
var rightMax = 0 | |||
// if (cashFlowMonthlyChartData.length !== 0) { | |||
for (var i = 0; i < cashFlowMonthlyChartData[0].teamCashFlowIncome.length; i++) { | |||
if (leftMax < cashFlowMonthlyChartData[0].teamCashFlowIncome[i].income || leftMax < cashFlowMonthlyChartData[0].teamCashFlowExpenditure[i].expenditure){ | |||
leftMax = Math.max(cashFlowMonthlyChartData[0].teamCashFlowIncome[i].income,cashFlowMonthlyChartData[0].teamCashFlowExpenditure[i].expenditure) | |||
} | |||
monthlyIncome.push(cashFlowMonthlyChartData[0].teamCashFlowIncome[i].income) | |||
cumulativeIncome.push(cashFlowMonthlyChartData[0].teamCashFlowIncome[i].cumulativeIncome) | |||
} | |||
for (var i = 0; i < cashFlowMonthlyChartData[0].teamCashFlowExpenditure.length; i++) { | |||
if (rightMax < cashFlowMonthlyChartData[0].teamCashFlowIncome[i].income || rightMax < cashFlowMonthlyChartData[0].teamCashFlowExpenditure[i].expenditure){ | |||
rightMax = Math.max(cashFlowMonthlyChartData[0].teamCashFlowIncome[i].income,cashFlowMonthlyChartData[0].teamCashFlowExpenditure[i].expenditure) | |||
} | |||
monthlyExpenditure.push(cashFlowMonthlyChartData[0].teamCashFlowExpenditure[i].expenditure) | |||
cumulativeExpenditure.push(cashFlowMonthlyChartData[0].teamCashFlowExpenditure[i].cumulativeExpenditure) | |||
} | |||
setMonthlyIncomeList(monthlyIncome) | |||
setMonthlyCumulativeIncomeList(cumulativeIncome) | |||
setMonthlyExpenditureList(monthlyExpenditure) | |||
setMonthlyCumulativeExpenditureList(cumulativeExpenditure) | |||
setMonthlyChartLeftMax(leftMax) | |||
setMonthlyChartRightMax(rightMax) | |||
// } else { | |||
// setMonthlyIncomeList([0,0,0,0,0,0,0,0,0,0,0,0]) | |||
// setMonthlyCumulativeIncomeList([0,0,0,0,0,0,0,0,0,0,0,0]) | |||
// setMonthlyExpenditureList([0,0,0,0,0,0,0,0,0,0,0,0]) | |||
// setMonthlyCumulativeExpenditureList([0,0,0,0,0,0,0,0,0,0,0,0]) | |||
// } | |||
} | |||
const fetchComboData = async () => { | |||
const teamComboList = [] | |||
const teamCombo = await fetchTeamCombo(); | |||
for (var i = 0; i < teamCombo.records.length; i++) { | |||
teamComboList.push({value: teamCombo.records[i].id, label: teamCombo.records[i].label}) | |||
} | |||
setTeamOptions(teamComboList) | |||
} | |||
useEffect(() => { | |||
fetchComboData() | |||
}, []); | |||
useEffect(() => { | |||
fetchChartData() | |||
}, [cashFlowYear,teamId]); | |||
const columns = [ | |||
{ | |||
@@ -158,7 +216,7 @@ const CompanyTeamCashFlow: React.FC = () => { | |||
text: "Monthly Income and Expenditure(HKD)", | |||
}, | |||
min: 0, | |||
max: 3700000, | |||
max: monthlyChartLeftMax, | |||
tickAmount: 5, | |||
labels: { | |||
formatter: function (val) { | |||
@@ -173,7 +231,7 @@ const CompanyTeamCashFlow: React.FC = () => { | |||
text: "Monthly Expenditure (HKD)", | |||
}, | |||
min: 0, | |||
max: 3700000, | |||
max: monthlyChartLeftMax, | |||
tickAmount: 5, | |||
}, | |||
{ | |||
@@ -183,7 +241,7 @@ const CompanyTeamCashFlow: React.FC = () => { | |||
text: "Cumulative Income and Expenditure(HKD)", | |||
}, | |||
min: 0, | |||
max: 21000000, | |||
max: monthlyChartRightMax, | |||
tickAmount: 5, | |||
labels: { | |||
formatter: function (val) { | |||
@@ -199,7 +257,7 @@ const CompanyTeamCashFlow: React.FC = () => { | |||
text: "Cumulative Expenditure (HKD)", | |||
}, | |||
min: 0, | |||
max: 21000000, | |||
max: monthlyChartRightMax, | |||
tickAmount: 5, | |||
}, | |||
], | |||
@@ -212,37 +270,25 @@ const CompanyTeamCashFlow: React.FC = () => { | |||
name: "Monthly_Income", | |||
type: "column", | |||
color: "#ffde91", | |||
data: [ | |||
1280000, 170000, 3600000, 2400000, 1000000, 1800000, 1800000, 1200000, | |||
1250000, 1200000, 600000, 2400000, | |||
], | |||
data: monthlyIncomeList, | |||
}, | |||
{ | |||
name: "Monthly_Expenditure", | |||
type: "column", | |||
color: "#82b59a", | |||
data: [ | |||
1200000, 1400000, 2000000, 1400000, 1450000, 1800000, 1200000, | |||
1400000, 1200000, 1600000, 2000000, 1600000, | |||
], | |||
data: monthlyExpenditureList, | |||
}, | |||
{ | |||
name: "Cumulative_Income", | |||
type: "line", | |||
color: "#EE6D7A", | |||
data: [ | |||
500000, 3000000, 7000000, 9000000, 10000000, 13000000, 14000000, | |||
16000000, 17000000, 17500000, 18000000, 20000000, | |||
], | |||
data: monthlyCumulativeIncomeList, | |||
}, | |||
{ | |||
name: "Cumulative_Expenditure", | |||
type: "line", | |||
color: "#7cd3f2", | |||
data: [ | |||
400000, 2800000, 4000000, 5200000, 7100000, 8000000, 10000000, | |||
11000000, 12100000, 14000000, 15400000, 17200000, | |||
], | |||
data: monthlyCumulativeExpenditureList, | |||
}, | |||
], | |||
}; | |||
@@ -296,6 +342,13 @@ const CompanyTeamCashFlow: React.FC = () => { | |||
placeholder="All Team" | |||
options={teamOptions} | |||
isClearable={true} | |||
onChange={(selectedOption:any) => { | |||
if (selectedOption === null) { | |||
setTeamId(null); | |||
} else { | |||
setTeamId(selectedOption.value); | |||
} | |||
}} | |||
/> | |||
</div> | |||
<ReactApexChart | |||
@@ -19,7 +19,7 @@ import SearchBox, { Criterion } from "../SearchBox"; | |||
import ProgressByClientSearch from "@/components/ProgressByClientSearch"; | |||
import { Suspense } from "react"; | |||
import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch"; | |||
import { fetchProjectsCashFlow,fetchProjectsCashFlowMonthlyChart,fetchProjectsCashFlowReceivableAndExpenditure,fetchProjectsCashFlowAnticipate} from "@/app/api/cashflow"; | |||
import { fetchProjectsCashFlow,fetchProjectsCashFlowMonthlyChart,fetchProjectsCashFlowReceivableAndExpenditure,fetchProjectsCashFlowAnticipate,fetchProjectsCashFlowLedger} from "@/app/api/cashflow"; | |||
import { Input, Label } from "reactstrap"; | |||
import { CashFlow } from "@/app/api/cashflow"; | |||
import dayjs from 'dayjs'; | |||
@@ -43,6 +43,7 @@ const ProjectCashFlow: React.FC = () => { | |||
const [monthlyCumulativeExpenditureList, setMonthlyCumulativeExpenditureList]: any[] = React.useState([]); | |||
const [monthlyChartLeftMax, setMonthlyChartLeftMax]: any[] = React.useState(0); | |||
const [monthlyChartRightMax, setMonthlyChartRightMax]: any[] = React.useState(0); | |||
const [monthlyAnticipateLeftMax, setMonthlyAnticipateLeftMax]: any[] = React.useState(0); | |||
const [receivedPercentage,setReceivedPercentage]: any[] = React.useState(0); | |||
const [totalBudget,setTotalBudget]: any[] = React.useState(0); | |||
const [totalInvoiced,setTotalInvoiced]: any[] = React.useState(0); | |||
@@ -51,6 +52,9 @@ const ProjectCashFlow: React.FC = () => { | |||
const [totalExpenditure,setTotalExpenditure]: any[] = React.useState(0); | |||
const [expenditureReceivable,setExpenditureReceivable]: any[] = React.useState(0); | |||
const [expenditurePercentage,setExpenditurePercentage]: any[] = React.useState(0); | |||
const [monthlyAnticipateIncomeList, setMonthlyAnticipateIncomeList]: any[] = React.useState([0,0,0,0,0,0,0,0,0,0,0,0]); | |||
const [monthlyAnticipateExpenditureList, setMonthlyAnticipateExpenditureList]: any[] = React.useState([0,0,0,0,0,0,0,0,0,0,0,0]); | |||
const [ledgerData, setLedgerData]: any[] = React.useState([]); | |||
const [cashFlowYear, setCashFlowYear]: any[] = React.useState( | |||
todayDate.getFullYear(), | |||
); | |||
@@ -105,6 +109,11 @@ const ProjectCashFlow: React.FC = () => { | |||
setMonthlyCumulativeExpenditureList(cumulativeExpenditure) | |||
setMonthlyChartLeftMax(leftMax) | |||
setMonthlyChartRightMax(rightMax) | |||
} else { | |||
setMonthlyIncomeList([0,0,0,0,0,0,0,0,0,0,0,0]) | |||
setMonthlyCumulativeIncomeList([0,0,0,0,0,0,0,0,0,0,0,0]) | |||
setMonthlyExpenditureList([0,0,0,0,0,0,0,0,0,0,0,0]) | |||
setMonthlyCumulativeExpenditureList([0,0,0,0,0,0,0,0,0,0,0,0]) | |||
} | |||
} | |||
@@ -122,7 +131,7 @@ const ProjectCashFlow: React.FC = () => { | |||
} | |||
} | |||
const fetchAnticipateData = async () => { | |||
const cashFlowAnticipateData = await fetchProjectsCashFlowAnticipate(selectedProjectIdList,cashFlowYear); | |||
const cashFlowAnticipateData = await fetchProjectsCashFlowAnticipate(selectedProjectIdList,anticipateCashFlowYear); | |||
const monthlyAnticipateIncome = [] | |||
var anticipateLeftMax = 0 | |||
if(cashFlowAnticipateData.length !== 0){ | |||
@@ -132,8 +141,51 @@ const ProjectCashFlow: React.FC = () => { | |||
} | |||
monthlyAnticipateIncome.push(cashFlowAnticipateData[0].anticipateIncomeList[i].anticipateIncome) | |||
} | |||
} else { | |||
setMonthlyAnticipateIncomeList([0,0,0,0,0,0,0,0,0,0,0,0]) | |||
setMonthlyAnticipateExpenditureList([0,0,0,0,0,0,0,0,0,0,0,0]) | |||
} | |||
console.log(monthlyAnticipateIncome) | |||
setMonthlyAnticipateIncomeList(monthlyAnticipateIncome) | |||
if(cashFlowAnticipateData.length !== 0){ | |||
if (cashFlowAnticipateData[0].anticipateExpenditureList.length !== 0) { | |||
const anticipateExpenditureList = [] | |||
for (var i = 0; i < cashFlowAnticipateData[0].anticipateExpenditureList.length; i++) { | |||
const subAnticipateExpenditure = [] | |||
var duration = cashFlowAnticipateData[0].anticipateExpenditureList[i].Duration | |||
var month = cashFlowAnticipateData[0].anticipateExpenditureList[i].startMonth | |||
const anticipateExpenditure = cashFlowAnticipateData[0].anticipateExpenditureList[i].aniticipateExpenditure | |||
for (var j = 1; j < 13; j++){ | |||
if (month === j && duration > 0) { | |||
subAnticipateExpenditure.push(anticipateExpenditure) | |||
duration = duration - 1 | |||
} else { | |||
subAnticipateExpenditure.push(0) | |||
} | |||
} | |||
anticipateExpenditureList.push(subAnticipateExpenditure) | |||
} | |||
const result = new Array(anticipateExpenditureList[0].length).fill(0); | |||
for (const arr of anticipateExpenditureList) { | |||
for (let i = 0; i < arr.length; i++) { | |||
result[i] += arr[i]; | |||
} | |||
} | |||
setMonthlyAnticipateExpenditureList(result) | |||
for (var i = 0; i < monthlyAnticipateIncome.length; i++) { | |||
if (anticipateLeftMax < monthlyAnticipateIncome[i] || result[i]){ | |||
anticipateLeftMax = Math.max(monthlyAnticipateIncome[i],result[i]) | |||
} | |||
setMonthlyAnticipateLeftMax(anticipateLeftMax) | |||
} | |||
} else { | |||
setMonthlyAnticipateExpenditureList([0,0,0,0,0,0,0,0,0,0,0,0]) | |||
} | |||
} | |||
} | |||
const fetchProjectCashFlowLedger = async () => { | |||
const cashFlowLedgerData = await fetchProjectsCashFlowLedger(selectedProjectIdList); | |||
setLedgerData(cashFlowLedgerData) | |||
} | |||
useEffect(() => { | |||
fetchData() | |||
@@ -143,7 +195,11 @@ const ProjectCashFlow: React.FC = () => { | |||
fetchChartData() | |||
fetchReceivableAndExpenditureData() | |||
fetchAnticipateData() | |||
fetchProjectCashFlowLedger() | |||
}, [cashFlowYear,selectedProjectIdList]); | |||
useEffect(() => { | |||
fetchAnticipateData() | |||
}, [anticipateCashFlowYear,selectedProjectIdList]); | |||
const columns = [ | |||
{ | |||
id: "projectCode", | |||
@@ -207,18 +263,39 @@ const ProjectCashFlow: React.FC = () => { | |||
field: "expenditure", | |||
headerName: "Expenditure (HKD)", | |||
flex: 0.6, | |||
renderCell: (params:any) => { | |||
return ( | |||
<span>${params.row.expenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
} | |||
}, | |||
{ | |||
id: "income", | |||
field: "income", | |||
headerName: "Income (HKD)", | |||
flex: 0.6, | |||
renderCell: (params:any) => { | |||
return ( | |||
<span>${params.row.income.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
} | |||
}, | |||
{ | |||
id: "cashFlowBalance", | |||
field: "cashFlowBalance", | |||
id: "balance", | |||
field: "balance", | |||
headerName: "Cash Flow Balance (HKD)", | |||
flex: 0.6, | |||
renderCell: (params:any) => { | |||
if (params.row.balance < 0) { | |||
return ( | |||
<span>(${Math.abs(params.row.balance).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })})</span> | |||
) | |||
} else { | |||
return ( | |||
<span>${params.row.balance.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
} | |||
}, | |||
}, | |||
{ | |||
id: "remarks", | |||
@@ -383,50 +460,50 @@ const ProjectCashFlow: React.FC = () => { | |||
text: "Anticipate Monthly Income and Expenditure(HKD)", | |||
}, | |||
min: 0, | |||
max: monthlyChartLeftMax, | |||
tickAmount: 5, | |||
labels: { | |||
formatter: function (val) { | |||
return val.toLocaleString() | |||
} | |||
} | |||
}, | |||
{ | |||
show: false, | |||
seriesName: "Monthly_Expenditure", | |||
title: { | |||
text: "Monthly Expenditure (HKD)", | |||
}, | |||
min: 0, | |||
max: monthlyChartLeftMax, | |||
tickAmount: 5, | |||
}, | |||
{ | |||
seriesName: "Cumulative_Income", | |||
opposite: true, | |||
title: { | |||
text: "Cumulative Income and Expenditure(HKD)", | |||
}, | |||
min: 0, | |||
max: monthlyChartRightMax, | |||
tickAmount: 5, | |||
labels: { | |||
formatter: function (val) { | |||
return val.toLocaleString() | |||
} | |||
} | |||
}, | |||
{ | |||
show: false, | |||
seriesName: "Cumulative_Expenditure", | |||
opposite: true, | |||
title: { | |||
text: "Cumulative Expenditure (HKD)", | |||
}, | |||
min: 0, | |||
max: monthlyChartRightMax, | |||
max: monthlyAnticipateLeftMax, | |||
tickAmount: 5, | |||
// labels: { | |||
// formatter: function (val) { | |||
// return val.toLocaleString() | |||
// } | |||
// } | |||
}, | |||
// { | |||
// show: false, | |||
// seriesName: "Monthly_Expenditure", | |||
// title: { | |||
// text: "Monthly Expenditure (HKD)", | |||
// }, | |||
// min: 0, | |||
// max: monthlyAnticipateLeftMax, | |||
// tickAmount: 5, | |||
// }, | |||
// { | |||
// seriesName: "Cumulative_Income", | |||
// opposite: true, | |||
// title: { | |||
// text: "Cumulative Income and Expenditure(HKD)", | |||
// }, | |||
// min: 0, | |||
// max: MonthlyAnticipateLeftMax, | |||
// tickAmount: 5, | |||
// labels: { | |||
// formatter: function (val) { | |||
// return val.toLocaleString() | |||
// } | |||
// } | |||
// }, | |||
// { | |||
// show: false, | |||
// seriesName: "Cumulative_Expenditure", | |||
// opposite: true, | |||
// title: { | |||
// text: "Cumulative Expenditure (HKD)", | |||
// }, | |||
// min: 0, | |||
// max: monthlyChartRightMax, | |||
// tickAmount: 5, | |||
// }, | |||
], | |||
grid: { | |||
borderColor: "#f1f1f1", | |||
@@ -437,16 +514,13 @@ const ProjectCashFlow: React.FC = () => { | |||
name: "Monthly_Income", | |||
type: "column", | |||
color: "#f1c48a", | |||
data: [0, 110000, 0, 0, 185000, 0, 0, 189000, 0, 0, 300000, 0], | |||
data: monthlyAnticipateIncomeList, | |||
}, | |||
{ | |||
name: "Monthly_Expenditure", | |||
type: "column", | |||
color: "#89d7f3", | |||
data: [ | |||
60000, 60000, 60000, 60000, 60000, 60000, 60000, 60000, 60000, 60000, | |||
60000, 60000, | |||
], | |||
data: monthlyAnticipateExpenditureList, | |||
} | |||
], | |||
}; | |||
@@ -635,7 +709,6 @@ const ProjectCashFlow: React.FC = () => { | |||
remarks: "Monthly Manpower Expenditure", | |||
}, | |||
]; | |||
const [ledgerData, setLedgerData]: any[] = React.useState(ledgerRows); | |||
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | |||
() => [ | |||
@@ -771,7 +844,7 @@ const ProjectCashFlow: React.FC = () => { | |||
className="text-lg font-medium ml-5" | |||
style={{ color: "#6b87cf" }} | |||
> | |||
{totalInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||
${totalInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||
</div> | |||
<hr /> | |||
<div | |||
@@ -784,7 +857,7 @@ const ProjectCashFlow: React.FC = () => { | |||
className="text-lg font-medium ml-5" | |||
style={{ color: "#6b87cf" }} | |||
> | |||
{totalReceived.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||
${totalReceived.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||
</div> | |||
<hr /> | |||
<div | |||
@@ -797,7 +870,7 @@ const ProjectCashFlow: React.FC = () => { | |||
className="text-lg font-medium ml-5 mb-2" | |||
style={{ color: "#6b87cf" }} | |||
> | |||
{receivable.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||
${receivable.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||
</div> | |||
</Card> | |||
</Card> | |||
@@ -833,7 +906,7 @@ const ProjectCashFlow: React.FC = () => { | |||
className="text-lg font-medium ml-5" | |||
style={{ color: "#6b87cf" }} | |||
> | |||
{totalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||
${totalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||
</div> | |||
<hr /> | |||
<div | |||
@@ -846,7 +919,7 @@ const ProjectCashFlow: React.FC = () => { | |||
className="text-lg font-medium ml-5" | |||
style={{ color: "#6b87cf" }} | |||
> | |||
{totalExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||
${totalExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||
</div> | |||
<hr /> | |||
<div | |||
@@ -859,7 +932,7 @@ const ProjectCashFlow: React.FC = () => { | |||
className="text-lg font-medium ml-5 mb-2" | |||
style={{ color: "#6b87cf" }} | |||
> | |||
{expenditureReceivable.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||
${expenditureReceivable.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||
</div> | |||
</Card> | |||
</Card> | |||
@@ -894,7 +967,7 @@ const ProjectCashFlow: React.FC = () => { | |||
</div> | |||
<div className="inline-block ml-1"> | |||
<button | |||
onClick={() => setAnticipateCashFlowYear(cashFlowYear - 1)} | |||
onClick={() => setAnticipateCashFlowYear(anticipateCashFlowYear - 1)} | |||
className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base" | |||
> | |||
< | |||
@@ -902,7 +975,7 @@ const ProjectCashFlow: React.FC = () => { | |||
</div> | |||
<div className="inline-block ml-1"> | |||
<button | |||
onClick={() => setAnticipateCashFlowYear(cashFlowYear + 1)} | |||
onClick={() => setAnticipateCashFlowYear(anticipateCashFlowYear + 1)} | |||
className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base" | |||
> | |||
> | |||
@@ -140,7 +140,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||
minWidth:50, | |||
renderCell: (params:any) => { | |||
return ( | |||
<span>${params.row.totalFee}</span> | |||
<span>${params.row.totalFee.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
}, | |||
}, | |||
@@ -151,7 +151,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||
minWidth:50, | |||
renderCell: (params:any) => { | |||
return ( | |||
<span>${params.row.totalBudget}</span> | |||
<span>${params.row.totalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
}, | |||
}, | |||
@@ -162,7 +162,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||
minWidth:280, | |||
renderCell: (params:any) => { | |||
return ( | |||
<span>${params.row.cumulativeExpenditure}</span> | |||
<span>${params.row.cumulativeExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
}, | |||
}, | |||
@@ -173,7 +173,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||
minWidth:250, | |||
renderCell: (params:any) => { | |||
return ( | |||
<span>${params.row.totalInvoiced}</span> | |||
<span>${params.row.totalInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
}, | |||
}, | |||
@@ -184,7 +184,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||
minWidth:250, | |||
renderCell: (params:any) => { | |||
return ( | |||
<span>${params.row.totalUninvoiced}</span> | |||
<span>${params.row.totalUninvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
}, | |||
}, | |||
@@ -195,7 +195,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||
minWidth:250, | |||
renderCell: (params:any) => { | |||
return ( | |||
<span>${params.row.totalReceived}</span> | |||
<span>${params.row.totalReceived.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
}, | |||
}, | |||
@@ -307,7 +307,7 @@ const columns2 = [ | |||
minWidth:50, | |||
renderCell: (params:any) => { | |||
return ( | |||
<span>${params.row.totalFee}</span> | |||
<span>${params.row.totalFee.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
}, | |||
}, | |||
@@ -318,7 +318,7 @@ const columns2 = [ | |||
minWidth:50, | |||
renderCell: (params:any) => { | |||
return ( | |||
<span>${params.row.totalBudget}</span> | |||
<span>${params.row.totalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
}, | |||
}, | |||
@@ -329,7 +329,7 @@ const columns2 = [ | |||
minWidth:250, | |||
renderCell: (params:any) => { | |||
return ( | |||
<span>${params.row.cumulativeExpenditure}</span> | |||
<span>${params.row.cumulativeExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
}, | |||
}, | |||
@@ -340,7 +340,7 @@ const columns2 = [ | |||
minWidth:250, | |||
renderCell: (params:any) => { | |||
return ( | |||
<span>${params.row.totalInvoiced}</span> | |||
<span>${params.row.totalInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
}, | |||
}, | |||
@@ -351,7 +351,7 @@ const columns2 = [ | |||
minWidth:250, | |||
renderCell: (params:any) => { | |||
return ( | |||
<span>${params.row.totalUninvoiced}</span> | |||
<span>${params.row.totalUninvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
}, | |||
}, | |||
@@ -362,7 +362,7 @@ const columns2 = [ | |||
minWidth:250, | |||
renderCell: (params:any) => { | |||
return ( | |||
<span>${params.row.totalReceived}</span> | |||
<span>${params.row.totalReceived.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | |||
) | |||
}, | |||
}, | |||