Przeglądaj źródła

update

tags/Baseline_30082024_FRONTEND_UAT
Mac\David 1 rok temu
rodzic
commit
e761dbc668
15 zmienionych plików z 1592 dodań i 175 usunięć
  1. +28
    -0
      src/app/(main)/dashboard/ProjectResourceConsumptionRanking/page.tsx
  2. +2
    -0
      src/app/api/cashflow/index.ts
  3. +3
    -3
      src/app/api/clientprojects/actions.ts
  4. +36
    -2
      src/app/api/teamprojects/actions.ts
  5. +1
    -0
      src/components/Breadcrumb/Breadcrumb.tsx
  6. +5
    -0
      src/components/NavigationContent/NavigationContent.tsx
  7. +85
    -10
      src/components/ProgressByClient/ProgressByClient.tsx
  8. +96
    -11
      src/components/ProgressByTeam/ProgressByTeam.tsx
  9. +38
    -8
      src/components/ProjectCashFlow/ProjectCashFlow.tsx
  10. +64
    -0
      src/components/ProjectFinancialSummary/ProjectFinancialCard.tsx
  11. +140
    -73
      src/components/ProjectFinancialSummary/ProjectFinancialSummary.tsx
  12. +923
    -0
      src/components/ProjectResourceConsumptionRanking/ProjectResourceConsumptionRanking.tsx
  13. +1
    -0
      src/components/ProjectResourceConsumptionRanking/index.ts
  14. +90
    -49
      src/components/ProjectResourceSummary/ProjectResourceSummary.tsx
  15. +80
    -19
      src/components/StaffUtilization/StaffUtilization.tsx

+ 28
- 0
src/app/(main)/dashboard/ProjectResourceConsumptionRanking/page.tsx Wyświetl plik

@@ -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 ProgressByTeamSearch from "@/components/ProgressByTeamSearch";
import { Suspense } from "react";
import Tabs, { TabsProps } from "@mui/material/Tabs";
import Tab from "@mui/material/Tab";
import Typography from "@mui/material/Typography";
import ProjectResourceConsumptionRankingDisplay from "@/components/ProjectResourceConsumptionRanking";
import { preloadClientProjects } from "@/app/api/clientprojects";

export const metadata: Metadata = {
title: "Project Resource Consumption Ranking",
};

const ProjectResourceConsumptionRanking: React.FC = () => {
preloadClientProjects();
return (
<I18nProvider namespaces={["dashboard"]}>
<Typography variant="h4" marginInlineEnd={2}>
Project Resource Consumption Ranking
</Typography>
<ProjectResourceConsumptionRankingDisplay/>
</I18nProvider>
);
};
export default ProjectResourceConsumptionRanking;

+ 2
- 0
src/app/api/cashflow/index.ts Wyświetl plik

