| @@ -8,12 +8,14 @@ import Tabs, { TabsProps } from "@mui/material/Tabs"; | |||
| import Tab from "@mui/material/Tab"; | |||
| import Typography from "@mui/material/Typography"; | |||
| import ProgressByClient from "@/components/ProgressByClient"; | |||
| import { preloadClientProjects } from "@/app/api/clientprojects"; | |||
| export const metadata: Metadata = { | |||
| title: "Project Status by Client", | |||
| }; | |||
| const ProjectStatusByClient: React.FC = () => { | |||
| preloadClientProjects(); | |||
| return ( | |||
| <I18nProvider namespaces={["dashboard"]}> | |||
| <Typography variant="h4" marginInlineEnd={2}> | |||
| @@ -22,7 +24,6 @@ const ProjectStatusByClient: React.FC = () => { | |||
| <Suspense fallback={<ProgressByClientSearch.Loading />}> | |||
| <ProgressByClientSearch /> | |||
| </Suspense> | |||
| <ProgressByClient /> | |||
| </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 { serverFetchJson } from "@/app/utils/fetchUtil"; | |||
| import { BASE_API_URL } from "@/config/api"; | |||
| import "server-only"; | |||
| export interface ClientProjectResult { | |||
| 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 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"; | |||
| @@ -18,9 +16,18 @@ import { AnyARecord, AnyCnameRecord } from "dns"; | |||
| import SearchBox, { Criterion } from "../SearchBox"; | |||
| import ProgressByClientSearch from "@/components/ProgressByClientSearch"; | |||
| 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 [SearchCriteria, setSearchCriteria] = React.useState({}); | |||
| const { t } = useTranslation("dashboard"); | |||
| @@ -45,42 +52,22 @@ const ProgressByClient: React.FC = () => { | |||
| const [checkboxDemo, setCheckboxDemo] = useState(false); | |||
| const [receiptFromDate, setReceiptFromDate] = 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 = [ | |||
| { | |||
| 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 = [ | |||
| { | |||
| id: "color", | |||
| field: "color", | |||
| headerName: "", | |||
| renderCell: (params: any) => { | |||
| renderCell: (param: any) => { | |||
| return ( | |||
| <span | |||
| className="dot" | |||
| @@ -189,7 +149,7 @@ const ProgressByClient: React.FC = () => { | |||
| height: "15px", | |||
| width: "15px", | |||
| borderRadius: "50%", | |||
| backgroundColor: `${params.row.color}`, | |||
| backgroundColor: `${param.row.color}`, | |||
| display: "inline-block", | |||
| }} | |||
| ></span> | |||
| @@ -198,8 +158,8 @@ const ProgressByClient: React.FC = () => { | |||
| flex: 0.1, | |||
| }, | |||
| { | |||
| id: "project", | |||
| field: "project", | |||
| id: "projectName", | |||
| field: "projectName", | |||
| headerName: "Project", | |||
| flex: 1, | |||
| }, | |||
| @@ -216,9 +176,9 @@ const ProgressByClient: React.FC = () => { | |||
| flex: 0.8, | |||
| }, | |||
| { | |||
| id: "currentStage", | |||
| field: "currentStage", | |||
| headerName: "Current Stage", | |||
| id: "expectedStage", | |||
| field: "expectedStage", | |||
| headerName: "Expected Stage", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| @@ -237,6 +197,7 @@ const ProgressByClient: React.FC = () => { | |||
| <span className="text-red-300">{params.row.spentManhour}</span> | |||
| ); | |||
| } else { | |||
| console.log(params) | |||
| return <span>{params.row.spentManhour}</span>; | |||
| } | |||
| }, | |||
| @@ -281,63 +242,130 @@ const ProgressByClient: React.FC = () => { | |||
| 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 = { | |||
| chart: { | |||
| @@ -396,6 +424,10 @@ const ProgressByClient: React.FC = () => { | |||
| type: "bar", | |||
| height: 350, | |||
| }, | |||
| series: [{ | |||
| name: "Project Resource Consumption Percentage", | |||
| data: chartManhourConsumptionPercentage, | |||
| },], | |||
| colors: ["#f57f90", "#94f7d6", "#87c5f5", "#ab95f5", "#fcd68b"], | |||
| plotOptions: { | |||
| bar: { | |||
| @@ -407,13 +439,7 @@ const ProgressByClient: React.FC = () => { | |||
| enabled: false, | |||
| }, | |||
| xaxis: { | |||
| categories: [ | |||
| "Consultancy Project 123", | |||
| "Consultancy Project 456", | |||
| "Construction Project A", | |||
| "Construction Project B", | |||
| "Construction Project C", | |||
| ], | |||
| categories: chartProjectName, | |||
| }, | |||
| yaxis: { | |||
| title: { | |||
| @@ -437,8 +463,8 @@ const ProgressByClient: React.FC = () => { | |||
| }; | |||
| 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); | |||
| const projectArray = []; | |||
| @@ -450,10 +476,10 @@ const ProgressByClient: React.FC = () => { | |||
| if (i === selectedRowsData.length && i > 0) { | |||
| projectArray.push("Remained"); | |||
| } else if (selectedRowsData.length > 0) { | |||
| projectArray.push(selectedRowsData[i].project); | |||
| projectArray.push(selectedRowsData[i].projectName); | |||
| totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour); | |||
| totalSpent += Number(selectedRowsData[i].spentManhour); | |||
| pieChartColorArray.push(selectedRowsData[i].color); | |||
| pieChartColorArray.push(color[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" /> | |||
| <div style={{ display: "inline-block", width: "99%" }}> | |||
| <ReactApexChart | |||
| options={options} | |||
| series={series} | |||
| type="bar" | |||
| options={optionstest} | |||
| series={optionstest.series} | |||
| type="line" | |||
| height={350} | |||
| /> | |||
| </div> | |||
| @@ -530,7 +556,7 @@ const ProgressByClient: React.FC = () => { | |||
| style={{ display: "inline-block", width: "99%", marginLeft: 10 }} | |||
| > | |||
| <CustomDatagrid | |||
| rows={rows2} | |||
| rows={clientSubsidiaryProjectResult} | |||
| columns={columns2} | |||
| columnWidth={200} | |||
| dataGridHeight={300} | |||
| @@ -564,13 +590,13 @@ const ProgressByClient: React.FC = () => { | |||
| Please select the project you want to check. | |||
| </div> | |||
| )} | |||
| {percentageArray.length > 0 && ( | |||
| {/* {percentageArray.length > 0 && ( | |||
| <ReactApexChart | |||
| options={options2} | |||
| series={percentageArray} | |||
| type="donut" | |||
| /> | |||
| )} | |||
| )} */} | |||
| </Card> | |||
| </Grid> | |||
| <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 { useTranslation } from "react-i18next"; | |||
| 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 ProgressByClient from "@/components/ProgressByClient"; | |||
| interface Props { | |||
| projects: ClientProjectResult[]; | |||
| clientProjects: ClientProjectResult[]; | |||
| } | |||
| type SearchQuery = Partial<Omit<ClientProjectResult, "id">>; | |||
| type SearchParamNames = keyof SearchQuery; | |||
| const ProgressByClientSearch: React.FC<Props> = ({ projects }) => { | |||
| const ProgressByClientSearch: React.FC<Props> = ({ clientProjects }) => { | |||
| const { t } = useTranslation("projects"); | |||
| const searchParams = useSearchParams() | |||
| // 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( | |||
| () => [ | |||
| { 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], | |||
| ); | |||
| 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>[]>( | |||
| () => [ | |||
| @@ -41,13 +56,13 @@ const ProgressByClientSearch: React.FC<Props> = ({ projects }) => { | |||
| name: "id", | |||
| label: t("Details"), | |||
| 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], | |||
| // [t], | |||
| @@ -58,13 +73,20 @@ const ProgressByClientSearch: React.FC<Props> = ({ projects }) => { | |||
| <SearchBox | |||
| criteria={searchCriteria} | |||
| 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> | |||
| items={filteredProjects} | |||
| 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 ProgressByClientSearch from "./ProgressByClientSearch"; | |||
| import ProgressByClientSearchLoading from "./ProgressByClientSearchLoading"; | |||
| @@ -8,9 +8,8 @@ interface SubComponents { | |||
| } | |||
| 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; | |||
| @@ -8,7 +8,7 @@ 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 ReactApexChart from "react-apexcharts"; | |||
| import { ApexOptions } from "apexcharts"; | |||
| import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid"; | |||
| import ReportProblemIcon from "@mui/icons-material/ReportProblem"; | |||
| @@ -18,7 +18,7 @@ import { AnyARecord, AnyCnameRecord } from "dns"; | |||
| import SearchBox, { Criterion } from "../SearchBox"; | |||
| import ProgressByTeamSearch from "@/components/ProgressByTeamSearch"; | |||
| 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 [activeTab, setActiveTab] = useState("financialSummary"); | |||
| @@ -20,6 +20,7 @@ type SearchParamNames = keyof SearchQuery; | |||
| const ProjectSearch: React.FC<Props> = ({ projects, projectCategories }) => { | |||
| const router = useRouter(); | |||
| const { t } = useTranslation("projects"); | |||
| console.log(projects) | |||
| const [filteredProjects, setFilteredProjects] = useState(projects); | |||