|
@@ -19,11 +19,16 @@ import SearchBox, { Criterion } from "../SearchBox"; |
|
|
import ProgressByClientSearch from "@/components/ProgressByClientSearch"; |
|
|
import ProgressByClientSearch from "@/components/ProgressByClientSearch"; |
|
|
import { Suspense } from "react"; |
|
|
import { Suspense } from "react"; |
|
|
import { fetchFinancialSummaryCard } from "@/app/api/financialsummary"; |
|
|
import { fetchFinancialSummaryCard } from "@/app/api/financialsummary"; |
|
|
import { exportFinancialSummaryByClientExcel, exportFinancialSummaryByProjectExcel, searchFinancialSummaryByClient,searchFinancialSummaryByProject } from "@/app/api/financialsummary/actions"; |
|
|
|
|
|
|
|
|
import { exportFinancialSummaryByClientExcel, exportFinancialSummaryByProjectExcel, FinancialSummaryByProjectResult, FinancialSummaryByClientResult, searchFinancialSummaryByClient,searchFinancialSummaryByProject } from "@/app/api/financialsummary/actions"; |
|
|
import ProjectFinancialCard from "./ProjectFinancialCard"; |
|
|
import ProjectFinancialCard from "./ProjectFinancialCard"; |
|
|
import VisibilityIcon from '@mui/icons-material/Visibility'; |
|
|
import VisibilityIcon from '@mui/icons-material/Visibility'; |
|
|
import { downloadFile } from "@/app/utils/commonUtil"; |
|
|
import { downloadFile } from "@/app/utils/commonUtil"; |
|
|
|
|
|
|
|
|
|
|
|
type SearchProjectQuery = Partial<Omit<FinancialSummaryByProjectResult, "id">>; |
|
|
|
|
|
type SearchClientQuery = Partial<Omit<FinancialSummaryByClientResult, "id">>; |
|
|
|
|
|
type SearchProjectParamNames = keyof SearchProjectQuery; |
|
|
|
|
|
type SearchClientParamNames = keyof SearchClientQuery; |
|
|
|
|
|
|
|
|
const ProjectFinancialSummary: React.FC = () => { |
|
|
const ProjectFinancialSummary: React.FC = () => { |
|
|
const [SearchCriteria, setSearchCriteria] = React.useState({}); |
|
|
const [SearchCriteria, setSearchCriteria] = React.useState({}); |
|
|
const { t } = useTranslation("dashboard"); |
|
|
const { t } = useTranslation("dashboard"); |
|
@@ -31,6 +36,24 @@ const ProjectFinancialSummary: React.FC = () => { |
|
|
const [projectFinancialData, setProjectFinancialData]: any[] = React.useState([]); |
|
|
const [projectFinancialData, setProjectFinancialData]: any[] = React.useState([]); |
|
|
const [clientFinancialRows, setClientFinancialRows]: any[] = React.useState([]); |
|
|
const [clientFinancialRows, setClientFinancialRows]: any[] = React.useState([]); |
|
|
const [projectFinancialRows, setProjectFinancialRows]: any[] = React.useState([]); |
|
|
const [projectFinancialRows, setProjectFinancialRows]: any[] = React.useState([]); |
|
|
|
|
|
const [filteredProjectResult, setFilteredProjectResult]:any[] = useState([]); |
|
|
|
|
|
const [filteredClientResult, setFilteredClientResult]:any[] = useState([]); |
|
|
|
|
|
|
|
|
|
|
|
const projectSearchCriteria: Criterion<SearchProjectParamNames>[] = useMemo( |
|
|
|
|
|
() => [ |
|
|
|
|
|
{ label: "Project Code", paramName: "projectCode", type: "text" }, |
|
|
|
|
|
{ label: "Project Name", paramName: "projectName", type: "text" }, |
|
|
|
|
|
], |
|
|
|
|
|
[t], |
|
|
|
|
|
); |
|
|
|
|
|
const clientSearchCriteria: Criterion<SearchClientParamNames>[] = useMemo( |
|
|
|
|
|
() => [ |
|
|
|
|
|
{ label: "Client Code", paramName: "customerCode", type: "text" }, |
|
|
|
|
|
{ label: "Client Name", paramName: "customerName", type: "text" }, |
|
|
|
|
|
], |
|
|
|
|
|
[t], |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
const fetchData = async () => { |
|
|
const fetchData = async () => { |
|
|
const financialSummaryCard = await fetchFinancialSummaryCard(); |
|
|
const financialSummaryCard = await fetchFinancialSummaryCard(); |
|
|
setProjectFinancialData(financialSummaryCard) |
|
|
setProjectFinancialData(financialSummaryCard) |
|
@@ -41,10 +64,11 @@ const ProjectFinancialSummary: React.FC = () => { |
|
|
console.log(financialSummaryByClient) |
|
|
console.log(financialSummaryByClient) |
|
|
// console.log(financialSummaryByProject) |
|
|
// console.log(financialSummaryByProject) |
|
|
setClientFinancialRows(financialSummaryByClient) |
|
|
setClientFinancialRows(financialSummaryByClient) |
|
|
|
|
|
setFilteredClientResult(financialSummaryByClient) |
|
|
} |
|
|
} |
|
|
useEffect(() => { |
|
|
useEffect(() => { |
|
|
fetchData() |
|
|
fetchData() |
|
|
fetchTableData(undefined) |
|
|
|
|
|
|
|
|
// fetchTableData(undefined) |
|
|
}, []); |
|
|
}, []); |
|
|
|
|
|
|
|
|
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"}, |
|
|
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"}, |
|
@@ -77,6 +101,7 @@ const ProjectFinancialSummary: React.FC = () => { |
|
|
|
|
|
|
|
|
const handleCardClick = (r: any, index:any) => { |
|
|
const handleCardClick = (r: any, index:any) => { |
|
|
fetchTableData(r.teamId) |
|
|
fetchTableData(r.teamId) |
|
|
|
|
|
fetchProjectTableData(r.teamId) |
|
|
setIsCardClickedIndex(index) |
|
|
setIsCardClickedIndex(index) |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
@@ -450,13 +475,14 @@ const columns2 = [ |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
const fetchProjectTableData = async (teamId?:any,customerId?:any) => { |
|
|
const fetchProjectTableData = async (teamId?:any,customerId?:any) => { |
|
|
const financialSummaryByProject = await searchFinancialSummaryByProject(teamId,customerId); |
|
|
|
|
|
|
|
|
const financialSummaryByProject = await searchFinancialSummaryByProject(teamId); |
|
|
setProjectFinancialRows(financialSummaryByProject) |
|
|
setProjectFinancialRows(financialSummaryByProject) |
|
|
|
|
|
setFilteredProjectResult(financialSummaryByProject) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const handleRowClick = (params:any) => { |
|
|
const handleRowClick = (params:any) => { |
|
|
console.log(params.row.teamId); |
|
|
console.log(params.row.teamId); |
|
|
fetchProjectTableData(params.row.teamId,params.row.cid) |
|
|
|
|
|
|
|
|
// fetchProjectTableData(params.row.teamId,params.row.cid) |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
const handleExportByClient = async () => { |
|
|
const handleExportByClient = async () => { |
|
@@ -486,37 +512,83 @@ const columns2 = [ |
|
|
</div> |
|
|
</div> |
|
|
))} |
|
|
))} |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<hr></hr> |
|
|
|
|
|
<div className="ml-10 text-base"><strong>-Formula-</strong></div> |
|
|
|
|
|
<div className="ml-10 text-sm"><strong>CPI:</strong> Invoiced Amount / Cumulative Expenditure</div> |
|
|
|
|
|
<div className="ml-10 text-sm"><strong>Cash Flow Status: </strong>{`Positive when CPI >= 1`}</div> |
|
|
|
|
|
<div className="ml-10 text-sm"><strong>Projected CPI:</strong> Project Fee / Cumulative Expenditure</div> |
|
|
|
|
|
<div className="ml-10 text-sm mb-5"><strong>Cash Flow Status: </strong>{`Positive when Projected CPI >= 1`}</div> |
|
|
</Card> |
|
|
</Card> |
|
|
<Card className="mt-5"> |
|
|
<Card className="mt-5"> |
|
|
<div style={{display:"inline-block"}}> |
|
|
<div style={{display:"inline-block"}}> |
|
|
<CardHeader className="text-slate-500" title="Financial Status (by Client)"/> |
|
|
|
|
|
|
|
|
<CardHeader className="text-slate-500" title="Financial Status (by Project)"/> |
|
|
</div> |
|
|
</div> |
|
|
<div style={{display:"inline-block"}}> |
|
|
<div style={{display:"inline-block"}}> |
|
|
{clientFinancialRows.length > 0 && ( |
|
|
|
|
|
<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"> |
|
|
|
|
|
|
|
|
{projectFinancialRows.length > 0 && ( |
|
|
|
|
|
<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"> |
|
|
Export Excel |
|
|
Export Excel |
|
|
</button> |
|
|
</button> |
|
|
)} |
|
|
)} |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
{projectFinancialRows.length > 0 && ( |
|
|
|
|
|
<SearchBox |
|
|
|
|
|
criteria={projectSearchCriteria} |
|
|
|
|
|
onSearch={(query) => { |
|
|
|
|
|
setFilteredProjectResult( |
|
|
|
|
|
projectFinancialRows.filter( |
|
|
|
|
|
(cp:any) => |
|
|
|
|
|
cp.projectCode.toLowerCase().includes(query.projectCode.toLowerCase()) && |
|
|
|
|
|
cp.projectName.toLowerCase().includes(query.projectName.toLowerCase()) |
|
|
|
|
|
), |
|
|
|
|
|
); |
|
|
|
|
|
}} |
|
|
|
|
|
/> |
|
|
|
|
|
)} |
|
|
<div style={{display:"inline-block",width:"99%",marginLeft:10}}> |
|
|
<div style={{display:"inline-block",width:"99%",marginLeft:10}}> |
|
|
{/* <CustomDatagrid rows={clientFinancialRows} columns={columns} columnWidth={200} dataGridHeight={300} checkboxSelection={true} onRowSelectionModelChange={handleSelectionChange} selectionModel={selectionModel}/> */} |
|
|
|
|
|
<CustomDatagrid onRowClick={handleRowClick} rows={clientFinancialRows} columns={columns} columnWidth={200} dataGridHeight={300}/> |
|
|
|
|
|
|
|
|
<CustomDatagrid rows={filteredProjectResult} columns={columns2} columnWidth={200} dataGridHeight={300}/> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<hr></hr> |
|
|
|
|
|
<div className="ml-10 text-base"><strong>-Formula-</strong></div> |
|
|
|
|
|
<div className="ml-10 text-sm"><strong>CPI:</strong> Invoiced Amount / Cumulative Expenditure</div> |
|
|
|
|
|
<div className="ml-10 text-sm"><strong>Cash Flow Status: </strong>{`Positive when CPI >= 1`}</div> |
|
|
|
|
|
<div className="ml-10 text-sm"><strong>Projected CPI:</strong> Project Fee / Cumulative Expenditure</div> |
|
|
|
|
|
<div className="ml-10 text-sm mb-5"><strong>Cash Flow Status: </strong>{`Positive when Projected CPI >= 1`}</div> |
|
|
</Card> |
|
|
</Card> |
|
|
<Card className="mt-5"> |
|
|
<Card className="mt-5"> |
|
|
<div style={{display:"inline-block"}}> |
|
|
<div style={{display:"inline-block"}}> |
|
|
<CardHeader className="text-slate-500" title="Financial Status (by Project)"/> |
|
|
|
|
|
|
|
|
<CardHeader className="text-slate-500" title="Financial Status (by Client)"/> |
|
|
</div> |
|
|
</div> |
|
|
<div style={{display:"inline-block"}}> |
|
|
<div style={{display:"inline-block"}}> |
|
|
{projectFinancialRows.length > 0 && ( |
|
|
|
|
|
<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"> |
|
|
|
|
|
|
|
|
{clientFinancialRows.length > 0 && ( |
|
|
|
|
|
<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"> |
|
|
Export Excel |
|
|
Export Excel |
|
|
</button> |
|
|
</button> |
|
|
)} |
|
|
)} |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
{clientFinancialRows.length > 0 && ( |
|
|
|
|
|
<SearchBox |
|
|
|
|
|
criteria={clientSearchCriteria} |
|
|
|
|
|
onSearch={(query) => { |
|
|
|
|
|
setFilteredClientResult( |
|
|
|
|
|
clientFinancialRows.filter( |
|
|
|
|
|
(cp:any) => |
|
|
|
|
|
cp.customerCode.toLowerCase().includes(query.customerCode.toLowerCase()) && |
|
|
|
|
|
cp.customerName.toLowerCase().includes(query.customerName.toLowerCase()) |
|
|
|
|
|
), |
|
|
|
|
|
); |
|
|
|
|
|
}} |
|
|
|
|
|
/> |
|
|
|
|
|
)} |
|
|
<div style={{display:"inline-block",width:"99%",marginLeft:10}}> |
|
|
<div style={{display:"inline-block",width:"99%",marginLeft:10}}> |
|
|
<CustomDatagrid rows={projectFinancialRows} columns={columns2} columnWidth={200} dataGridHeight={300}/> |
|
|
|
|
|
|
|
|
{/* <CustomDatagrid rows={clientFinancialRows} columns={columns} columnWidth={200} dataGridHeight={300} checkboxSelection={true} onRowSelectionModelChange={handleSelectionChange} selectionModel={selectionModel}/> */} |
|
|
|
|
|
<CustomDatagrid onRowClick={handleRowClick} rows={filteredClientResult} columns={columns} columnWidth={200} dataGridHeight={300}/> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<hr></hr> |
|
|
|
|
|
<div className="ml-10 text-base"><strong>-Formula-</strong></div> |
|
|
|
|
|
<div className="ml-10 text-sm"><strong>CPI:</strong> Invoiced Amount / Cumulative Expenditure</div> |
|
|
|
|
|
<div className="ml-10 text-sm"><strong>Cash Flow Status: </strong>{`Positive when CPI >= 1`}</div> |
|
|
|
|
|
<div className="ml-10 text-sm"><strong>Projected CPI:</strong> Project Fee / Cumulative Expenditure</div> |
|
|
|
|
|
<div className="ml-10 text-sm mb-5"><strong>Cash Flow Status: </strong>{`Positive when Projected CPI >= 1`}</div> |
|
|
</Card> |
|
|
</Card> |
|
|
</Grid> |
|
|
</Grid> |
|
|
); |
|
|
); |
|
|