"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 ProgressByTeamSearch from "@/components/ProgressByTeamSearch"; import { Suspense } from "react"; import { useSearchParams } from 'next/navigation'; import { fetchAllTeamProjects, TeamProjectResult, ClientSubsidiaryProjectResult, fetchTeamProjects, fetchAllTeamConsumption, fetchAllTeamConsumptionColorOrder} from "@/app/api/teamprojects/actions"; import Typography from "@mui/material/Typography"; // const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false }); type SearchProjectQuery = Partial>; type SearchProjectParamNames = keyof SearchProjectQuery; interface Props { projects: TeamProjectResult[]; } type SearchQuery = Partial>; type SearchParamNames = keyof SearchQuery; const ProjectResourceConsumptionRanking: React.FC = () => { const searchParams = useSearchParams(); const teamLeadId = searchParams.get('teamLeadId'); const [activeTab, setActiveTab] = useState("financialSummary"); const [SearchCriteria, setSearchCriteria] = React.useState({}); const { t } = useTranslation("dashboard"); const [projectData, setProjectData]: any[] = React.useState([]); const [filteredResult, setFilteredResult]:any[] = useState([]); const [teamCode, setTeamCode] = useState(""); const [teamName, setTeamName] = useState(""); const [projectArray, setProjectArray]: any[] = useState([]); const [percentageArray, setPercentageArray]: any[] = useState([]); const [colorArray, setColorArray]: any[] = useState([]); const [selectionModel, setSelectionModel]: any[] = React.useState([]); const [pieChartColor, setPieChartColor]: any[] = React.useState([]); const [filteredTeamProjectResult, setFilteredTeamProjectResult]:any[] = useState([]); const [totalSpentPercentage, setTotalSpentPercentage]: any = React.useState(); const [projectBudgetManhour, setProjectBudgetManhour]: any = React.useState("-"); const [actualManhourSpent, setActualManhourSpent]: any = React.useState("-"); const [remainedManhour, setRemainedManhour]: any = React.useState("-"); const [lastUpdate, setLastUpdate]: any = React.useState("-"); const [dropdownDemo, setDropdownDemo] = useState(""); const [dateDemo, setDateDemo] = useState(null); const [checkboxDemo, setCheckboxDemo] = useState(false); const [receiptFromDate, setReceiptFromDate] = useState(null); const [receiptToDate, setReceiptToDate] = useState(null); const [selectedRows, setSelectedRows] = useState([]); const [chartProjectColor, setChartProjectColor]:any[] = useState([]); const [chartProjectName, setChartProjectName]:any[] = useState([]); const [chartProjectDisplayName, setChartProjectDisplayName]:any[] = useState([]); const [chartProjectBudgetedHour, setChartProjectBudgetedHour]:any[] = useState([]); const [chartProjectSpentHour, setChartProjectSpentHour]:any[] = useState([]); const [chartManhourConsumptionPercentage, setChartManhourConsumptionPercentage]:any[] = useState([]); const [chartTeam, setChartTeam]:any[] = useState([]); const color = ["#f57f90", "#94f7d6", "#87c5f5", "#ab95f5", "#fcd68b", "#f58a9b", "#8ef4d1", "#92caf9", "#a798f9", "#fad287", "#f595a6", "#88f1cc", "#9dcff5", "#a39bf5", "#f8de83", "#f5a0b1", "#82eec7", "#a8d4f1", "#9f9ef1", "#f6ea7f", "#f5abb4", "#7cebca", "#b3d9ed", "#9ba1ed", "#f4f67b", "#f5b6b7", "#76e8cd", "#bed6e9", "#97a4e9", "#f2fa77", "#f5c1ba", "#70e5d0", "#c9d3e5", "#93a7e5", "#f0fe73", "#f5ccbd", "#6ae2d3", "#d4d0e1", "#8faae1", "#eefe6f", "#f5d7c0", "#64dfd6", "#dfc5dd", "#8badd5", "#ecfe6b", "#f5e2c3", "#5edcd9", "#eabada", "#87b0c9", "#eafc67", "#f5edc6", "#58d9dc", "#f5afd6", "#83b3bd", "#e8fc63", "#f5f8c9", "#52d6df", "#ffacd2", "#7fb6b1", "#e6fc5f", "#f5ffcc", "#4cd3e2", "#ffa9ce", "#7bb9a5", "#e4fc5b", "#f2ffcf", "#46d0e5", "#ffa6ca", "#77bc99", "#e2fc57", "#efffd2", "#40cde8", "#ffa3c6", "#73bf8d", "#e0fc53", "#ecffd5", "#3acaeb", "#ffa0c2", "#6fc281", "#defb4f", "#e9ffd8", "#34c7ee", "#ff9dbe", "#6bc575", "#dcfb4b", "#e6ffdb", "#2ec4f1", "#ff9aba", "#67c869", "#dafb47", "#e3ffde", "#28c1f4", "#ff97b6", "#63cb5d", "#d8fb43", "#e0ffe1", "#22bef7", "#ff94b2", "#5fce51", "#d6fb3f", "#ddfee4", "#1cbbfa", "#ff91ae", "#5bd145", "#d4fb3b", "#dafee7", "#16b8fd", "#ff8eaa", "#57d439", "#d2fb37", "#d7feea", "#10b5ff", "#ff8ba6", "#53d72d", "#d0fb33", "#d4feed", "#0ab2ff", "#ff88a2", "#4fda21", "#cefb2f", "#d1fef0", "#04afff", "#ff859e", "#4bdd15", "#ccfb2b"]; const [teamProjectResult, setTeamProjectResult]:any[] = useState([]); const [teamProjectColorOrder, setTeamProjectColorOrder]:any[] = useState([]); const [currentPageProjectList, setCurrentPageProjectList]: any[] = React.useState([]); const [currentPageProjectNameList, setCurrentPageProjectNameList]: any[] = React.useState([]); const [currentPageProjectBudgetedManhourList, setCurrentPageProjectBudgetedManhourList]: any[] = React.useState([]); const [currentPageProjectSpentManhourList, setCurrentPageProjectSpentManhourList]: any[] = React.useState([]); const [currentPagePercentage, setCurrentPagePercentage]: any[] = React.useState([]); const [currentPageColor, setCurrentPageColor]: any[] = React.useState([]); const [currentPage, setCurrentPage] = useState(1); const recordsPerPage = 10; const [tableSorting, setTableSorting] = useState('ProjectName'); const [selectedTeamIdList, setSelectedTeamIdList]: any[] = React.useState([]); const fetchTeamData = async () => { const teamprojects = await fetchTeamProjects(); setProjectData(teamprojects) setFilteredResult(teamprojects) } const fetchData = async () => { console.log(selectedTeamIdList) if (selectedTeamIdList) { try { const clickResult = await fetchAllTeamConsumption( selectedTeamIdList,tableSorting) const colorOrder = await fetchAllTeamConsumptionColorOrder( selectedTeamIdList,tableSorting) console.log(clickResult) setTeamProjectResult(clickResult); setFilteredTeamProjectResult(clickResult); setTeamProjectColorOrder(colorOrder); } catch (error) { console.error('Error fetching team consumption:', error); } } } const projectSearchCriteria: Criterion[] = useMemo( () => [ { label: t("Project Code"), paramName: "projectCode", type: "text" }, { label: t("Project Name"), paramName: "projectName", type: "text" }, ], [t], ); const searchCriteria: Criterion[] = useMemo( () => [ { label: t("Team Code"), paramName: "teamCode", type: "text" }, { label: t("Team Name"), paramName: "teamName", type: "text" }, ], [t], ); useEffect(() => { const projectNo = [] const projectName = [] const projectBudgetedManHour = [] const projectSpentManHour = [] const manhourConsumptionPercentage = [] const chartColor = [] const chartTeam = [] const colorOrder = [] let c = 0 let d = 0 for (let i = 0; i < teamProjectColorOrder.length; i++){ if (i === 0) { chartTeam.push('Team '+teamProjectColorOrder[i].team) colorOrder.push({"team":teamProjectColorOrder[i].team,"color":color[d]}) } else if (teamProjectColorOrder[i].team !== teamProjectColorOrder[i - 1].team) { d = d + 1 chartTeam.push('Team '+teamProjectColorOrder[i].team) colorOrder.push({"team":teamProjectColorOrder[i].team,"color":color[d]}) } } for (let i = 0; i < teamProjectResult.length; i++){ projectNo.push(teamProjectResult[i].projectCode + "(" + teamProjectResult[i].team + ")") projectName.push(teamProjectResult[i].projectName) projectBudgetedManHour.push(teamProjectResult[i].budgetedManhour) projectSpentManHour.push(teamProjectResult[i].spentManhour) manhourConsumptionPercentage.push(teamProjectResult[i].manhourConsumptionPercentage) for (let j = 0; j < colorOrder.length; j++){ if (teamProjectResult[i].team === colorOrder[j].team){ chartColor.push(colorOrder[j].color) teamProjectResult[i].color = color[j] } } // if (i === 0) { // chartColor.push(color[c]) // teamProjectResult[i].color = color[c] // } else if (teamProjectResult[i].team !== teamProjectResult[i - 1].team) { // c = c + 1 // chartColor.push(color[c]) // teamProjectResult[i].color = color[c] // } else if (teamProjectResult[i].team === teamProjectResult[i - 1].team){ // chartColor.push(color[c]) // teamProjectResult[i].color = color[c] // } } setChartProjectColor(chartColor) setChartProjectName(projectNo) setChartProjectDisplayName(projectName) setChartProjectBudgetedHour(projectBudgetedManHour) setChartProjectSpentHour(projectSpentManHour) setChartManhourConsumptionPercentage(manhourConsumptionPercentage) setChartTeam(chartTeam) }, [teamProjectResult, teamProjectColorOrder]); useEffect(() => { fetchTeamData() }, []); useEffect(() => { fetchData() }, [selectedTeamIdList,tableSorting]); const rows = [ { id: 1, teamCode: "TEAM-001", teamName: "Team A", noOfProjects: "5", }, { id: 2, teamCode: "TEAM-001", teamName: "Team B", noOfProjects: "5", }, { id: 3, teamCode: "TEAM-001", teamName: "Team C", noOfProjects: "3", }, { id: 4, teamCode: "TEAM-001", teamName: "Team D", noOfProjects: "1", }, ]; //['#f57f90', '#94f7d6', '#87c5f5', '#ab95f5', '#fcd68b'] const rows2 = [ { id: 1, project: "Consultancy Project 123", team: "XXX", teamLeader: "XXX", currentStage: "Contract Documentation", budgetedManhour: "200.00", spentManhour: "120.00", remainedManhour: "80.00", comingPaymentMilestone: "31/03/2024", alert: false, color: "#f57f90", }, { id: 2, project: "Consultancy Project 456", team: "XXX", teamLeader: "XXX", currentStage: "Report Preparation", budgetedManhour: "400.00", spentManhour: "200.00", remainedManhour: "200.00", comingPaymentMilestone: "20/02/2024", alert: false, color: "#94f7d6", }, { id: 3, project: "Construction Project A", team: "YYY", teamLeader: "YYY", currentStage: "Construction", budgetedManhour: "187.50", spentManhour: "200.00", remainedManhour: "12.50", comingPaymentMilestone: "13/12/2023", alert: true, color: "#87c5f5", }, { id: 4, project: "Construction Project B", team: "XXX", teamLeader: "XXX", currentStage: "Post Construction", budgetedManhour: "100.00", spentManhour: "40.00", remainedManhour: "60.00", comingPaymentMilestone: "05/01/2024", alert: false, color: "#ab95f5", }, { id: 5, project: "Construction Project C", team: "YYY", teamLeader: "YYY", currentStage: "Construction", budgetedManhour: "300.00", spentManhour: "150.00", remainedManhour: "150.00", comingPaymentMilestone: "31/03/2024", alert: false, color: "#fcd68b", }, ]; const searchColumns = [ { id: "teamCode", field: "teamCode", headerName: t("Team Code"), flex: 1, }, { id: "teamName", field: "teamName", headerName: t("Team Name"), flex: 1, }, { id: "projectNo", field: "projectNo", headerName: t("No. of Projects"), flex: 1, }, ]; const columns = [ { id: "clientCode", field: "clientCode", headerName: "Client Code", flex: 1, }, { id: "clientName", field: "clientName", headerName: "Client Name", flex: 1, }, { id: "clientSubsidiaryCode", field: "clientSubsidiaryCode", headerName: "Client Subsidiary Code", flex: 1, }, { id: "noOfProjects", field: "noOfProjects", headerName: "No. of Projects", flex: 1, }, ]; const columns2 = [ { id: "color", field: "color", headerName: "", renderCell: (params: any) => { return ( ); }, flex: 0.1, }, { id: "projectCode", field: "projectCode", headerName: t("Project Code"), minWidth:100 }, { id: "projectName", field: "projectName", headerName: t("Project Name"), minWidth:300 }, { id: "team", field: "team", headerName: t("Team"), minWidth:50 }, { id: "teamLead", field: "teamLead", headerName: t("Team Leader"), minWidth: 70 }, { id: "expectedStage", field: "expectedStage", headerName: t("Expected Stage"), minWidth: 300, renderCell: (params: any) => { if (params.row.expectedStage != null){ const expectedStage = params.row.expectedStage; const lines = expectedStage.split(",").map((line:any, index:any) => ( {line.trim()}
)); return
{lines}
; } else { return
-
; } }, }, { id: "budgetedManhour", field: "budgetedManhour", headerName: t("Budgeted Manhours"), minWidth: 70, type: "number", renderCell: (params: any) => { return {params.row.budgetedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}; } }, { id: "spentManhour", field: "spentManhour", headerName: t("Spent Manhours"), type: "number", renderCell: (params: any) => { if (params.row.budgetedManhour - params.row.spentManhour <= 0) { return ( {params.row.spentManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} ); } else { return {params.row.spentManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}; } }, minWidth: 70 }, { id: "remainedManhour", field: "remainedManhour", headerName: t("Remained Manhours"), type: "number", renderCell: (params: any) => { if (params.row.budgetedManhour - params.row.spentManhour <= 0) { return ( ({params.row.remainedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}) ); } else { return {params.row.remainedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}; } }, minWidth: 70 }, { id: "comingPaymentMilestone", field: "comingPaymentMilestone", headerName: t("Coming Payment Milestones"), minWidth: 100 }, { id: "alert", field: "alert", headerName: t("Alert"), renderCell: (params: any) => { if (params.row.alert === 1) { return ( ); } else { return ; } }, flex: 0.1, }, ]; const InputFields = [ { id: "teamCode", label: "Team Code", type: "text", value: teamCode, setValue: setTeamCode, }, { id: "teamName", label: "Team Name", type: "text", value: teamName, setValue: setTeamName, }, // { id: 'dropdownDemo', label: "dropdownDemo", type: 'dropdown', options: [{id:"1", label:"1"}], value: dropdownDemo, setValue: setDropdownDemo }, // { id: 'dateDemo', label:'dateDemo', type: 'date', value: dateDemo, setValue: setDateDemo }, // { id: 'checkboxDemo', label:'checkboxDemo', type: 'checkbox', value: checkboxDemo, setValue: setCheckboxDemo }, // { id: ['receiptFromDate','receiptToDate'], label: ["收貨日期","收貨日期"], value: [receiptFromDate ? receiptFromDate : null, receiptToDate ? receiptToDate : null], // setValue: [setReceiptFromDate, setReceiptToDate],type: 'dateRange' }, ]; const stageDeadline = [ "31/03/2024", "20/02/2024", "01/12/2023", "05/01/2024", "31/03/2023", ]; const series2: ApexAxisChartSeries | ApexNonAxisChartSeries = [ { data: [17.1, 28.6, 5.7, 48.6], }, ]; const series: ApexAxisChartSeries | ApexNonAxisChartSeries = [ { name: "Project Resource Consumption Percentage", data: [80, 55, 40, 65, 70], }, ]; const options2: ApexOptions = { chart: { type: "donut", }, colors: colorArray, plotOptions: { pie: { donut: { labels: { show: true, name: { show: true, }, value: { show: true, fontWeight: 500, fontSize: "30px", color: "#3e98c7", }, total: { show: true, showAlways: true, label: t("Spent"), fontFamily: "sans-serif", formatter: function (val) { return totalSpentPercentage + "%"; }, }, }, }, }, }, labels: projectArray, legend: { show: false, }, tooltip: { enabled: true, y: { formatter: function (val) { return (val.toString().includes(".") ? val.toString() : val.toFixed(1)) + "%"; } } }, responsive: [ { breakpoint: 480, options: { chart: { width: 200, }, legend: { position: "bottom", show: false, }, }, }, ], }; const options: ApexOptions = { chart: { type: "bar", height: 450, }, tooltip: { enabled: true, // Enable tooltip custom: ({ series, seriesIndex, dataPointIndex, w }) => { const projectCode = currentPageProjectList[dataPointIndex]; const projectName = currentPageProjectNameList[dataPointIndex]; const budgetManhours = currentPageProjectBudgetedManhourList[dataPointIndex]; const spentManhours = currentPageProjectSpentManhourList[dataPointIndex]; const value = series[seriesIndex][dataPointIndex]; const tooltipContent = `
${projectCode} - ${projectName}
${t("Budget Manhours")}: ${budgetManhours.toFixed(2)} ${t("hours")}
${t("Spent Manhours")}: ${spentManhours.toFixed(2)} ${t("hours")}
Percentage: ${value.toString().includes(".") ? value.toString() : value.toFixed(1)}%
`; return tooltipContent; }, }, series: [{ name: "Project Resource Consumption Percentage", data: currentPagePercentage, },], colors: currentPageColor, plotOptions: { bar: { horizontal: true, distributed: true, dataLabels: { position: 'top' }, }, }, dataLabels: { enabled: true, textAnchor: 'end', formatter: (val) => `${val}%`, }, xaxis: { categories: currentPageProjectList, }, yaxis: { title: { text: t("Projects"), }, labels: { maxWidth: 200, style: { cssClass: "apexcharts-yaxis-label", }, }, }, title: { text: t("Project Resource Consumption Percentage"), align: "center", }, grid: { borderColor: "#f1f1f1", xaxis: { lines: { show: true, } } }, legend:{ show: true, showForSingleSeries: true, customLegendItems: chartTeam, markers: { fillColors: color } }, annotations: {}, }; const handleSearchSelectionChange = (newSelectionModel: GridRowSelectionModel) => { const selectedRowsData = projectData.filter((row: any) => newSelectionModel.includes(row.id), ); const teamIdList = [] for (var i=0; i { const selectedRowsData = teamProjectResult.filter((row:any) => newSelectionModel.includes(row.id), ); console.log(selectedRowsData); const projectArray = []; const pieChartColorArray = []; let totalSpent = 0; let totalBudgetManhour = 0; const percentageArray = []; for (let i = 0; i <= selectedRowsData.length; i++) { if (i === selectedRowsData.length && i > 0) { projectArray.push(t("Remained")); } else if (selectedRowsData.length > 0) { projectArray.push(selectedRowsData[i].projectName); totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour); totalSpent += Number(selectedRowsData[i].spentManhour); pieChartColorArray.push(selectedRowsData[i].color); } } for (let i = 0; i <= selectedRowsData.length; i++) { if (i === selectedRowsData.length && i > 0) { const remainedManhour = totalBudgetManhour - totalSpent; percentageArray.push( Number(((remainedManhour / totalBudgetManhour) * 100).toFixed(1)), ); } else if (selectedRowsData.length > 0) { const percentage = ( (Number(selectedRowsData[i].spentManhour) / totalBudgetManhour) * 100 ).toFixed(1); percentageArray.push(Number(percentage)); } } setProjectBudgetManhour(totalBudgetManhour.toFixed(2)); setActualManhourSpent(totalSpent.toFixed(2)); setRemainedManhour((totalBudgetManhour - totalSpent).toFixed(2)); setLastUpdate(new Date().toLocaleDateString("en-GB")); setSelectionModel(newSelectionModel); console.log(projectArray); setProjectArray(projectArray); setPercentageArray(percentageArray); console.log(percentageArray); setTotalSpentPercentage( ((totalSpent / totalBudgetManhour) * 100).toFixed(1), ); if (projectArray.length > 0 && projectArray.includes(t("Remained"))) { const nonLastRecordColors = pieChartColorArray; setColorArray([ ...nonLastRecordColors.slice(0, projectArray.length - 1), "#a3a3a3", ]); } else { setColorArray(pieChartColorArray); } }; const startIndex = (currentPage - 1) * recordsPerPage; const endIndex = startIndex + recordsPerPage; useEffect(() => { console.log(chartManhourConsumptionPercentage) const currentPageProjectData = chartProjectName.slice(startIndex, endIndex) const currentPageProjectName = chartProjectDisplayName.slice(startIndex, endIndex) const currentPageProjectBudgetedManhour = chartProjectBudgetedHour.slice(startIndex, endIndex) const currentPageProjectSpentManhour = chartProjectSpentHour.slice(startIndex, endIndex) const currentPageData = chartManhourConsumptionPercentage.slice(startIndex, endIndex); const colorArray = chartProjectColor.slice(startIndex, endIndex); console.log(currentPage) console.log(Math.ceil(chartManhourConsumptionPercentage.length / recordsPerPage)) setCurrentPageProjectList(currentPageProjectData) setCurrentPageProjectNameList(currentPageProjectName) setCurrentPageProjectBudgetedManhourList(currentPageProjectBudgetedManhour) setCurrentPageProjectSpentManhourList(currentPageProjectSpentManhour) setCurrentPagePercentage(currentPageData) setCurrentPageColor(colorArray) }, [chartManhourConsumptionPercentage,currentPage]); const handlePrevPage = () => { if (currentPage > 1) { setCurrentPage(currentPage - 1); } }; const handleNextPage = () => { if (endIndex < chartManhourConsumptionPercentage.length) { setCurrentPage(currentPage + 1); } }; const applySearch = (data: any) => { console.log(data); setSearchCriteria(data); }; return ( <> {t("Project Resource Consumption Ranking")} { setFilteredResult( projectData.filter( (cp:any) => cp.teamCode.toLowerCase().includes(query.teamCode.toLowerCase()) && cp.teamName.toLowerCase().includes(query.teamName.toLowerCase()) ), ); }} />
{t("Sorting")}:
{currentPage === 1 && ( )} {currentPage !== 1 && ( )} {endIndex >= chartManhourConsumptionPercentage.length && ( )} {endIndex < chartManhourConsumptionPercentage.length && ( )} {t("Page")}  {chartManhourConsumptionPercentage.length === 0 && ( 0 )} {chartManhourConsumptionPercentage.length > 0 && ( currentPage )}  of  {Math.ceil(chartManhourConsumptionPercentage.length / recordsPerPage)}
{teamProjectResult.length > 0 && ( { setFilteredTeamProjectResult( teamProjectResult.filter( (cp:any) => cp.projectCode.toLowerCase().includes(query.projectCode.toLowerCase()) && cp.projectName.toLowerCase().includes(query.projectName.toLowerCase()) ), ); }} /> )}
{percentageArray.length === 0 && (
{t("Please select the project you want to check.")}
)} {percentageArray.length > 0 && ( )}
{t("Project Budget Manhours")}
{projectBudgetManhour}

{t("Actual Manhours Spent")}
{actualManhourSpent}

{t("Remained Manhours")}
{remainedManhour}

{t("Last Update")}
{lastUpdate}
); }; export default ProjectResourceConsumptionRanking;