@@ -8,12 +8,14 @@ import Tabs, { TabsProps } from "@mui/material/Tabs"; | |||||
import Tab from "@mui/material/Tab"; | import Tab from "@mui/material/Tab"; | ||||
import Typography from "@mui/material/Typography"; | import Typography from "@mui/material/Typography"; | ||||
import ProgressByClient from "@/components/ProgressByClient"; | import ProgressByClient from "@/components/ProgressByClient"; | ||||
import { preloadClientProjects } from "@/app/api/clientprojects"; | |||||
export const metadata: Metadata = { | export const metadata: Metadata = { | ||||
title: "Project Status by Client", | title: "Project Status by Client", | ||||
}; | }; | ||||
const ProjectStatusByClient: React.FC = () => { | const ProjectStatusByClient: React.FC = () => { | ||||
preloadClientProjects(); | |||||
return ( | return ( | ||||
<I18nProvider namespaces={["dashboard"]}> | <I18nProvider namespaces={["dashboard"]}> | ||||
<Typography variant="h4" marginInlineEnd={2}> | <Typography variant="h4" marginInlineEnd={2}> | ||||
@@ -22,7 +24,6 @@ const ProjectStatusByClient: React.FC = () => { | |||||
<Suspense fallback={<ProgressByClientSearch.Loading />}> | <Suspense fallback={<ProgressByClientSearch.Loading />}> | ||||
<ProgressByClientSearch /> | <ProgressByClientSearch /> | ||||
</Suspense> | </Suspense> | ||||
<ProgressByClient /> | |||||
</I18nProvider> | </I18nProvider> | ||||
); | ); | ||||
}; | }; | ||||
@@ -0,0 +1,28 @@ | |||||
"use server"; | |||||
import { serverFetchJson } from "@/app/utils/fetchUtil"; | |||||
import { BASE_API_URL } from "@/config/api"; | |||||
import { Dayjs } from "dayjs"; | |||||
import { cache } from "react"; | |||||
export interface ClientSubsidiaryProjectResult { | |||||
color: string; | |||||
projectId: number; | |||||
projectCode: string; | |||||
projectName: string; | |||||
team: string; | |||||
teamLead: string; | |||||
expectedStage: string; | |||||
budgetedManhour: number; | |||||
spentManhour: number; | |||||
remainedManhour: number; | |||||
manhourConsumptionPercentage: number; | |||||
comingPaymentMilestone: string; | |||||
} | |||||
export const fetchAllClientSubsidiaryProjects = cache(async (customerId: number, subsidiaryId: number) => { | |||||
return serverFetchJson<ClientSubsidiaryProjectResult[]>( | |||||
`${BASE_API_URL}/dashboard/searchCustomerSubsidiaryProject?customerId=${customerId}&subsidiaryId=${subsidiaryId}` | |||||
); | |||||
}); |
@@ -1,53 +1,86 @@ | |||||
import { cache } from "react"; | import { cache } from "react"; | ||||
import { serverFetchJson } from "@/app/utils/fetchUtil"; | |||||
import { BASE_API_URL } from "@/config/api"; | |||||
import "server-only"; | |||||
export interface ClientProjectResult { | export interface ClientProjectResult { | ||||
id: number; | id: number; | ||||
clientCode: string; | |||||
clientName: string; | |||||
SubsidiaryClientCode: string; | |||||
SubsidiaryClientName: string; | |||||
NoOfProjects: number; | |||||
customerId: number; | |||||
customerCode: string; | |||||
customerName: string; | |||||
subsidiaryId: number; | |||||
subsidiaryCode: string; | |||||
subsidiaryName: string; | |||||
projectNo: number; | |||||
} | } | ||||
export const preloadProjects = () => { | |||||
fetchClientProjects(); | |||||
// export interface ClientSubsidiaryProjectResult { | |||||
// projectId: number; | |||||
// projectCode: string; | |||||
// projectName: string; | |||||
// team: string; | |||||
// teamLead: string; | |||||
// expectedStage: string; | |||||
// budgetedManhour: number; | |||||
// spentManhour: number; | |||||
// remainedManhour: number; | |||||
// manhourConsumptionPercentage: number; | |||||
// comingPaymentMilestone: string; | |||||
// } | |||||
export const preloadClientProjects = () => { | |||||
fetchAllClientProjects(); | |||||
}; | }; | ||||
export const fetchClientProjects = cache(async () => { | |||||
return mockProjects; | |||||
// export const fetchClientProjects = cache(async () => { | |||||
// return mockProjects; | |||||
// }); | |||||
export const fetchAllClientProjects = cache(async () => { | |||||
return serverFetchJson<ClientProjectResult[]>(`${BASE_API_URL}/dashboard/searchCustomerSubsidiary`); | |||||
}); | }); | ||||
const mockProjects: ClientProjectResult[] = [ | |||||
{ | |||||
id: 1, | |||||
clientCode: "CUST-001", | |||||
clientName: "Client A", | |||||
SubsidiaryClientCode: "N/A", | |||||
SubsidiaryClientName: "N/A", | |||||
NoOfProjects: 5, | |||||
}, | |||||
{ | |||||
id: 2, | |||||
clientCode: "CUST-001", | |||||
clientName: "Client A", | |||||
SubsidiaryClientCode: "SUBS-001", | |||||
SubsidiaryClientName: "Subsidiary A", | |||||
NoOfProjects: 5, | |||||
}, | |||||
{ | |||||
id: 3, | |||||
clientCode: "CUST-001", | |||||
clientName: "Client A", | |||||
SubsidiaryClientCode: "SUBS-002", | |||||
SubsidiaryClientName: "Subsidiary B", | |||||
NoOfProjects: 3, | |||||
}, | |||||
{ | |||||
id: 4, | |||||
clientCode: "CUST-001", | |||||
clientName: "Client A", | |||||
SubsidiaryClientCode: "SUBS-003", | |||||
SubsidiaryClientName: "Subsidiary C", | |||||
NoOfProjects: 1, | |||||
}, | |||||
]; | |||||
// export const fetchAllClientSubsidiaryProjects = cache(async (customerId: number, subsidiaryId: number) => { | |||||
// return serverFetchJson<ClientSubsidiaryProjectResult>( | |||||
// `${BASE_API_URL}/dashboard/searchCustomerSubsidiaryProject/?${customerId}&${subsidiaryId}`, | |||||
// { | |||||
// next: { tags: [`allClientSubsidiaryProjects`] }, | |||||
// }, | |||||
// ); | |||||
// }); | |||||
// const mockProjects: ClientProjectResult[] = [ | |||||
// { | |||||
// id: 1, | |||||
// clientCode: "CUST-001", | |||||
// clientName: "Client A", | |||||
// SubsidiaryClientCode: "N/A", | |||||
// SubsidiaryClientName: "N/A", | |||||
// NoOfProjects: 5, | |||||
// }, | |||||
// { | |||||
// id: 2, | |||||
// clientCode: "CUST-001", | |||||
// clientName: "Client A", | |||||
// SubsidiaryClientCode: "SUBS-001", | |||||
// SubsidiaryClientName: "Subsidiary A", | |||||
// NoOfProjects: 5, | |||||
// }, | |||||
// { | |||||
// id: 3, | |||||
// clientCode: "CUST-001", | |||||
// clientName: "Client A", | |||||
// SubsidiaryClientCode: "SUBS-002", | |||||
// SubsidiaryClientName: "Subsidiary B", | |||||
// NoOfProjects: 3, | |||||
// }, | |||||
// { | |||||
// id: 4, | |||||
// clientCode: "CUST-001", | |||||
// clientName: "Client A", | |||||
// SubsidiaryClientCode: "SUBS-003", | |||||
// SubsidiaryClientName: "Subsidiary C", | |||||
// NoOfProjects: 1, | |||||
// }, | |||||
// ]; |
@@ -8,8 +8,6 @@ import { useTranslation } from "react-i18next"; | |||||
import { Card, CardHeader } from "@mui/material"; | import { Card, CardHeader } from "@mui/material"; | ||||
import CustomSearchForm from "../CustomSearchForm/CustomSearchForm"; | import CustomSearchForm from "../CustomSearchForm/CustomSearchForm"; | ||||
import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; | import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; | ||||
// import ReactApexChart from "react-apexcharts"; | |||||
import { ApexOptions } from "apexcharts"; | |||||
import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid"; | import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid"; | ||||
import ReportProblemIcon from "@mui/icons-material/ReportProblem"; | import ReportProblemIcon from "@mui/icons-material/ReportProblem"; | ||||
import dynamic from "next/dynamic"; | import dynamic from "next/dynamic"; | ||||
@@ -18,9 +16,18 @@ import { AnyARecord, AnyCnameRecord } from "dns"; | |||||
import SearchBox, { Criterion } from "../SearchBox"; | import SearchBox, { Criterion } from "../SearchBox"; | ||||
import ProgressByClientSearch from "@/components/ProgressByClientSearch"; | import ProgressByClientSearch from "@/components/ProgressByClientSearch"; | ||||
import { Suspense } from "react"; | import { Suspense } from "react"; | ||||
const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false }); | |||||
import { ClientSubsidiaryProjectResult } from "@/app/api/clientprojects/actions"; | |||||
import { ClientProjectResult} from "@/app/api/clientprojects"; | |||||
import { ConstructionOutlined } from "@mui/icons-material"; | |||||
import ReactApexChart from "react-apexcharts"; | |||||
import { ApexOptions } from "apexcharts"; | |||||
// const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false }); | |||||
interface Props { | |||||
clientSubsidiaryProjectResult: ClientSubsidiaryProjectResult[]; | |||||
} | |||||
const ProgressByClient: React.FC = () => { | |||||
const ProgressByClient: React.FC<Props> = ({ clientSubsidiaryProjectResult }) => { | |||||
const [activeTab, setActiveTab] = useState("financialSummary"); | const [activeTab, setActiveTab] = useState("financialSummary"); | ||||
const [SearchCriteria, setSearchCriteria] = React.useState({}); | const [SearchCriteria, setSearchCriteria] = React.useState({}); | ||||
const { t } = useTranslation("dashboard"); | const { t } = useTranslation("dashboard"); | ||||
@@ -45,42 +52,22 @@ const ProgressByClient: React.FC = () => { | |||||
const [checkboxDemo, setCheckboxDemo] = useState(false); | const [checkboxDemo, setCheckboxDemo] = useState(false); | ||||
const [receiptFromDate, setReceiptFromDate] = useState(null); | const [receiptFromDate, setReceiptFromDate] = useState(null); | ||||
const [receiptToDate, setReceiptToDate] = useState(null); | const [receiptToDate, setReceiptToDate] = useState(null); | ||||
const [selectedRows, setSelectedRows] = useState([]); | |||||
const rows = [ | |||||
{ | |||||
id: 1, | |||||
clientCode: "CUST-001", | |||||
clientName: "Client A", | |||||
clientSubsidiaryCode: "N/A", | |||||
clientSubsidiaryName: "N/A", | |||||
noOfProjects: "5", | |||||
}, | |||||
{ | |||||
id: 2, | |||||
clientCode: "CUST-001", | |||||
clientName: "Client A", | |||||
clientSubsidiaryCode: "SUBS-001", | |||||
clientSubsidiaryName: "Subsidiary A", | |||||
noOfProjects: "5", | |||||
}, | |||||
{ | |||||
id: 3, | |||||
clientCode: "CUST-001", | |||||
clientName: "Client A", | |||||
clientSubsidiaryCode: "SUBS-002", | |||||
clientSubsidiaryName: "Subsidiary B", | |||||
noOfProjects: "3", | |||||
}, | |||||
{ | |||||
id: 4, | |||||
clientCode: "CUST-001", | |||||
clientName: "Client A", | |||||
clientSubsidiaryCode: "SUBS-003", | |||||
clientSubsidiaryName: "Subsidiary C", | |||||
noOfProjects: "1", | |||||
}, | |||||
]; | |||||
//['#f57f90', '#94f7d6', '#87c5f5', '#ab95f5', '#fcd68b'] | |||||
const [selectedRows, setSelectedRows]:any[] = useState([]); | |||||
const [chartProjectName, setChartProjectName]:any[] = useState([]); | |||||
const [chartManhourConsumptionPercentage, setChartManhourConsumptionPercentage]:any[] = useState([]); | |||||
const color = ["#f57f90", "#94f7d6", "#87c5f5", "#ab95f5", "#fcd68b"]; | |||||
useEffect(() => { | |||||
const projectName = [] | |||||
const manhourConsumptionPercentage = [] | |||||
for (let i = 0; i < clientSubsidiaryProjectResult.length; i++){ | |||||
clientSubsidiaryProjectResult[i].color = color[i] | |||||
projectName.push(clientSubsidiaryProjectResult[i].projectName) | |||||
manhourConsumptionPercentage.push(clientSubsidiaryProjectResult[i].manhourConsumptionPercentage) | |||||
} | |||||
setChartProjectName(projectName) | |||||
setChartManhourConsumptionPercentage(manhourConsumptionPercentage) | |||||
}, [clientSubsidiaryProjectResult]); | |||||
const rows2 = [ | const rows2 = [ | ||||
{ | { | ||||
id: 1, | id: 1, | ||||
@@ -149,39 +136,12 @@ const ProgressByClient: React.FC = () => { | |||||
}, | }, | ||||
]; | ]; | ||||
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 = [ | const columns2 = [ | ||||
{ | { | ||||
id: "color", | id: "color", | ||||
field: "color", | field: "color", | ||||
headerName: "", | headerName: "", | ||||
renderCell: (params: any) => { | |||||
renderCell: (param: any) => { | |||||
return ( | return ( | ||||
<span | <span | ||||
className="dot" | className="dot" | ||||
@@ -189,7 +149,7 @@ const ProgressByClient: React.FC = () => { | |||||
height: "15px", | height: "15px", | ||||
width: "15px", | width: "15px", | ||||
borderRadius: "50%", | borderRadius: "50%", | ||||
backgroundColor: `${params.row.color}`, | |||||
backgroundColor: `${param.row.color}`, | |||||
display: "inline-block", | display: "inline-block", | ||||
}} | }} | ||||
></span> | ></span> | ||||
@@ -198,8 +158,8 @@ const ProgressByClient: React.FC = () => { | |||||
flex: 0.1, | flex: 0.1, | ||||
}, | }, | ||||
{ | { | ||||
id: "project", | |||||
field: "project", | |||||
id: "projectName", | |||||
field: "projectName", | |||||
headerName: "Project", | headerName: "Project", | ||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
@@ -216,9 +176,9 @@ const ProgressByClient: React.FC = () => { | |||||
flex: 0.8, | flex: 0.8, | ||||
}, | }, | ||||
{ | { | ||||
id: "currentStage", | |||||
field: "currentStage", | |||||
headerName: "Current Stage", | |||||
id: "expectedStage", | |||||
field: "expectedStage", | |||||
headerName: "Expected Stage", | |||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
{ | { | ||||
@@ -237,6 +197,7 @@ const ProgressByClient: React.FC = () => { | |||||
<span className="text-red-300">{params.row.spentManhour}</span> | <span className="text-red-300">{params.row.spentManhour}</span> | ||||
); | ); | ||||
} else { | } else { | ||||
console.log(params) | |||||
return <span>{params.row.spentManhour}</span>; | return <span>{params.row.spentManhour}</span>; | ||||
} | } | ||||
}, | }, | ||||
@@ -281,63 +242,130 @@ const ProgressByClient: React.FC = () => { | |||||
flex: 0.2, | flex: 0.2, | ||||
}, | }, | ||||
]; | ]; | ||||
const InputFields = [ | |||||
{ | |||||
id: "clientCode", | |||||
label: "Client Code", | |||||
type: "text", | |||||
value: clientCode, | |||||
setValue: setClientCode, | |||||
const optionstest: ApexOptions = { | |||||
chart: { | |||||
height: 350, | |||||
type: "line", | |||||
}, | }, | ||||
{ | |||||
id: "clientName", | |||||
label: "Client Name", | |||||
type: "text", | |||||
value: clientName, | |||||
setValue: setClientName, | |||||
stroke: { | |||||
width: [0, 0, 2, 2], | |||||
}, | }, | ||||
{ | |||||
id: "subsidiaryClientCode", | |||||
label: "Subsidiary Client Code", | |||||
type: "text", | |||||
value: subsidiaryClientCode, | |||||
setValue: setSubsidiaryClientCode, | |||||
plotOptions: { | |||||
bar: { | |||||
horizontal: false, | |||||
distributed: false, | |||||
}, | |||||
}, | }, | ||||
{ | |||||
id: "subsidiaryClientName", | |||||
label: "Subsidiary Client Name", | |||||
type: "text", | |||||
value: subsidiaryClientName, | |||||
setValue: setSubsidiaryClientName, | |||||
dataLabels: { | |||||
enabled: false, | |||||
}, | }, | ||||
// { 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], | |||||
xaxis: { | |||||
categories: [ | |||||
"Q1", | |||||
"Q2", | |||||
"Q3", | |||||
"Q4", | |||||
"Q5", | |||||
"Q6", | |||||
"Q7", | |||||
"Q8", | |||||
"Q9", | |||||
"Q10", | |||||
"Q11", | |||||
"Q12", | |||||
], | |||||
}, | }, | ||||
]; | |||||
const series: ApexAxisChartSeries | ApexNonAxisChartSeries = [ | |||||
{ | |||||
name: "Project Resource Consumption Percentage", | |||||
data: [80, 55, 40, 65, 70], | |||||
yaxis: [ | |||||
{ | |||||
title: { | |||||
text: "Monthly Income and Expenditure(HKD)", | |||||
}, | |||||
min: 0, | |||||
max: 350000, | |||||
tickAmount: 5, | |||||
labels: { | |||||
formatter: function (val) { | |||||
return val.toLocaleString() | |||||
} | |||||
} | |||||
}, | |||||
{ | |||||
show: false, | |||||
seriesName: "Monthly_Expenditure", | |||||
title: { | |||||
text: "Monthly Expenditure (HKD)", | |||||
}, | |||||
min: 0, | |||||
max: 350000, | |||||
tickAmount: 5, | |||||
}, | |||||
{ | |||||
seriesName: "Cumulative_Income", | |||||
opposite: true, | |||||
title: { | |||||
text: "Cumulative Income and Expenditure(HKD)", | |||||
}, | |||||
min: 0, | |||||
max: 850000, | |||||
tickAmount: 5, | |||||
labels: { | |||||
formatter: function (val) { | |||||
return val.toLocaleString() | |||||
} | |||||
} | |||||
}, | |||||
{ | |||||
show: false, | |||||
seriesName: "Cumulative_Expenditure", | |||||
opposite: true, | |||||
title: { | |||||
text: "Cumulative Expenditure (HKD)", | |||||
}, | |||||
min: 0, | |||||
max: 850000, | |||||
tickAmount: 5, | |||||
}, | |||||
], | |||||
grid: { | |||||
borderColor: "#f1f1f1", | |||||
}, | }, | ||||
]; | |||||
annotations: {}, | |||||
series: [ | |||||
{ | |||||
name: "Monthly_Income", | |||||
type: "column", | |||||
color: "#ffde91", | |||||
data: [0, 110000, 0, 0, 185000, 0, 0, 189000, 0, 0, 300000, 0], | |||||
}, | |||||
{ | |||||
name: "Monthly_Expenditure", | |||||
type: "column", | |||||
color: "#82b59a", | |||||
data: [ | |||||
0, 160000, 120000, 120000, 55000, 55000, 55000, 55000, 55000, 70000, | |||||
55000, 55000, | |||||
], | |||||
}, | |||||
{ | |||||
name: "Cumulative_Income", | |||||
type: "line", | |||||
color: "#EE6D7A", | |||||
data: [ | |||||
0, 100000, 100000, 100000, 300000, 300000, 300000, 500000, 500000, | |||||
500000, 800000, 800000, | |||||
], | |||||
}, | |||||
{ | |||||
name: "Cumulative_Expenditure", | |||||
type: "line", | |||||
color: "#7cd3f2", | |||||
data: [ | |||||
0, 198000, 240000, 400000, 410000, 430000, 510000, 580000, 600000, | |||||
710000, 730000, 790000, | |||||
], | |||||
}, | |||||
], | |||||
}; | |||||
const options2: ApexOptions = { | const options2: ApexOptions = { | ||||
chart: { | chart: { | ||||
@@ -396,6 +424,10 @@ const ProgressByClient: React.FC = () => { | |||||
type: "bar", | type: "bar", | ||||
height: 350, | height: 350, | ||||
}, | }, | ||||
series: [{ | |||||
name: "Project Resource Consumption Percentage", | |||||
data: chartManhourConsumptionPercentage, | |||||
},], | |||||
colors: ["#f57f90", "#94f7d6", "#87c5f5", "#ab95f5", "#fcd68b"], | colors: ["#f57f90", "#94f7d6", "#87c5f5", "#ab95f5", "#fcd68b"], | ||||
plotOptions: { | plotOptions: { | ||||
bar: { | bar: { | ||||
@@ -407,13 +439,7 @@ const ProgressByClient: React.FC = () => { | |||||
enabled: false, | enabled: false, | ||||
}, | }, | ||||
xaxis: { | xaxis: { | ||||
categories: [ | |||||
"Consultancy Project 123", | |||||
"Consultancy Project 456", | |||||
"Construction Project A", | |||||
"Construction Project B", | |||||
"Construction Project C", | |||||
], | |||||
categories: chartProjectName, | |||||
}, | }, | ||||
yaxis: { | yaxis: { | ||||
title: { | title: { | ||||
@@ -437,8 +463,8 @@ const ProgressByClient: React.FC = () => { | |||||
}; | }; | ||||
const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => { | const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => { | ||||
const selectedRowsData = rows2.filter((row) => | |||||
newSelectionModel.includes(row.id), | |||||
const selectedRowsData:any = clientSubsidiaryProjectResult.filter((row) => | |||||
newSelectionModel.includes(row.projectId), | |||||
); | ); | ||||
console.log(selectedRowsData); | console.log(selectedRowsData); | ||||
const projectArray = []; | const projectArray = []; | ||||
@@ -450,10 +476,10 @@ const ProgressByClient: React.FC = () => { | |||||
if (i === selectedRowsData.length && i > 0) { | if (i === selectedRowsData.length && i > 0) { | ||||
projectArray.push("Remained"); | projectArray.push("Remained"); | ||||
} else if (selectedRowsData.length > 0) { | } else if (selectedRowsData.length > 0) { | ||||
projectArray.push(selectedRowsData[i].project); | |||||
projectArray.push(selectedRowsData[i].projectName); | |||||
totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour); | totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour); | ||||
totalSpent += Number(selectedRowsData[i].spentManhour); | totalSpent += Number(selectedRowsData[i].spentManhour); | ||||
pieChartColorArray.push(selectedRowsData[i].color); | |||||
pieChartColorArray.push(color[i]); | |||||
} | } | ||||
} | } | ||||
for (let i = 0; i <= selectedRowsData.length; i++) { | for (let i = 0; i <= selectedRowsData.length; i++) { | ||||
@@ -507,9 +533,9 @@ const ProgressByClient: React.FC = () => { | |||||
<CardHeader className="text-slate-500" title="Project Resource Consumption" /> | <CardHeader className="text-slate-500" title="Project Resource Consumption" /> | ||||
<div style={{ display: "inline-block", width: "99%" }}> | <div style={{ display: "inline-block", width: "99%" }}> | ||||
<ReactApexChart | <ReactApexChart | ||||
options={options} | |||||
series={series} | |||||
type="bar" | |||||
options={optionstest} | |||||
series={optionstest.series} | |||||
type="line" | |||||
height={350} | height={350} | ||||
/> | /> | ||||
</div> | </div> | ||||
@@ -530,7 +556,7 @@ const ProgressByClient: React.FC = () => { | |||||
style={{ display: "inline-block", width: "99%", marginLeft: 10 }} | style={{ display: "inline-block", width: "99%", marginLeft: 10 }} | ||||
> | > | ||||
<CustomDatagrid | <CustomDatagrid | ||||
rows={rows2} | |||||
rows={clientSubsidiaryProjectResult} | |||||
columns={columns2} | columns={columns2} | ||||
columnWidth={200} | columnWidth={200} | ||||
dataGridHeight={300} | dataGridHeight={300} | ||||
@@ -564,13 +590,13 @@ const ProgressByClient: React.FC = () => { | |||||
Please select the project you want to check. | Please select the project you want to check. | ||||
</div> | </div> | ||||
)} | )} | ||||
{percentageArray.length > 0 && ( | |||||
{/* {percentageArray.length > 0 && ( | |||||
<ReactApexChart | <ReactApexChart | ||||
options={options2} | options={options2} | ||||
series={percentageArray} | series={percentageArray} | ||||
type="donut" | type="donut" | ||||
/> | /> | ||||
)} | |||||
)} */} | |||||
</Card> | </Card> | ||||
</Grid> | </Grid> | ||||
<Grid item xs={12} md={12} lg={12}> | <Grid item xs={12} md={12} lg={12}> | ||||
@@ -5,35 +5,50 @@ import React, { useMemo, useState, useCallback } from "react"; | |||||
import SearchBox, { Criterion } from "../SearchBox"; | import SearchBox, { Criterion } from "../SearchBox"; | ||||
import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
import SearchResults, { Column } from "../SearchResults"; | import SearchResults, { Column } from "../SearchResults"; | ||||
import { ClientProjectResult } from "@/app/api/clientprojects"; | |||||
import EditNote from "@mui/icons-material/EditNote"; | |||||
import { ClientProjectResult} from "@/app/api/clientprojects"; | |||||
import { fetchAllClientSubsidiaryProjects} from "@/app/api/clientprojects/actions"; | |||||
import VisibilityIcon from '@mui/icons-material/Visibility'; | |||||
import { useRouter, useSearchParams } from "next/navigation"; | import { useRouter, useSearchParams } from "next/navigation"; | ||||
import ProgressByClient from "@/components/ProgressByClient"; | |||||
interface Props { | interface Props { | ||||
projects: ClientProjectResult[]; | |||||
clientProjects: ClientProjectResult[]; | |||||
} | } | ||||
type SearchQuery = Partial<Omit<ClientProjectResult, "id">>; | type SearchQuery = Partial<Omit<ClientProjectResult, "id">>; | ||||
type SearchParamNames = keyof SearchQuery; | type SearchParamNames = keyof SearchQuery; | ||||
const ProgressByClientSearch: React.FC<Props> = ({ projects }) => { | |||||
const ProgressByClientSearch: React.FC<Props> = ({ clientProjects }) => { | |||||
const { t } = useTranslation("projects"); | const { t } = useTranslation("projects"); | ||||
const searchParams = useSearchParams() | const searchParams = useSearchParams() | ||||
// If project searching is done on the server-side, then no need for this. | // If project searching is done on the server-side, then no need for this. | ||||
const [filteredProjects, setFilteredProjects] = useState(projects); | |||||
const [filteredProjects, setFilteredProjects] = useState(clientProjects); | |||||
const [clientSubsidiaryProjectResult, setClientSubsidiaryProjectResult]:any[] = useState([]); | |||||
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | ||||
() => [ | () => [ | ||||
{ label: "Client Code", paramName: "clientCode", type: "text" }, | |||||
{ label: "Client Name", paramName: "clientName", type: "text" }, | |||||
{ label: "Client Code", paramName: "customerCode", type: "text" }, | |||||
{ label: "Client Name", paramName: "customerName", type: "text" }, | |||||
], | ], | ||||
[t], | [t], | ||||
); | ); | ||||
const onTaskClick = useCallback((clientProjectResult: ClientProjectResult) => { | |||||
const params = new URLSearchParams(searchParams.toString()) | |||||
params.set("id", clientProjectResult.id.toString()) | |||||
console.log(clientProjectResult) | |||||
}, []); | |||||
// const onTaskClick = useCallback((clientProjectResult: ClientProjectResult) => { | |||||
// const clickResult = fetchAllClientSubsidiaryProjects(clientProjectResult.customerId, clientProjectResult.subsidiaryId) | |||||
// console.log(clickResult) | |||||
// setClientSubsidiaryProjectResult(clickResult) | |||||
// }, []); | |||||
const onTaskClick = useCallback(async (clientProjectResult: ClientProjectResult) => { | |||||
try { | |||||
const clickResult = await fetchAllClientSubsidiaryProjects(clientProjectResult.customerId, clientProjectResult.subsidiaryId); | |||||
console.log(clickResult); | |||||
setClientSubsidiaryProjectResult(clickResult); | |||||
} catch (error) { | |||||
console.error('Error fetching client subsidiary projects:', error); | |||||
} | |||||
}, []); | |||||
const columns = useMemo<Column<ClientProjectResult>[]>( | const columns = useMemo<Column<ClientProjectResult>[]>( | ||||
() => [ | () => [ | ||||
@@ -41,13 +56,13 @@ const ProgressByClientSearch: React.FC<Props> = ({ projects }) => { | |||||
name: "id", | name: "id", | ||||
label: t("Details"), | label: t("Details"), | ||||
onClick: onTaskClick, | onClick: onTaskClick, | ||||
buttonIcon: <EditNote />, | |||||
buttonIcon: <VisibilityIcon />, | |||||
}, | }, | ||||
{ name: "clientCode", label: t("Client Code") }, | |||||
{ name: "clientName", label: t("Client Name") }, | |||||
{ name: "SubsidiaryClientCode", label: t("Subsidiary Code") }, | |||||
{ name: "SubsidiaryClientName", label: t("Subisdiary") }, | |||||
{ name: "NoOfProjects", label: t("No. of Projects") }, | |||||
{ name: "customerCode", label: t("Client Code") }, | |||||
{ name: "customerName", label: t("Client Name") }, | |||||
{ name: "subsidiaryCode", label: t("Subsidiary Code") }, | |||||
{ name: "subsidiaryName", label: t("Subisdiary") }, | |||||
{ name: "projectNo", label: t("No. of Projects") }, | |||||
], | ], | ||||
[onTaskClick, t], | [onTaskClick, t], | ||||
// [t], | // [t], | ||||
@@ -58,13 +73,20 @@ const ProgressByClientSearch: React.FC<Props> = ({ projects }) => { | |||||
<SearchBox | <SearchBox | ||||
criteria={searchCriteria} | criteria={searchCriteria} | ||||
onSearch={(query) => { | onSearch={(query) => { | ||||
console.log(query); | |||||
setFilteredProjects( | |||||
clientProjects.filter( | |||||
(cp) => | |||||
cp.customerCode.toLowerCase().includes(query.customerCode.toLowerCase()) && | |||||
cp.customerName.toLowerCase().includes(query.customerName.toLowerCase()) | |||||
), | |||||
); | |||||
}} | }} | ||||
/> | /> | ||||
<SearchResults<ClientProjectResult> | <SearchResults<ClientProjectResult> | ||||
items={filteredProjects} | items={filteredProjects} | ||||
columns={columns} | columns={columns} | ||||
/> | /> | ||||
<ProgressByClient clientSubsidiaryProjectResult={clientSubsidiaryProjectResult}/> | |||||
</> | </> | ||||
); | ); | ||||
}; | }; | ||||
@@ -1,4 +1,4 @@ | |||||
import { fetchClientProjects } from "@/app/api/clientprojects"; | |||||
import { fetchAllClientProjects } from "@/app/api/clientprojects"; | |||||
import React from "react"; | import React from "react"; | ||||
import ProgressByClientSearch from "./ProgressByClientSearch"; | import ProgressByClientSearch from "./ProgressByClientSearch"; | ||||
import ProgressByClientSearchLoading from "./ProgressByClientSearchLoading"; | import ProgressByClientSearchLoading from "./ProgressByClientSearchLoading"; | ||||
@@ -8,9 +8,8 @@ interface SubComponents { | |||||
} | } | ||||
const ProgressByClientSearchWrapper: React.FC & SubComponents = async () => { | const ProgressByClientSearchWrapper: React.FC & SubComponents = async () => { | ||||
const clentprojects = await fetchClientProjects(); | |||||
return <ProgressByClientSearch projects={clentprojects} />; | |||||
const clientprojects = await fetchAllClientProjects(); | |||||
return <ProgressByClientSearch clientProjects={clientprojects} />; | |||||
}; | }; | ||||
ProgressByClientSearchWrapper.Loading = ProgressByClientSearchLoading; | ProgressByClientSearchWrapper.Loading = ProgressByClientSearchLoading; | ||||
@@ -8,7 +8,7 @@ import { useTranslation } from "react-i18next"; | |||||
import { Card, CardHeader } from "@mui/material"; | import { Card, CardHeader } from "@mui/material"; | ||||
import CustomSearchForm from "../CustomSearchForm/CustomSearchForm"; | import CustomSearchForm from "../CustomSearchForm/CustomSearchForm"; | ||||
import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; | import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; | ||||
// import ReactApexChart from "react-apexcharts"; | |||||
import ReactApexChart from "react-apexcharts"; | |||||
import { ApexOptions } from "apexcharts"; | import { ApexOptions } from "apexcharts"; | ||||
import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid"; | import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid"; | ||||
import ReportProblemIcon from "@mui/icons-material/ReportProblem"; | import ReportProblemIcon from "@mui/icons-material/ReportProblem"; | ||||
@@ -18,7 +18,7 @@ import { AnyARecord, AnyCnameRecord } from "dns"; | |||||
import SearchBox, { Criterion } from "../SearchBox"; | import SearchBox, { Criterion } from "../SearchBox"; | ||||
import ProgressByTeamSearch from "@/components/ProgressByTeamSearch"; | import ProgressByTeamSearch from "@/components/ProgressByTeamSearch"; | ||||
import { Suspense } from "react"; | import { Suspense } from "react"; | ||||
const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false }); | |||||
// const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false }); | |||||
const ProgressByTeam: React.FC = () => { | const ProgressByTeam: React.FC = () => { | ||||
const [activeTab, setActiveTab] = useState("financialSummary"); | const [activeTab, setActiveTab] = useState("financialSummary"); | ||||
@@ -20,6 +20,7 @@ type SearchParamNames = keyof SearchQuery; | |||||
const ProjectSearch: React.FC<Props> = ({ projects, projectCategories }) => { | const ProjectSearch: React.FC<Props> = ({ projects, projectCategories }) => { | ||||
const router = useRouter(); | const router = useRouter(); | ||||
const { t } = useTranslation("projects"); | const { t } = useTranslation("projects"); | ||||
console.log(projects) | |||||
const [filteredProjects, setFilteredProjects] = useState(projects); | const [filteredProjects, setFilteredProjects] = useState(projects); | ||||