| @@ -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); | ||||