@@ -39,6 +39,8 @@ export interface CashFlowReceivableAndExpenditure {
totalBudget: number;
totalExpenditure: number;
expenditureReceivable: number;
totalProjectFee: number;
invoicedPercentage: number;
}
export interface CashFlowAnticipatedChartResult {
anticipateIncomeList: any[];


+ 3
- 3
src/app/api/clientprojects/actions.ts Wyświetl plik

@@ -21,14 +21,14 @@ export interface ClientSubsidiaryProjectResult {
comingPaymentMilestone: string;
}

export const fetchAllClientSubsidiaryProjects = cache(async (customerId: number, subsidiaryId?: number) => {
export const fetchAllClientSubsidiaryProjects = cache(async (customerId: number, tableSorting:string, subsidiaryId?: number) => {
if (subsidiaryId === 0){
return serverFetchJson<ClientSubsidiaryProjectResult[]>(
`${BASE_API_URL}/dashboard/searchCustomerSubsidiaryProject?customerId=${customerId}`
`${BASE_API_URL}/dashboard/searchCustomerSubsidiaryProject?customerId=${customerId}&tableSorting=${tableSorting}`
);
} else {
return serverFetchJson<ClientSubsidiaryProjectResult[]>(
`${BASE_API_URL}/dashboard/searchCustomerSubsidiaryProject?customerId=${customerId}&subsidiaryId=${subsidiaryId}`
`${BASE_API_URL}/dashboard/searchCustomerSubsidiaryProject?customerId=${customerId}&subsidiaryId=${subsidiaryId}&tableSorting=${tableSorting}`
);
}


+ 36
- 2
src/app/api/teamprojects/actions.ts Wyświetl plik

@@ -21,9 +21,43 @@ export interface ClientSubsidiaryProjectResult {
comingPaymentMilestone: string;
}

export const fetchAllTeamProjects = cache(async (teamLeadId: number) => {
export interface TeamConsumptionResult {
color: string;
team: string;
teamLead: string;
budgetedManhour: number;
spentManhour: number;
remainedManhour: number;
manhourConsumptionPercentage: number;
}

export interface TeamProjectResult {
id: number;
teamId: number;
teamLeadId: number;
teamCode: string;
teamName: string;
projectNo: number;
}

export const fetchTeamProjects = cache(async () => {
return serverFetchJson<TeamProjectResult[]>(`${BASE_API_URL}/dashboard/searchTeamProjectNo`);
});

export const fetchAllTeamProjects = cache(async (teamLeadId: number, tableSorting:string) => {
return serverFetchJson<ClientSubsidiaryProjectResult[]>(
`${BASE_API_URL}/dashboard/searchTeamProject?teamLeadId=${teamLeadId}`
`${BASE_API_URL}/dashboard/searchTeamProject?teamLeadId=${teamLeadId}&tableSorting=${tableSorting}`
);

});

export const fetchAllTeamConsumption = cache(async (teamIdList: number[],tableSorting:string) => {
if (teamIdList.length !== 0) {
const queryParams = new URLSearchParams();
queryParams.append('teamIdList', teamIdList.join(','));
return serverFetchJson<TeamConsumptionResult[]>(`${BASE_API_URL}/dashboard/searchTeamConsumption?${queryParams.toString()}&tableSorting=${tableSorting}`);
} else {
return [];
}
});

+ 1
- 0
src/components/Breadcrumb/Breadcrumb.tsx Wyświetl plik

@@ -21,6 +21,7 @@ const pathToLabelMap: { [path: string]: string } = {
"/dashboard/ProjectResourceSummary": "Project Resource Summary",
"/dashboard/ProjectStatusByClient": "Project Status by Client",
"/dashboard/ProjectStatusByTeam": "Project Status by Team",
"/dashboard/ProjectResourceConsumptionRanking": "Project Resource Consumption Ranking",
"/dashboard/StaffUtilization": "Staff Utilization",
"/projects": "Projects",
"/projects/create": "Create Project",


+ 5
- 0
src/components/NavigationContent/NavigationContent.tsx Wyświetl plik

@@ -127,6 +127,11 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => {
label: "Project Status by Team",
path: "/dashboard/ProjectStatusByTeam",
},
{
icon: <AccountTreeIcon />,
label: "Project Resource Consumption Ranking",
path: "/dashboard/ProjectResourceConsumptionRanking",
},
{
icon: <PeopleIcon />,
label: "Staff Utilization",


+ 85
- 10
src/components/ProgressByClient/ProgressByClient.tsx Wyświetl plik

@@ -59,6 +59,9 @@ const ProgressByClient: React.FC<Props> = () => {
const [receiptToDate, setReceiptToDate] = useState(null);
const [selectedRows, setSelectedRows]: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 color = ["#f57f90", "#94f7d6", "#87c5f5", "#ab95f5", "#fcd68b",
"#f58a9b", "#8ef4d1", "#92caf9", "#a798f9", "#fad287",
@@ -86,6 +89,7 @@ const ProgressByClient: React.FC<Props> = () => {
"#d4feed", "#0ab2ff", "#ff88a2", "#4fda21", "#cefb2f",
"#d1fef0", "#04afff", "#ff859e", "#4bdd15", "#ccfb2b"];
const [clientSubsidiaryProjectResult, setClientSubsidiaryProjectResult]:any[] = useState([]);
const [tableSorting, setTableSorting] = useState('ProjectName');

const fetchData = async () => {
if (customerId && subsidiaryId) {
@@ -93,12 +97,13 @@ const ProgressByClient: React.FC<Props> = () => {
if (subsidiaryId === '-'){
console.log("ss")
const clickResult = await fetchAllClientSubsidiaryProjects(
Number(customerId),Number(0))
Number(customerId),tableSorting,Number(0))
console.log(clickResult)
setClientSubsidiaryProjectResult(clickResult);
} else {
const clickResult = await fetchAllClientSubsidiaryProjects(
Number(customerId),
tableSorting,
Number(subsidiaryId))
console.log(clickResult)
setClientSubsidiaryProjectResult(clickResult);
@@ -113,19 +118,28 @@ const ProgressByClient: React.FC<Props> = () => {
useEffect(() => {
const projectCode = []
const projectName = []
const projectBudgetedManHour = []
const projectSpentManHour = []
const manhourConsumptionPercentage = []
for (let i = 0; i < clientSubsidiaryProjectResult.length; i++){
clientSubsidiaryProjectResult[i].color = color[i]
projectCode.push(clientSubsidiaryProjectResult[i].projectCode)
projectCode.push(clientSubsidiaryProjectResult[i].projectCode + "(" + clientSubsidiaryProjectResult[i].team + ")")
projectName.push(clientSubsidiaryProjectResult[i].projectName)
projectBudgetedManHour.push(clientSubsidiaryProjectResult[i].budgetedManhour)
projectSpentManHour.push(clientSubsidiaryProjectResult[i].spentManhour)
manhourConsumptionPercentage.push(clientSubsidiaryProjectResult[i].manhourConsumptionPercentage)
}
setChartProjectName(projectCode)
setChartProjectDisplayName(projectName)
setChartProjectBudgetedHour(projectBudgetedManHour)
setChartProjectSpentHour(projectSpentManHour)
setChartManhourConsumptionPercentage(manhourConsumptionPercentage)
}, [clientSubsidiaryProjectResult]);

useEffect(() => {
fetchData()
}, [customerId,subsidiaryId]);
}, [customerId,subsidiaryId,tableSorting]);



@@ -383,7 +397,31 @@ const ProgressByClient: React.FC<Props> = () => {
const options: ApexOptions = {
chart: {
type: "bar",
height: 350,
height: 450,
},
tooltip: {
enabled: true, // Enable tooltip
custom: ({ series, seriesIndex, dataPointIndex, w }) => {

const projectCode = chartProjectName[dataPointIndex];
const projectName = chartProjectDisplayName[dataPointIndex];
const budgetManhours = chartProjectBudgetedHour[dataPointIndex];
const spentManhours = chartProjectSpentHour[dataPointIndex];
const value = series[seriesIndex][dataPointIndex];
const tooltipContent = `
<div style="width: 250px;">
<span style="font-weight: bold;">${projectCode} - ${projectName}</span>
<br>
Budget Manhours: ${budgetManhours} hours
<br>
Spent Manhours: ${spentManhours} hours
<br>
Percentage: ${value}%
</div>
`;

return tooltipContent;
},
},
series: [{
name: "Project Resource Consumption Percentage",
@@ -418,10 +456,15 @@ const ProgressByClient: React.FC<Props> = () => {
bar: {
horizontal: true,
distributed: true,
dataLabels: {
position: 'top'
},
},
},
dataLabels: {
enabled: false,
enabled: true,
textAnchor: 'end',
formatter: (val) => `${val}%`,
},
xaxis: {
categories: chartProjectName,
@@ -443,6 +486,11 @@ const ProgressByClient: React.FC<Props> = () => {
},
grid: {
borderColor: "#f1f1f1",
xaxis: {
lines: {
show: true,
}
}
},
annotations: {},
};
@@ -517,11 +565,35 @@ const ProgressByClient: React.FC<Props> = () => {
<Card>
<CardHeader className="text-slate-500" title="Project Resource Consumption" />
<div style={{ display: "inline-block", width: "99%" }}>
<div className="ml-6 text-sm">
<b>
Sorting:
</b>
</div>
<div className="ml-6 mb-2">
<button onClick={() => {setTableSorting('PercentageASC')}}
className="hover:cursor-pointer hover:bg-violet-50 text-sm bg-transparent border-violet-500 text-violet-500 border-solid w-36"
>
Percentage ASC
</button>
<button
onClick={() => {setTableSorting('PercentageDESC')}}
className="hover:cursor-pointer hover:bg-violet-50 text-sm bg-transparent border-violet-500 text-violet-500 border-solid w-36"
>
Percentage DESC
</button>
<button
onClick={() => {setTableSorting('ProjectName')}}
className="hover:cursor-pointer hover:bg-violet-50 text-sm bg-transparent border-violet-500 text-violet-500 border-solid w-36"
>
Project Name
</button>
</div>
<ReactApexChart
options={options}
series={options.series}
type="bar"
height={350}
height={500}
/>
</div>
{/* <div style={{display:"inline-block",width:"20%",verticalAlign:"top",textAlign:"center"}}>
@@ -533,6 +605,8 @@ const ProgressByClient: React.FC<Props> = () => {
);
})}
</div> */}
</Card>
<Card className="mt-2">
<CardHeader
className="text-slate-500"
title="Resource Consumption and Coming Milestone"
@@ -561,15 +635,15 @@ const ProgressByClient: React.FC<Props> = () => {
marginLeft: 0,
}}
>
<Grid item xs={12} md={12} lg={12}>
<Card style={{ marginLeft: 15, marginRight: 20 }}>
<Grid item xs={12} md={12} lg={12} style={{height:620}}>
<Card style={{ marginLeft: 15, marginRight: 20, height:"100%"}}>
<CardHeader
className="text-slate-500"
title="Overall Progress per Project"
/>
{percentageArray.length === 0 && (
<div
className="mt-10 mb-10 ml-5 mr-5 text-lg font-medium text-center"
className="mt-40 mb-10 ml-5 mr-5 text-lg font-medium text-center"
style={{ color: "#898d8d" }}
>
Please select the project you want to check.
@@ -580,12 +654,13 @@ const ProgressByClient: React.FC<Props> = () => {
options={options2}
series={percentageArray}
type="donut"
style={{marginTop:'10rem'}}
/>
)}
</Card>
</Grid>
<Grid item xs={12} md={12} lg={12}>
<Card style={{ marginLeft: 15, marginRight: 20, marginTop: 20 }}>
<Card style={{ marginLeft: 15, marginRight: 20, marginTop: 20}}>
<div>
<div
className="mt-5 text-lg font-medium"


+ 96
- 11
src/components/ProgressByTeam/ProgressByTeam.tsx Wyświetl plik

@@ -49,6 +49,9 @@ const ProgressByTeam: React.FC = () => {
const [receiptToDate, setReceiptToDate] = useState(null);
const [selectedRows, setSelectedRows] = 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 color = ["#f57f90", "#94f7d6", "#87c5f5", "#ab95f5", "#fcd68b",
"#f58a9b", "#8ef4d1", "#92caf9", "#a798f9", "#fad287",
@@ -77,16 +80,21 @@ const ProgressByTeam: React.FC = () => {
"#d1fef0", "#04afff", "#ff859e", "#4bdd15", "#ccfb2b"];
const [teamProjectResult, setTeamProjectResult]: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 fetchData = async () => {
console.log(tableSorting)
if (teamLeadId) {
try {
const clickResult = await fetchAllTeamProjects(
Number(teamLeadId))
Number(teamLeadId),tableSorting)
console.log(clickResult)
setTeamProjectResult(clickResult);
} catch (error) {
@@ -97,19 +105,29 @@ const ProgressByTeam: React.FC = () => {

useEffect(() => {
const projectNo = []
const projectName = []
const projectBudgetedManHour = []
const projectSpentManHour = []
const manhourConsumptionPercentage = []
for (let i = 0; i < teamProjectResult.length; i++){
teamProjectResult[i].color = color[i]
projectNo.push(teamProjectResult[i].projectCode)
console.log(teamProjectResult[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)
}
setChartProjectName(projectNo)
setChartProjectDisplayName(projectName)
setChartProjectBudgetedHour(projectBudgetedManHour)
setChartProjectSpentHour(projectSpentManHour)
setChartManhourConsumptionPercentage(manhourConsumptionPercentage)
}, [teamProjectResult]);

useEffect(() => {
fetchData()
}, [teamLeadId]);
}, [teamLeadId,tableSorting]);

const rows = [
{
@@ -462,7 +480,31 @@ const ProgressByTeam: React.FC = () => {
const options: ApexOptions = {
chart: {
type: "bar",
height: 350,
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 = `
<div style="width: 250px;">
<span style="font-weight: bold;">${projectCode} - ${projectName}</span>
<br>
Budget Manhours: ${budgetManhours} hours
<br>
Spent Manhours: ${spentManhours} hours
<br>
Percentage: ${value}%
</div>
`;

return tooltipContent;
},
},
series: [{
name: "Project Resource Consumption Percentage",
@@ -473,10 +515,15 @@ const ProgressByTeam: React.FC = () => {
bar: {
horizontal: true,
distributed: true,
dataLabels: {
position: 'top'
},
},
},
dataLabels: {
enabled: false,
enabled: true,
textAnchor: 'end',
formatter: (val) => `${val}%`,
},
xaxis: {
categories: currentPageProjectList,
@@ -498,6 +545,11 @@ const ProgressByTeam: React.FC = () => {
},
grid: {
borderColor: "#f1f1f1",
xaxis: {
lines: {
show: true,
}
}
},
annotations: {},
};
@@ -564,11 +616,17 @@ const ProgressByTeam: React.FC = () => {
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 = color.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]);
@@ -598,11 +656,35 @@ const ProgressByTeam: React.FC = () => {
<Card>
<CardHeader className="text-slate-500" title="Project Resource Consumption" />
<div style={{ display: "inline-block", width: "99%" }}>
<div className="ml-6 text-sm">
<b>
Sorting:
</b>
</div>
<div className="ml-6 mb-2">
<button onClick={() => {setTableSorting('PercentageASC')}}
className="hover:cursor-pointer hover:bg-violet-50 text-sm bg-transparent border-violet-500 text-violet-500 border-solid w-36"
>
Percentage ASC
</button>
<button
onClick={() => {setTableSorting('PercentageDESC')}}
className="hover:cursor-pointer hover:bg-violet-50 text-sm bg-transparent border-violet-500 text-violet-500 border-solid w-36"
>
Percentage DESC
</button>
<button
onClick={() => {setTableSorting('ProjectName')}}
className="hover:cursor-pointer hover:bg-violet-50 text-sm bg-transparent border-violet-500 text-violet-500 border-solid w-36"
>
Project Name
</button>
</div>
<ReactApexChart
options={options}
series={options.series}
type="bar"
height={350}
height={500}
/>
<div className="float-right mr-4 mb-10">
{currentPage === 1 && (
@@ -646,6 +728,8 @@ const ProgressByTeam: React.FC = () => {
);
})}
</div> */}
</Card>
<Card className="mt-2">
<CardHeader
className="text-slate-500"
title="Resource Consumption and Coming Milestone"
@@ -674,16 +758,16 @@ const ProgressByTeam: React.FC = () => {
marginLeft: 0,
}}
>
<Grid item xs={12} md={12} lg={12}>
<Card style={{ marginLeft: 15, marginRight: 20 }}>
<Grid item xs={12} md={12} lg={12} style={{height:710}}>
<Card style={{ marginLeft: 15, marginRight: 20, height:"100%"}}>
<CardHeader
className="text-slate-500"
title="Overall Progress per Project"
/>
{percentageArray.length === 0 && (
<div
className="mt-10 mb-10 ml-5 mr-5 text-lg font-medium text-center"
style={{ color: "#898d8d" }}
className="mt-40 mb-10 ml-5 mr-5 text-lg font-medium text-center"
style={{ color: "#898d8d"}}
>
Please select the project you want to check.
</div>
@@ -693,12 +777,13 @@ const ProgressByTeam: React.FC = () => {
options={options2}
series={percentageArray}
type="donut"
style={{marginTop:'10rem'}}
/>
)}
</Card>
</Grid>
<Grid item xs={12} md={12} lg={12}>
<Card style={{ marginLeft: 15, marginRight: 20, marginTop: 20 }}>
<Card style={{ marginLeft: 15, marginRight: 20, marginTop: 15 }}>
<div>
<div
className="mt-5 text-lg font-medium"


+ 38
- 8
src/components/ProjectCashFlow/ProjectCashFlow.tsx Wyświetl plik

@@ -23,6 +23,7 @@ import { fetchProjectsCashFlow,fetchProjectsCashFlowMonthlyChart,fetchProjectsCa
import { Input, Label } from "reactstrap";
import { CashFlow } from "@/app/api/cashflow";
import dayjs from 'dayjs';
import ProjectTotalFee from "../CreateInvoice_forGen/ProjectTotalFee";

interface Props {
projects: CashFlow[];
@@ -45,6 +46,8 @@ const ProjectCashFlow: React.FC = () => {
const [monthlyChartRightMax, setMonthlyChartRightMax]: any[] = React.useState(10);
const [monthlyAnticipateLeftMax, setMonthlyAnticipateLeftMax]: any[] = React.useState(10);
const [receivedPercentage,setReceivedPercentage]: any[] = React.useState(0);
const [invoicedPercentage,setInvoicedPercentage]: any[] = React.useState(0);
const [totalFee,setTotalFee]: any[] = React.useState(0);
const [totalBudget,setTotalBudget]: any[] = React.useState(0);
const [totalInvoiced,setTotalInvoiced]: any[] = React.useState(0);
const [totalReceived,setTotalReceived]: any[] = React.useState(0);
@@ -121,6 +124,8 @@ const ProjectCashFlow: React.FC = () => {
const cashFlowReceivableAndExpenditureData = await fetchProjectsCashFlowReceivableAndExpenditure(selectedProjectIdList);
if(cashFlowReceivableAndExpenditureData.length !== 0){
setReceivedPercentage(cashFlowReceivableAndExpenditureData[0].receivedPercentage)
setInvoicedPercentage(cashFlowReceivableAndExpenditureData[0].invoicedPercentage)
setTotalFee(cashFlowReceivableAndExpenditureData[0].totalProjectFee)
setTotalInvoiced(cashFlowReceivableAndExpenditureData[0].totalInvoiced)
setTotalReceived(cashFlowReceivableAndExpenditureData[0].totalReceived)
setReceivable(cashFlowReceivableAndExpenditureData[0].receivable)
@@ -511,9 +516,9 @@ const ProjectCashFlow: React.FC = () => {

const accountsReceivableOptions: ApexOptions = {
colors: ["#20E647"],
series: [receivedPercentage],
series: [receivedPercentage,invoicedPercentage],
chart: {
height: 350,
height: 50,
type: "radialBar",
},
plotOptions: {
@@ -533,13 +538,23 @@ const ProjectCashFlow: React.FC = () => {
},
dataLabels: {
name: {
show: false,
show: true,
fontSize: "0.9em",
},
value: {
color: "#3e98c7",
fontSize: "3em",
fontSize: "1.5em",
show: true,
},
total: {
show: true,
color: "#20E647",
fontSize: "0.9em",
label: 'Receivable / Invoiced',
formatter: function (w:any) {
return receivedPercentage + "% / " + invoicedPercentage + "%"
},
}
},
},
},
@@ -555,7 +570,7 @@ const ProjectCashFlow: React.FC = () => {
stroke: {
lineCap: "round",
},
labels: ["AccountsReceivable"],
labels: ["Accounts Receivable","Account Invoiced"],
};

const expenditureOptions: ApexOptions = {
@@ -582,11 +597,12 @@ const ProjectCashFlow: React.FC = () => {
},
dataLabels: {
name: {
show: false,
show: true,
fontSize: "0.9em",
},
value: {
color: "#3e98c7",
fontSize: "3em",
fontSize: "1.5em",
show: true,
},
},
@@ -604,7 +620,7 @@ const ProjectCashFlow: React.FC = () => {
stroke: {
lineCap: "round",
},
labels: ["AccountsReceivable"],
labels: ["Accounts Expenditure"],
};

const rows = [
@@ -812,12 +828,26 @@ const ProjectCashFlow: React.FC = () => {
className="text-slate-500"
title="Accounts Receivable (HKD)"
/>
<div style={{ display: "inline-block", width: "99%" }}>
<ReactApexChart
options={accountsReceivableOptions}
series={accountsReceivableOptions.series}
type="radialBar"
/>
</div>
<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 Project Fee
</div>
<div
className="text-lg font-medium ml-5"
style={{ color: "#6b87cf" }}
>
${totalFee.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<div
className="text-sm font-medium ml-5 mt-2"
style={{ color: "#898d8d" }}


+ 64
- 0
src/components/ProjectFinancialSummary/ProjectFinancialCard.tsx Wyświetl plik

@@ -25,10 +25,13 @@ interface Props {
TotalBudget: number;
TotalCumulative: number;
TotalInvoicedAmount: number;
TotalUnInvoicedAmount: number;
TotalReceivedAmount: number;
CashFlowStatus: string;
CostPerformanceIndex: number;
ClickedIndex: number;
ProjectedCPI: number;
ProjectedCashFlowStatus: string;
Index: number;
}

@@ -39,10 +42,13 @@ const ProjectFinancialCard: React.FC<Props> = ({
TotalBudget,
TotalCumulative,
TotalInvoicedAmount,
TotalUnInvoicedAmount,
TotalReceivedAmount,
CashFlowStatus,
CostPerformanceIndex,
ClickedIndex,
ProjectedCPI,
ProjectedCashFlowStatus,
Index,
}) => {
const [SearchCriteria, setSearchCriteria] = React.useState({});
@@ -106,6 +112,13 @@ const ProjectFinancialCard: React.FC<Props> = ({
{TotalInvoicedAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<hr />
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
Total Un-Invoiced Amount
</div>
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}>
{TotalUnInvoicedAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<hr />
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
Total Received Amount
</div>
@@ -164,6 +177,57 @@ const ProjectFinancialCard: React.FC<Props> = ({
</div>
</>
)}
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
Projected Cash Flow Status
</div>
{ProjectedCashFlowStatus === "Negative" && (
<>
<div
className="text-lg font-medium ml-5"
style={{ color: "#f896aa" }}
>
{ProjectedCashFlowStatus}
</div>
<hr />
</>
)}
{ProjectedCashFlowStatus === "Positive" && (
<>
<div
className="text-lg font-medium ml-5"
style={{ color: "#71d19e" }}
>
{CashFlowStatus}
</div>
<hr />
</>
)}
<div
className="text-sm mt-2 font-medium ml-5"
style={{ color: "#898d8d" }}
>
Projected Cost Performance Index (CPI)
</div>
{Number(ProjectedCPI) < 1 && (
<>
<div
className="text-lg font-medium ml-5 mb-2"
style={{ color: "#f896aa" }}
>
{ProjectedCPI}
</div>
</>
)}
{Number(ProjectedCPI) >= 1 && (
<>
<div
className="text-lg font-medium ml-5 mb-2"
style={{ color: "#71d19e" }}
>
{ProjectedCPI}
</div>
</>
)}
</Card>
);
};


+ 140
- 73
src/components/ProjectFinancialSummary/ProjectFinancialSummary.tsx Wyświetl plik

@@ -133,6 +133,40 @@ const ProjectFinancialSummary: React.FC = () => {
}
},
},
{
id: 'projectedCashFlowStatus',
field: 'projectedCashFlowStatus',
headerName: "Projected Cash Flow Status",
minWidth:100,
renderCell: (params:any) => {
if (params.row.projectedCashFlowStatus === "Positive") {
return (
<span className="text-lime-500">{params.row.projectedCashFlowStatus}</span>
)
} else if (params.row.projectedCashFlowStatus === "Negative") {
return (
<span className="text-red-500">{params.row.projectedCashFlowStatus}</span>
)
}
},
},
{
id: 'projectedCpi',
field: 'projectedCpi',
headerName: "Projected CPI",
minWidth:50,
renderCell: (params:any) => {
if (params.row.projectedCpi >= 1) {
return (
<span className="text-lime-500">{params.row.projectedCpi}</span>
)
} else if (params.row.projectedCpi < 1) {
return (
<span className="text-red-500">{params.row.projectedCpi}</span>
)
}
},
},
{
id: 'totalFee',
field: 'totalFee',
@@ -292,86 +326,119 @@ const columns2 = [
}
},
},
{
id: "cpi",
field: "cpi",
headerName: "CPI",
minWidth:50,
renderCell: (params: any) => {
if (params.row.cpi >= 1) {
return <span className="text-lime-500">{params.row.cpi}</span>;
} else if (params.row.cpi < 1) {
return <span className="text-red-500">{params.row.cpi}</span>;
}
},
{
id: "cpi",
field: "cpi",
headerName: "CPI",
minWidth:50,
renderCell: (params: any) => {
if (params.row.cpi >= 1) {
return <span className="text-lime-500">{params.row.cpi}</span>;
} else if (params.row.cpi < 1) {
return <span className="text-red-500">{params.row.cpi}</span>;
}
},

{
id: 'totalFees',
field: 'totalFees',
headerName: "Total Fees (HKD)",
minWidth:50,
renderCell: (params:any) => {
},
{
id: 'projectedCashFlowStatus',
field: 'projectedCashFlowStatus',
headerName: "Projected Cash Flow Status",
minWidth:100,
renderCell: (params:any) => {
if (params.row.projectedCashFlowStatus === "Positive") {
return (
<span className="text-lime-500">{params.row.projectedCashFlowStatus}</span>
)
} else if (params.row.projectedCashFlowStatus === "Negative") {
return (
<span className="text-red-500">{params.row.projectedCashFlowStatus}</span>
)
}
},
},
{
id: 'projectedCpi',
field: 'projectedCpi',
headerName: "Projected CPI",
minWidth:50,
renderCell: (params:any) => {
if (params.row.projectedCpi >= 1) {
return (
<span className="text-lime-500">{params.row.projectedCpi}</span>
)
} else if (params.row.projectedCpi < 1) {
return (
<span className="text-red-500">{params.row.projectedCpi}</span>
)
}
},
},
{
id: 'totalFees',
field: 'totalFees',
headerName: "Total Fees (HKD)",
minWidth:50,
renderCell: (params:any) => {
return (
<span>${params.row.totalFee.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
)
},
},
{
id: 'totalBudget',
field: 'totalBudget',
headerName: "Total Budget (HKD)",
minWidth:50,
renderCell: (params:any) => {
return (
<span>${params.row.totalFee.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
<span>${params.row.totalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
)
},
},
{
id: 'totalBudget',
field: 'totalBudget',
headerName: "Total Budget (HKD)",
minWidth:50,
renderCell: (params:any) => {
return (
<span>${params.row.totalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
)
},
},
{
id: 'totalCumulativeExpenditure',
field: 'totalCumulativeExpenditure',
headerName: "Total Cumulative Expenditure (HKD)",
minWidth:250,
renderCell: (params:any) => {
return (
<span>${params.row.cumulativeExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
)
},
},
{
id: 'totalInvoicedAmount',
field: 'totalInvoicedAmount',
headerName: "Total Invoiced Amount (HKD)",
minWidth:250,
renderCell: (params:any) => {
return (
<span>${params.row.totalInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
)
{
id: 'totalCumulativeExpenditure',
field: 'totalCumulativeExpenditure',
headerName: "Total Cumulative Expenditure (HKD)",
minWidth:250,
renderCell: (params:any) => {
return (
<span>${params.row.cumulativeExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
)
},
},
},
{
id: 'totalUnInvoicedAmount',
field: 'totalUnInvoicedAmount',
headerName: "Total Un-invoiced Amount (HKD)",
minWidth:250,
renderCell: (params:any) => {
return (
<span>${params.row.totalUninvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
)
{
id: 'totalInvoicedAmount',
field: 'totalInvoicedAmount',
headerName: "Total Invoiced Amount (HKD)",
minWidth:250,
renderCell: (params:any) => {
return (
<span>${params.row.totalInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
)
},
},
{
id: 'totalUnInvoicedAmount',
field: 'totalUnInvoicedAmount',
headerName: "Total Un-invoiced Amount (HKD)",
minWidth:250,
renderCell: (params:any) => {
return (
<span>${params.row.totalUninvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
)
},
},
},
{
id: 'totalReceivedAmount',
field: 'totalReceivedAmount',
headerName: "Total Received Amount (HKD)",
minWidth:250,
renderCell: (params:any) => {
return (
<span>${params.row.totalReceived.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
)
{
id: 'totalReceivedAmount',
field: 'totalReceivedAmount',
headerName: "Total Received Amount (HKD)",
minWidth:250,
renderCell: (params:any) => {
return (
<span>${params.row.totalReceived.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
)
},
},
},
];

const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => {
@@ -398,7 +465,7 @@ const columns2 = [
<div className="ml-10 mr-10" style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'start'}}>
{projectFinancialData.map((record:any, index:any) => (
<div className="hover:cursor-pointer ml-4 mt-5 mb-4 inline-block" key={index} onClick={(r) => handleCardClick(record,index)}>
<ProjectFinancialCard Title={record.teamName} TotalActiveProjectNumber={record.projectNo} TotalFees={record.totalFee} TotalBudget={record.totalBudget} TotalCumulative={record.cumulativeExpenditure ?? 0} TotalInvoicedAmount={record.totalInvoiced ?? 0} TotalReceivedAmount={record.totalReceived ?? 0} CashFlowStatus={record.cashFlowStatus ?? "Negative"} CostPerformanceIndex={record.cpi ?? 0} ClickedIndex={isCardClickedIndex} Index={index}/>
<ProjectFinancialCard Title={record.teamName} TotalActiveProjectNumber={record.projectNo} TotalFees={record.totalFee} TotalBudget={record.totalBudget} TotalCumulative={record.cumulativeExpenditure ?? 0} TotalInvoicedAmount={record.totalInvoiced ?? 0} TotalUnInvoicedAmount={record.unInvoiced ?? 0} TotalReceivedAmount={record.totalReceived ?? 0} CashFlowStatus={record.cashFlowStatus ?? "Negative"} CostPerformanceIndex={record.cpi ?? 0} ProjectedCashFlowStatus={record.projectedCashFlowStatus ?? "Negative"} ProjectedCPI={record.projectedCpi ?? 0} ClickedIndex={isCardClickedIndex} Index={index}/>
</div>
))}
</div>


+ 923
- 0
src/components/ProjectResourceConsumptionRanking/ProjectResourceConsumptionRanking.tsx Wyświetl plik

@@ -0,0 +1,923 @@
"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, fetchTeamProjects, fetchAllTeamConsumption} from "@/app/api/teamprojects/actions";
// const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false });

interface Props {
projects: TeamProjectResult[];
}
type SearchQuery = Partial<Omit<TeamProjectResult, "id">>;
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 [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 [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 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 [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)
console.log(clickResult)
setTeamProjectResult(clickResult);
} catch (error) {
console.error('Error fetching team consumption:', error);
}
}
}

const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
() => [
{ label: "Team Code", paramName: "teamCode", type: "text" },
{ label: "Team Name", paramName: "teamName", type: "text" },
],
[t],
);

useEffect(() => {
const projectNo = []
const projectName = []
const projectBudgetedManHour = []
const projectSpentManHour = []
const manhourConsumptionPercentage = []
for (let i = 0; i < teamProjectResult.length; i++){
teamProjectResult[i].color = color[i]
console.log(teamProjectResult[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)
}
setChartProjectName(projectNo)
setChartProjectDisplayName(projectName)
setChartProjectBudgetedHour(projectBudgetedManHour)
setChartProjectSpentHour(projectSpentManHour)
setChartManhourConsumptionPercentage(manhourConsumptionPercentage)
}, [teamProjectResult]);

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: "Team Code",
flex: 1,
},
{
id: "teamName",
field: "teamName",
headerName: "Team Name",
flex: 1,
},
{
id: "projectNo",
field: "projectNo",
headerName: "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 (
<span
className="dot"
style={{
height: "15px",
width: "15px",
borderRadius: "50%",
backgroundColor: `${params.row.color}`,
display: "inline-block",
}}
></span>
);
},
flex: 0.1,
},
{
id: "projectCode",
field: "projectCode",
headerName: "Project No",
minWidth:100
},
{
id: "projectName",
field: "projectName",
headerName: "Project",
minWidth:300
},
{
id: "team",
field: "team",
headerName: "Team",
minWidth:50
},
{
id: "teamLead",
field: "teamLead",
headerName: "Team Leader",
minWidth: 70
},
{
id: "expectedStage",
field: "expectedStage",
headerName: "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) => (
<React.Fragment key={index}>
{line.trim()}
<br />
</React.Fragment>
));
return <div>{lines}</div>;
} else {
return <div>-</div>;
}
},
},
{
id: "budgetedManhour",
field: "budgetedManhour",
headerName: "Budgeted Manhour",
minWidth: 70,
renderCell: (params: any) => {
return <span>{params.row.budgetedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>;
}
},
{
id: "spentManhour",
field: "spentManhour",
headerName: "Spent Manhour",
renderCell: (params: any) => {
if (params.row.budgetedManhour - params.row.spentManhour <= 0) {
return (
<span className="text-red-300">{params.row.spentManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
);
} else {
return <span>{params.row.spentManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>;
}
},
minWidth: 70
},
{
id: "remainedManhour",
field: "remainedManhour",
headerName: "Remained Manhour",
renderCell: (params: any) => {
if (params.row.budgetedManhour - params.row.spentManhour <= 0) {
return (
<span className="text-red-300">({params.row.remainedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })})</span>
);
} else {
return <span>{params.row.remainedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>;
}
},
minWidth: 70
},
{
id: "comingPaymentMilestone",
field: "comingPaymentMilestone",
headerName: "Coming Payment Milestone",
minWidth: 100
},
{
id: "alert",
field: "alert",
headerName: "Alert",
renderCell: (params: any) => {
if (params.row.alert === true) {
return (
<span className="text-red-300 text-center">
<ReportProblemIcon />
</span>
);
} else {
return <span></span>;
}
},
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: "Spent",
fontFamily: "sans-serif",
formatter: function (val) {
return totalSpentPercentage + "%";
},
},
},
},
},
},
labels: projectArray,
legend: {
show: false,
},
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 = `
<div style="width: 250px;">
<span style="font-weight: bold;">${projectCode} - ${projectName}</span>
<br>
Budget Manhours: ${budgetManhours} hours
<br>
Spent Manhours: ${spentManhours} hours
<br>
Percentage: ${value}%
</div>
`;

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: "Projects",
},
labels: {
maxWidth: 200,
style: {
cssClass: "apexcharts-yaxis-label",
},
},
},
title: {
text: "Project Resource Consumption Percentage",
align: "center",
},
grid: {
borderColor: "#f1f1f1",
xaxis: {
lines: {
show: true,
}
}
},
annotations: {},
};

const handleSearchSelectionChange = (newSelectionModel: GridRowSelectionModel) => {
const selectedRowsData = projectData.filter((row: any) =>
newSelectionModel.includes(row.id),
);
const teamIdList = []
for (var i=0; i<selectedRowsData.length; i++){
teamIdList.push(selectedRowsData[i].id)
}
setSelectedTeamIdList(teamIdList)
};

const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => {
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("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("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 = color.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 (
<>
<SearchBox
criteria={searchCriteria}
onSearch={(query) => {
setFilteredResult(
projectData.filter(
(cp:any) =>
cp.teamCode.toLowerCase().includes(query.teamCode.toLowerCase()) &&
cp.teamName.toLowerCase().includes(query.teamName.toLowerCase())
),
);
}}
/>
<CustomDatagrid
rows={filteredResult}
columns={searchColumns}
columnWidth={200}
dataGridHeight={300}
checkboxSelection={true}
onRowSelectionModelChange={handleSearchSelectionChange}
selectionModel={selectionModel}
/>
<Grid item sm>
<div style={{ display: "inline-block", width: "70%" }}>
<Grid item xs={12} md={12} lg={12}>
<Card>
<CardHeader className="text-slate-500" title="Project Resource Consumption" />
<div style={{ display: "inline-block", width: "99%" }}>
<div className="ml-6 text-sm">
<b>
Sorting:
</b>
</div>
<div className="ml-6 mb-2">
<button onClick={() => {setTableSorting('PercentageASC')}}
className="hover:cursor-pointer hover:bg-violet-50 text-sm bg-transparent border-violet-500 text-violet-500 border-solid w-36"
>
Percentage ASC
</button>
<button
onClick={() => {setTableSorting('PercentageDESC')}}
className="hover:cursor-pointer hover:bg-violet-50 text-sm bg-transparent border-violet-500 text-violet-500 border-solid w-36"
>
Percentage DESC
</button>
<button
onClick={() => {setTableSorting('ProjectName')}}
className="hover:cursor-pointer hover:bg-violet-50 text-sm bg-transparent border-violet-500 text-violet-500 border-solid w-36"
>
Project Name
</button>
</div>
<ReactApexChart
options={options}
series={options.series}
type="bar"
height={500}
/>
<div className="float-right mr-4 mb-10">
{currentPage === 1 && (
<button className="bg-blue-500 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-l">
Pervious
</button>
)}
{currentPage !== 1 && (
<button onClick={handlePrevPage} className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 outline-none rounded-l">
Previous
</button>
)}
{endIndex >= chartManhourConsumptionPercentage.length && (
<button className="bg-blue-500 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-r mr-2">
Next
</button>
)}
{endIndex < chartManhourConsumptionPercentage.length && (
<button onClick={handleNextPage} className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 outline-none rounded-r mr-2">
Next
</button>
)}
Page&nbsp;
{chartManhourConsumptionPercentage.length === 0 && (
0
)}
{chartManhourConsumptionPercentage.length > 0 && (
currentPage
)}
&nbsp;of&nbsp;
{Math.ceil(chartManhourConsumptionPercentage.length / recordsPerPage)}
</div>
</div>
</Card>
<Card className="mt-2">
<CardHeader
className="text-slate-500"
title="Resource Consumption and Coming Milestone"
/>
<div
style={{ display: "inline-block", width: "99%", marginLeft: 10 }}
>
<CustomDatagrid
rows={teamProjectResult}
columns={columns2}
columnWidth={200}
dataGridHeight={300}
checkboxSelection={true}
onRowSelectionModelChange={handleSelectionChange}
selectionModel={selectionModel}
/>
</div>
</Card>
</Grid>
</div>
<div
style={{
display: "inline-block",
width: "30%",
verticalAlign: "top",
marginLeft: 0,
}}
>
<Grid item xs={12} md={12} lg={12} style={{height:710}}>
<Card style={{ marginLeft: 15, marginRight: 20, height:"100%"}}>
<CardHeader
className="text-slate-500"
title="Overall Progress per Project"
/>
{percentageArray.length === 0 && (
<div
className="mt-40 mb-10 ml-5 mr-5 text-lg font-medium text-center"
style={{ color: "#898d8d"}}
>
Please select the project you want to check.
</div>
)}
{percentageArray.length > 0 && (
<ReactApexChart
options={options2}
series={percentageArray}
type="donut"
style={{marginTop:'10rem'}}
/>
)}
</Card>
</Grid>
<Grid item xs={12} md={12} lg={12}>
<Card style={{ marginLeft: 15, marginRight: 20, marginTop: 15 }}>
<div>
<div
className="mt-5 text-lg font-medium"
style={{ color: "#898d8d" }}
>
<span style={{ marginLeft: "5%" }}>Project Budget Manhour</span>
</div>
<div
className="mt-2 text-2xl font-extrabold"
style={{ color: "#6b87cf" }}
>
<span style={{ marginLeft: "5%" }}>{projectBudgetManhour}</span>
</div>
</div>
<hr />
<div>
<div
className="mt-2 text-lg font-medium"
style={{ color: "#898d8d" }}
>
<span style={{ marginLeft: "5%" }}>Actual Manhour Spent</span>
</div>
<div
className="mt-2 text-2xl font-extrabold"
style={{ color: "#6b87cf" }}
>
<span style={{ marginLeft: "5%" }}>{actualManhourSpent}</span>
</div>
</div>
<hr />
<div>
<div
className="mt-2 text-lg font-medium"
style={{ color: "#898d8d" }}
>
<span style={{ marginLeft: "5%" }}>Remained Manhour</span>
</div>
<div
className="mt-2 text-2xl font-extrabold"
style={{ color: "#6b87cf" }}
>
<span style={{ marginLeft: "5%" }}>{remainedManhour}</span>
</div>
</div>
<hr />
<div>
<div
className="mt-2 text-lg font-medium"
style={{ color: "#898d8d" }}
>
<span style={{ marginLeft: "5%" }}>Last Update</span>
</div>
<div
className="mt-2 mb-5 text-2xl font-extrabold"
style={{ color: "#6b87cf" }}
>
<span style={{ marginLeft: "5%" }}>{lastUpdate}</span>
</div>
</div>
</Card>
</Grid>
</div>
</Grid>
</>
);
};

export default ProjectResourceConsumptionRanking;

+ 1
- 0
src/components/ProjectResourceConsumptionRanking/index.ts Wyświetl plik

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

+ 90
- 49
src/components/ProjectResourceSummary/ProjectResourceSummary.tsx Wyświetl plik

@@ -33,6 +33,7 @@ import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import { useSearchParams } from 'next/navigation';
import {fetchResourceSummaryDetailResult} from "@/app/api/resourcesummary/actions";
import { set } from "lodash";


const ProjectResourceSummary: React.FC = () => {
@@ -43,6 +44,9 @@ const ProjectResourceSummary: React.FC = () => {
const [selectionModel, setSelectionModel]: any[] = React.useState([]);
const [projectName, setProjectName]:any = React.useState("NA");
const [projectFee, setProjectFee]:any = React.useState(0);
const [projectBudget, setProjectBudget]:any = React.useState(0);
const [expenditure, setExpenditure]:any = React.useState(0);
const [remainingBudget, setRemainingBudget]:any = React.useState(0);
const [status, setStatus]:any = React.useState("NA");
const [plannedResources, setPlannedResources]:any = React.useState(0);
const [actualResourcesSpent, setActualResourcesSpent]:any = React.useState(0);
@@ -94,6 +98,9 @@ const ProjectResourceSummary: React.FC = () => {
const result = await fetchResourceSummaryDetailResult(intProjectId);
setProjectName(result[0].summaryInformation[0].projectCodeAndName)
setProjectFee(result[0].summaryInformation[0].totalFee)
setProjectBudget(result[0].summaryInformation[0].totalBudget)
setExpenditure(result[0].summaryInformation[0].expenditure)
setRemainingBudget(result[0].summaryInformation[0].remainingBudget)
setStatus(result[0].summaryInformation[0].status)
setPlannedResources(result[0].summaryInformation[0].plannedResources)
setActualResourcesSpent(result[0].summaryInformation[0].resourcesSpent)
@@ -233,8 +240,8 @@ const ProjectResourceSummary: React.FC = () => {
return (
<React.Fragment>
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
<TableCell>
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }} className="border-t-2 border-b-0 border-l-0 border-r-0 border-solid border-slate-300">
<TableCell >
{row.task.length > 0 && (
<IconButton
aria-label="expand row"
@@ -247,21 +254,21 @@ const ProjectResourceSummary: React.FC = () => {
</TableCell>
<TableCell style={{fontSize:13}}>{row.stage}</TableCell>
<TableCell style={{fontSize:13}}>{row.taskCount}</TableCell>
<TableCell style={{fontSize:13}}>{row.g1Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13}}>{row.g1Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13}}>{row.g2Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13}}>{row.g2Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13}}>{row.g3Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13}}>{row.g3Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13}}>{row.g4Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13}}>{row.g4Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13}}>{row.g5Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13}}>{row.g5Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13}}>{row.totalPlanned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13}}>{row.totalActual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g1Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g1Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g2Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g2Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g3Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g3Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g4Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g4Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g5Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g5Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.totalPlanned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.totalActual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
</TableRow>
{row.task.map((taskRow:any) => (
<TableRow key={taskRow[0]} style={{backgroundColor:"#f0f3f7"}}>
<TableRow key={taskRow[0]} style={{backgroundColor:"#f0f3f7"}} className="border-t-2 border-b-0 border-l-0 border-r-0 border-solid border-slate-300">
<TableCell style={{ paddingBottom: 0, paddingTop: 0}} colSpan={1}>
<Collapse in={open} timeout="auto" unmountOnExit style={{marginLeft:-17, marginRight:-17}}>
<Box sx={{ margin: 0 }}>
@@ -307,7 +314,7 @@ const ProjectResourceSummary: React.FC = () => {
<Table size="small" aria-label="tasks">
<TableBody>
<TableRow>
<TableCell style={{fontSize:13}} colSpan={1}>{taskRow[4].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{taskRow[4].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
</TableRow>
</TableBody>
</Table>
@@ -320,7 +327,7 @@ const ProjectResourceSummary: React.FC = () => {
<Table size="small" aria-label="tasks">
<TableBody>
<TableRow>
<TableCell style={{fontSize:13}} colSpan={1}>{taskRow[5].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{taskRow[5].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
</TableRow>
</TableBody>
</Table>
@@ -333,7 +340,7 @@ const ProjectResourceSummary: React.FC = () => {
<Table size="small" aria-label="tasks">
<TableBody>
<TableRow>
<TableCell style={{fontSize:13}} colSpan={1}>{taskRow[6].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{taskRow[6].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
</TableRow>
</TableBody>
</Table>
@@ -346,7 +353,7 @@ const ProjectResourceSummary: React.FC = () => {
<Table size="small" aria-label="tasks">
<TableBody>
<TableRow>
<TableCell style={{fontSize:13}} colSpan={1}>{taskRow[7].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{taskRow[7].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
</TableRow>
</TableBody>
</Table>
@@ -359,7 +366,7 @@ const ProjectResourceSummary: React.FC = () => {
<Table size="small" aria-label="tasks">
<TableBody>
<TableRow>
<TableCell style={{fontSize:13}} colSpan={1}>{taskRow[8].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{taskRow[8].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
</TableRow>
</TableBody>
</Table>
@@ -372,7 +379,7 @@ const ProjectResourceSummary: React.FC = () => {
<Table size="small" aria-label="tasks">
<TableBody>
<TableRow>
<TableCell style={{fontSize:13}} colSpan={1}>{taskRow[9].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{taskRow[9].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
</TableRow>
</TableBody>
</Table>
@@ -385,7 +392,7 @@ const ProjectResourceSummary: React.FC = () => {
<Table size="small" aria-label="tasks">
<TableBody>
<TableRow>
<TableCell style={{fontSize:13}} colSpan={1}>{taskRow[10].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{taskRow[10].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
</TableRow>
</TableBody>
</Table>
@@ -398,7 +405,7 @@ const ProjectResourceSummary: React.FC = () => {
<Table size="small" aria-label="tasks">
<TableBody>
<TableRow>
<TableCell style={{fontSize:13}} colSpan={1}>{taskRow[11].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{taskRow[11].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
</TableRow>
</TableBody>
</Table>
@@ -411,7 +418,7 @@ const ProjectResourceSummary: React.FC = () => {
<Table size="small" aria-label="tasks">
<TableBody>
<TableRow>
<TableCell style={{fontSize:13}} colSpan={1}>{taskRow[12].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{taskRow[12].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
</TableRow>
</TableBody>
</Table>
@@ -424,7 +431,7 @@ const ProjectResourceSummary: React.FC = () => {
<Table size="small" aria-label="tasks">
<TableBody>
<TableRow>
<TableCell style={{fontSize:13}} colSpan={1}>{taskRow[13].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{taskRow[13].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
</TableRow>
</TableBody>
</Table>
@@ -437,7 +444,7 @@ const ProjectResourceSummary: React.FC = () => {
<Table size="small" aria-label="tasks">
<TableBody>
<TableRow>
<TableCell style={{fontSize:13}} colSpan={1}>{taskRow[2].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{taskRow[2].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
</TableRow>
</TableBody>
</Table>
@@ -450,7 +457,7 @@ const ProjectResourceSummary: React.FC = () => {
<Table size="small" aria-label="tasks">
<TableBody>
<TableRow>
<TableCell style={{fontSize:13}} colSpan={1}>{taskRow[3].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{taskRow[3].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell>
</TableRow>
</TableBody>
</Table>
@@ -497,6 +504,9 @@ const columns2 = [
field: 'g1Planned',
headerName: "Planned",
flex: 0.7,
renderCell: (params: any) => {
return <span style={{color:'red'}}>{params.row.g1Planned}</span>;
},
},
{
id: 'g1Actual',
@@ -631,6 +641,36 @@ const columns2 = [
HKD ${projectFee.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
</div>
<div style={{ display: "inline-block", width: "33%"}}>
<div style={{ fontSize:"1em", fontWeight:"bold"}}>
<u>
Total Budget
</u>
</div>
<div style={{fontSize:"1em"}}>
HKD ${projectBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
</div>
<div style={{ display: "inline-block", width: "33%"}}>
<div style={{ fontSize:"1em", fontWeight:"bold"}}>
<u>
Cumculative Expenditure
</u>
</div>
<div style={{fontSize:"1em"}}>
HKD ${expenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
</div>
<div style={{ display: "inline-block", width: "33%"}}>
<div style={{ fontSize:"1em", fontWeight:"bold"}}>
<u>
Remaining Budget
</u>
</div>
<div style={{fontSize:"1em"}}>
HKD ${remainingBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
</div>
<div style={{ display: "inline-block", width: "33%"}}>
<div style={{ fontSize:"1em", fontWeight:"bold"}}>
<u>
@@ -658,7 +698,7 @@ const columns2 = [
</u>
</div>
<div style={{fontSize:"1em"}}>
{(actualResourcesSpent ?? 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} Manhours
{(actualResourcesSpent ?? 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} Manhours ({(actualResourcesSpent/plannedResources*100).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}%)
</div>
</div>
<div style={{ display: "inline-block", width: "33%"}}>
@@ -668,7 +708,7 @@ const columns2 = [
</u>
</div>
<div style={{fontSize:"1em"}}>
{(remainingResources ?? 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} Manhours
{(remainingResources ?? 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} Manhours ({(remainingResources/plannedResources*100).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}%)
</div>
</div>
</div>
@@ -676,8 +716,11 @@ const columns2 = [
<CustomDatagrid rows={projectResourcesRows} columns={columns2} columnWidth={200} dataGridHeight={480} pageSize={100} columnGroupingModel={columnGroupingModel} sx={{fontSize:13}}/>
</div> */}
{/* <div style={{display:"inline-block",width:"99%",marginLeft:10, marginRight:10, marginTop:10}}> */}
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650, maxWidth:1080}} aria-label="simple table">
{/* </div> */}
</Card>
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650, maxWidth:1920}} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell align="center" colSpan={3}>
@@ -702,22 +745,22 @@ const columns2 = [
Total
</TableCell>
</TableRow>
<TableRow>
<TableCell style={{width:"5%"}}/>
<TableCell style={{fontSize:13, minWidth:300}}>Stage</TableCell>
<TableCell style={{fontSize:13, width:"5%"}}>Task Count</TableCell>
<TableCell style={{fontSize:13, width:"5%"}}>Planned</TableCell>
<TableCell style={{fontSize:13, width:"5%"}}>Actual</TableCell>
<TableCell style={{fontSize:13, width:"5%"}}>Planned</TableCell>
<TableCell style={{fontSize:13, width:"5%"}}>Actual</TableCell>
<TableCell style={{fontSize:13, width:"5%"}}>Planned</TableCell>
<TableCell style={{fontSize:13, width:"5%"}}>Actual</TableCell>
<TableCell style={{fontSize:13, width:"5%"}}>Planned</TableCell>
<TableCell style={{fontSize:13, width:"5%"}}>Actual</TableCell>
<TableCell style={{fontSize:13, width:"5%"}}>Planned</TableCell>
<TableCell style={{fontSize:13, width:"5%"}}>Actual</TableCell>
<TableCell style={{fontSize:13, width:"5%"}}>Planned</TableCell>
<TableCell style={{fontSize:13, width:"5%"}}>Actual</TableCell>
<TableRow className="border-t-2 border-b-0 border-l-0 border-r-0 border-solid border-slate-300">
<TableCell style={{minWidth:30}}/>
<TableCell style={{fontSize:11, minWidth:150}}>Stage</TableCell>
<TableCell style={{fontSize:11, minWidth:30}}>Task Count</TableCell>
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>Planned</TableCell>
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>Actual</TableCell>
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>Planned</TableCell>
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>Actual</TableCell>
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>Planned</TableCell>
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>Actual</TableCell>
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>Planned</TableCell>
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>Actual</TableCell>
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>Planned</TableCell>
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>Actual</TableCell>
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>Planned</TableCell>
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>Actual</TableCell>
</TableRow>
</TableHead>
<TableBody>
@@ -727,8 +770,6 @@ const columns2 = [
</TableBody>
</Table>
</TableContainer>
{/* </div> */}
</Card>
</Grid>
);
};


+ 80
- 19
src/components/StaffUtilization/StaffUtilization.tsx Wyświetl plik

@@ -34,6 +34,7 @@ import moment from "moment";
import { fetchTeamCombo, fetchweeklyTeamTotalManhours, fetchmonthlyTeamTotalManhours, fetchTotalManhoursByGrade, fetchWeeklyUnsubmit, fetchMonthlyUnsubmit, fetchStaffCombo, fetchDailyIndividualStaffManhours, fetchWeeklyIndividualStaffManhours, fetchMonthlyIndividualStaffManhours } from "@/app/api/staffUtilization";
import { SessionStaff } from "@/config/authConfig";
import { VIEW_DASHBOARD_ALL } from "@/middleware";
import { QrCode } from "@mui/icons-material";

dayjs.extend(isBetweenPlugin);
interface CustomPickerDayProps extends PickersDayProps<Dayjs> {
@@ -137,15 +138,15 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
firstDayOfWeekString + " to " + lastDayOfWeekString,
);
const [unsubmittedTimeSheetSelect, setUnsubmittedTimeSheetSelect]: any =
React.useState("Weekly");
React.useState("Monthly");
const [teamTotalManhoursSpentSelect, setTeamTotalManhoursSpentSelect]: any =
React.useState("Weekly");
React.useState("Monthly");
const [staffGradeManhoursSpentSelect, setStaffGradeManhoursSpentSelect]: any =
React.useState("Weekly");
React.useState("Monthly");
const [
individualStaffManhoursSpentSelect,
setIndividualStaffManhoursSpentSelect,
]: any = React.useState("Daily");
]: any = React.useState("Monthly");
const weekDates: any[] = [];
const monthDates: any[] = [];
const currentDate = dayjs();
@@ -665,13 +666,13 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
if (staffGradeManhoursSpentSelect === "Weekly") {
fetchTotalManhoursByGradeData()
}
}, [weeklyValueByStaffGrade, weeklyToValueByStaffGrade]);
}, [staffGradeTeamId, weeklyValueByStaffGrade, weeklyToValueByStaffGrade]);

useEffect(() => {
if (staffGradeManhoursSpentSelect === "Monthly") {
fetchMonthlyTotalManhoursByGradeData()
}
}, [totalManHoursMonthlyFromValue, totalManHoursMonthlyToValue]);
}, [staffGradeTeamId, totalManHoursMonthlyFromValue, totalManHoursMonthlyToValue]);

useEffect(() => {
if (unsubmittedTimeSheetSelect === "Weekly") {
@@ -703,6 +704,21 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
}
}, [staffId, indivdualManHoursMonthlyFromValue]);

// useEffect(() => {
// console.log(unsubmittedTimeSheetSelect)
// if (unsubmittedTimeSheetSelect === "Monthly" || teamTotalManhoursSpentSelect === "Monthly" || staffGradeManhoursSpentSelect === "Monthly" || individualStaffManhoursSpentSelect === "Monthly") {
// setUnsubmittedTimeSheetSelect("Monthly")
// setTeamTotalManhoursSpentSelect("Monthly")
// setStaffGradeManhoursSpentSelect("Monthly")
// setIndividualStaffManhoursSpentSelect("Monthly")
// } else if (unsubmittedTimeSheetSelect === "Weekly" || teamTotalManhoursSpentSelect === "Weekly" || staffGradeManhoursSpentSelect === "Weekly" || individualStaffManhoursSpentSelect === "Weekly") {
// setUnsubmittedTimeSheetSelect("Weekly")
// setTeamTotalManhoursSpentSelect("Weekly")
// setStaffGradeManhoursSpentSelect("Weekly")
// setIndividualStaffManhoursSpentSelect("Weekly")
// }
// }, [unsubmittedTimeSheetSelect, teamTotalManhoursSpentSelect, staffGradeManhoursSpentSelect, individualStaffManhoursSpentSelect]);




@@ -828,7 +844,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
const staffGradeOptions: ApexOptions = {
chart: {
height: 350,
type: "line",
type: "bar",
},
stroke: {
width: [2, 2],
@@ -972,6 +988,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {

const teamTotalManhoursSpentOnClick = (r: any) => {
setTeamTotalManhoursSpentSelect(r);

if (r === "Weekly") {
fetchWeeklyTeamManhourSpentData()
setValue(dayjs().startOf('week'));
@@ -1321,8 +1338,15 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
Weekly
</button>
<button
onClick={() =>
onClick={() => {
teamTotalManhoursSpentOnClick("Monthly")
setUnsubmittedTimeSheetSelect("Monthly")
fetchMonthlyUnsubmittedData()
setStaffGradeManhoursSpentSelect("Monthly")
fetchMonthlyTotalManhoursByGradeData()
setIndividualStaffManhoursSpentSelect("Monthly")
fetchMonthlyIndividualManhoursData()
}
}
className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-r-md w-32"
>
@@ -1333,8 +1357,15 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
{teamTotalManhoursSpentSelect === "Monthly" && (
<>
<button
onClick={() =>
onClick={() => {
teamTotalManhoursSpentOnClick("Weekly")
setUnsubmittedTimeSheetSelect("Weekly")
fetchWeeklyUnsubmittedData()
setStaffGradeManhoursSpentSelect("Weekly")
fetchTotalManhoursByGradeData()
setIndividualStaffManhoursSpentSelect("Weekly")
fetchWeeklyIndividualManhoursData()
}
}
className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-l-md w-32"
>
@@ -1451,8 +1482,13 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
</button>
<button
onClick={() => {
teamTotalManhoursSpentOnClick("Monthly")
setUnsubmittedTimeSheetSelect("Monthly")
fetchMonthlyUnsubmittedData()
setStaffGradeManhoursSpentSelect("Monthly")
fetchMonthlyTotalManhoursByGradeData()
setIndividualStaffManhoursSpentSelect("Monthly")
fetchMonthlyIndividualManhoursData()
}
}
className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-r-md w-48"
@@ -1465,8 +1501,13 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
<>
<button
onClick={() => {
teamTotalManhoursSpentOnClick("Weekly")
setUnsubmittedTimeSheetSelect("Weekly")
fetchWeeklyUnsubmittedData()
setStaffGradeManhoursSpentSelect("Weekly")
fetchTotalManhoursByGradeData()
setIndividualStaffManhoursSpentSelect("Weekly")
fetchWeeklyIndividualManhoursData()
}
}
className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-l-md w-32"
@@ -1601,8 +1642,13 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
</button>
<button
onClick={() => {
unsubmittedTimeSheetOnClick("Monthly")
fetchMonthlyUnsubmittedData()
teamTotalManhoursSpentOnClick("Monthly")
setUnsubmittedTimeSheetSelect("Monthly")
fetchMonthlyUnsubmittedData()
setStaffGradeManhoursSpentSelect("Monthly")
fetchMonthlyTotalManhoursByGradeData()
setIndividualStaffManhoursSpentSelect("Monthly")
fetchMonthlyIndividualManhoursData()
}
}
className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-r-md w-32"
@@ -1615,8 +1661,13 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
<>
<button
onClick={() => {
unsubmittedTimeSheetOnClick("Weekly")
fetchWeeklyUnsubmittedData()
teamTotalManhoursSpentOnClick("Weekly")
setUnsubmittedTimeSheetSelect("Weekly")
fetchWeeklyUnsubmittedData()
setStaffGradeManhoursSpentSelect("Weekly")
fetchTotalManhoursByGradeData()
setIndividualStaffManhoursSpentSelect("Weekly")
fetchWeeklyIndividualManhoursData()
}
}
className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid w-32"
@@ -1788,7 +1839,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
)}
{individualStaffManhoursSpentSelect === "Weekly" && (
<>
<button
{/* <button
onClick={() => {
individualStaffManhoursSpentOnClick("Daily")
fetchDailyIndividualManhoursData()
@@ -1797,13 +1848,18 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-l-md w-32"
>
Daily
</button>
</button> */}
<button className="text-lg bg-violet-100 border-violet-500 text-violet-500 border-solid w-32">
Weekly
</button>
<button
onClick={() => {
individualStaffManhoursSpentOnClick("Monthly")
teamTotalManhoursSpentOnClick("Monthly")
setUnsubmittedTimeSheetSelect("Monthly")
fetchMonthlyUnsubmittedData()
setStaffGradeManhoursSpentSelect("Monthly")
fetchMonthlyTotalManhoursByGradeData()
setIndividualStaffManhoursSpentSelect("Monthly")
fetchMonthlyIndividualManhoursData()
}
}
@@ -1815,7 +1871,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
)}
{individualStaffManhoursSpentSelect === "Monthly" && (
<>
<button
{/* <button
onClick={() => {
individualStaffManhoursSpentOnClick("Daily")
fetchDailyIndividualManhoursData()
@@ -1824,10 +1880,15 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => {
className="hover:cursor-pointer hover:bg-violet-50 text-lg bg-transparent border-violet-500 text-violet-500 border-solid rounded-l-md w-32"
>
Daily
</button>
</button> */}
<button
onClick={() => {
individualStaffManhoursSpentOnClick("Weekly")
teamTotalManhoursSpentOnClick("Weekly")
setUnsubmittedTimeSheetSelect("Weekly")
fetchWeeklyUnsubmittedData()
setStaffGradeManhoursSpentSelect("Weekly")
fetchTotalManhoursByGradeData()
setIndividualStaffManhoursSpentSelect("Weekly")
fetchWeeklyIndividualManhoursData()
}
}


Ładowanie…
Anuluj
Zapisz