| @@ -1,10 +1,10 @@ | |||
| /** @type {import('next').NextConfig} */ | |||
| const nextConfig = { | |||
| // eslint: { | |||
| // // Warning: This allows production builds to successfully complete even if | |||
| // // your project has ESLint errors. | |||
| // ignoreDuringBuilds: true, | |||
| // }, | |||
| } | |||
| // eslint: { | |||
| // // Warning: This allows production builds to successfully complete even if | |||
| // // your project has ESLint errors. | |||
| // ignoreDuringBuilds: true, | |||
| // }, | |||
| }; | |||
| module.exports = nextConfig | |||
| module.exports = nextConfig; | |||
| @@ -3,25 +3,23 @@ import { I18nProvider } from "@/i18n"; | |||
| import DashboardPage from "@/components/DashboardPage/DashboardPage"; | |||
| import DashboardPageButton from "@/components/DashboardPage/DashboardTabButton"; | |||
| import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch"; | |||
| import { Suspense} from "react"; | |||
| import { Suspense } from "react"; | |||
| import Tabs, { TabsProps } from "@mui/material/Tabs"; | |||
| import Tab from "@mui/material/Tab"; | |||
| import Typography from "@mui/material/Typography"; | |||
| import CompanyTeamCashFlowComponent from '@/components/CompanyTeamCashFlow' | |||
| import CompanyTeamCashFlowComponent from "@/components/CompanyTeamCashFlow"; | |||
| export const metadata: Metadata = { | |||
| title: "Project Status by Client", | |||
| }; | |||
| const CompanyTeamCashFlow: React.FC = () => { | |||
| return ( | |||
| <I18nProvider namespaces={["dashboard"]}> | |||
| <Typography variant="h4" marginInlineEnd={2}> | |||
| Company / Team Cash Flow | |||
| </Typography> | |||
| <CompanyTeamCashFlowComponent/> | |||
| <CompanyTeamCashFlowComponent /> | |||
| </I18nProvider> | |||
| ); | |||
| }; | |||
| @@ -3,19 +3,17 @@ import { I18nProvider } from "@/i18n"; | |||
| import DashboardPage from "@/components/DashboardPage/DashboardPage"; | |||
| import DashboardPageButton from "@/components/DashboardPage/DashboardTabButton"; | |||
| import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch"; | |||
| import { Suspense} from "react"; | |||
| import { Suspense } from "react"; | |||
| import Tabs, { TabsProps } from "@mui/material/Tabs"; | |||
| import Tab from "@mui/material/Tab"; | |||
| import Typography from "@mui/material/Typography"; | |||
| import ProjectCashFlowComponent from '@/components/ProjectCashFlow' | |||
| import ProjectCashFlowComponent from "@/components/ProjectCashFlow"; | |||
| export const metadata: Metadata = { | |||
| title: "Project Status by Client", | |||
| }; | |||
| const ProjectCashFlow: React.FC = () => { | |||
| return ( | |||
| <I18nProvider namespaces={["dashboard"]}> | |||
| <Typography variant="h4" marginInlineEnd={2}> | |||
| @@ -24,7 +22,7 @@ const ProjectCashFlow: React.FC = () => { | |||
| {/* <Suspense fallback={<ProgressCashFlowSearch.Loading />}> | |||
| <ProgressCashFlowSearch/> | |||
| </Suspense> */} | |||
| <ProjectCashFlowComponent/> | |||
| <ProjectCashFlowComponent /> | |||
| </I18nProvider> | |||
| ); | |||
| }; | |||
| @@ -3,7 +3,7 @@ import { I18nProvider } from "@/i18n"; | |||
| import DashboardPage from "@/components/DashboardPage/DashboardPage"; | |||
| import DashboardPageButton from "@/components/DashboardPage/DashboardTabButton"; | |||
| import ProgressByClientSearch from "@/components/ProgressByClientSearch"; | |||
| import { Suspense} from "react"; | |||
| import { Suspense } from "react"; | |||
| import Tabs, { TabsProps } from "@mui/material/Tabs"; | |||
| import Tab from "@mui/material/Tab"; | |||
| import Typography from "@mui/material/Typography"; | |||
| @@ -13,15 +13,13 @@ export const metadata: Metadata = { | |||
| title: "Project Status by Client", | |||
| }; | |||
| const ProjectFinancialSummary: React.FC = () => { | |||
| return ( | |||
| <I18nProvider namespaces={["dashboard"]}> | |||
| <Typography variant="h4" marginInlineEnd={2}> | |||
| Project Financial Summary | |||
| </Typography> | |||
| <ProjectFinancialSummaryComponents/> | |||
| <ProjectFinancialSummaryComponents /> | |||
| </I18nProvider> | |||
| ); | |||
| }; | |||
| @@ -3,7 +3,7 @@ import { I18nProvider } from "@/i18n"; | |||
| import DashboardPage from "@/components/DashboardPage/DashboardPage"; | |||
| import DashboardPageButton from "@/components/DashboardPage/DashboardTabButton"; | |||
| import ProgressByClientSearch from "@/components/ProgressByClientSearch"; | |||
| import { Suspense} from "react"; | |||
| import { Suspense } from "react"; | |||
| import Tabs, { TabsProps } from "@mui/material/Tabs"; | |||
| import Tab from "@mui/material/Tab"; | |||
| import Typography from "@mui/material/Typography"; | |||
| @@ -13,18 +13,16 @@ export const metadata: Metadata = { | |||
| title: "Project Status by Client", | |||
| }; | |||
| const ProjectStatusByClient: React.FC = () => { | |||
| return ( | |||
| <I18nProvider namespaces={["dashboard"]}> | |||
| <Typography variant="h4" marginInlineEnd={2}> | |||
| Project Status by Client | |||
| </Typography> | |||
| <Suspense fallback={<ProgressByClientSearch.Loading />}> | |||
| <ProgressByClientSearch/> | |||
| <ProgressByClientSearch /> | |||
| </Suspense> | |||
| <ProgressByClient/> | |||
| <ProgressByClient /> | |||
| </I18nProvider> | |||
| ); | |||
| }; | |||
| @@ -3,7 +3,7 @@ import { I18nProvider } from "@/i18n"; | |||
| import DashboardPage from "@/components/DashboardPage/DashboardPage"; | |||
| import DashboardPageButton from "@/components/DashboardPage/DashboardTabButton"; | |||
| import ProgressByClientSearch from "@/components/ProgressByClientSearch"; | |||
| import { Suspense} from "react"; | |||
| import { Suspense } from "react"; | |||
| import Tabs, { TabsProps } from "@mui/material/Tabs"; | |||
| import Tab from "@mui/material/Tab"; | |||
| import Typography from "@mui/material/Typography"; | |||
| @@ -13,15 +13,13 @@ export const metadata: Metadata = { | |||
| title: "Project Status by Client", | |||
| }; | |||
| const StaffUtilization: React.FC = () => { | |||
| return ( | |||
| <I18nProvider namespaces={["dashboard"]}> | |||
| <Typography variant="h4" marginInlineEnd={2}> | |||
| Staff Utilization | |||
| </Typography> | |||
| <StaffUtilizationComponent/> | |||
| <StaffUtilizationComponent /> | |||
| </I18nProvider> | |||
| ); | |||
| }; | |||
| @@ -3,7 +3,7 @@ import { I18nProvider } from "@/i18n"; | |||
| import DashboardPage from "@/components/DashboardPage/DashboardPage"; | |||
| import DashboardPageButton from "@/components/DashboardPage/DashboardTabButton"; | |||
| import ProgressByClientSearch from "@/components/ProgressByClientSearch"; | |||
| import { Suspense} from "react"; | |||
| import { Suspense } from "react"; | |||
| import Tabs, { TabsProps } from "@mui/material/Tabs"; | |||
| import Tab from "@mui/material/Tab"; | |||
| @@ -11,12 +11,8 @@ export const metadata: Metadata = { | |||
| title: "Dashboard", | |||
| }; | |||
| const Dashboard: React.FC = () => { | |||
| return ( | |||
| <div>test</div> | |||
| ); | |||
| return <div>test</div>; | |||
| }; | |||
| export default Dashboard; | |||
| @@ -9,8 +9,8 @@ export const metadata: Metadata = { | |||
| const Home: React.FC = async () => { | |||
| return ( | |||
| <I18nProvider namespaces={["home"]}> | |||
| <UserWorkspacePage/> | |||
| </I18nProvider> | |||
| <UserWorkspacePage /> | |||
| </I18nProvider> | |||
| ); | |||
| }; | |||
| @@ -34,6 +34,6 @@ const mockProjects: CashFlow[] = [ | |||
| startDateTo: "5", | |||
| targetEndDate: "s", | |||
| client: "ss", | |||
| subsidiary:"ss", | |||
| } | |||
| subsidiary: "ss", | |||
| }, | |||
| ]; | |||
| @@ -24,7 +24,7 @@ const mockClaims: ClaimResult[] = [ | |||
| id: 1, | |||
| created: "2023-11-22", | |||
| name: "Consultancy Project A", | |||
| cost: 121.00, | |||
| cost: 121.0, | |||
| type: "Expense", | |||
| status: "Not Submitted", | |||
| remarks: "", | |||
| @@ -33,7 +33,7 @@ const mockClaims: ClaimResult[] = [ | |||
| id: 2, | |||
| created: "2023-11-30", | |||
| name: "Consultancy Project A", | |||
| cost: 4300.00, | |||
| cost: 4300.0, | |||
| type: "Expense", | |||
| status: "Waiting for Approval", | |||
| remarks: "", | |||
| @@ -42,7 +42,7 @@ const mockClaims: ClaimResult[] = [ | |||
| id: 3, | |||
| created: "2023-12-12", | |||
| name: "Construction Project C", | |||
| cost: 3675.00, | |||
| cost: 3675.0, | |||
| type: "Petty Cash", | |||
| status: "Rejected", | |||
| remarks: "Duplicate Claim Form", | |||
| @@ -16,7 +16,7 @@ const AppBar: React.FC<AppBarProps> = ({ avatarImageSrc, profileName }) => { | |||
| <I18nProvider namespaces={["common"]}> | |||
| <MUIAppBar position="sticky" color="default" elevation={4}> | |||
| <Toolbar> | |||
| <NavigationToggle/> | |||
| <NavigationToggle /> | |||
| <Box | |||
| sx={{ flexGrow: 1, display: "flex", justifyContent: "flex-end" }} | |||
| > | |||
| @@ -1,15 +1,26 @@ | |||
| import * as React from 'react'; | |||
| import { Card, CardHeader, CardContent, SxProps, Theme, Tabs, Tab, Box, Typography, Grid, Link} from '@mui/material'; | |||
| import { DataGrid, GridColDef } from '@mui/x-data-grid'; | |||
| import { darken, lighten, styled } from '@mui/material/styles'; | |||
| import { ThemeProvider } from '@emotion/react'; | |||
| import { TAB_THEME } from '@/theme/colorConst'; | |||
| import AllProjectGrid from '../UserWorkspacePage/ProjectGrid'; | |||
| import * as React from "react"; | |||
| import { | |||
| Card, | |||
| CardHeader, | |||
| CardContent, | |||
| SxProps, | |||
| Theme, | |||
| Tabs, | |||
| Tab, | |||
| Box, | |||
| Typography, | |||
| Grid, | |||
| Link, | |||
| } from "@mui/material"; | |||
| import { DataGrid, GridColDef } from "@mui/x-data-grid"; | |||
| import { darken, lighten, styled } from "@mui/material/styles"; | |||
| import { ThemeProvider } from "@emotion/react"; | |||
| import { TAB_THEME } from "@/theme/colorConst"; | |||
| import AllProjectGrid from "../UserWorkspacePage/ProjectGrid"; | |||
| interface AssignedProjectGridProps { | |||
| Title?: string; | |||
| // rows: any[]; | |||
| // rows: any[]; | |||
| // columns: any[]; | |||
| columnWidth?: number; | |||
| Style?: boolean; | |||
| @@ -47,7 +58,7 @@ function CustomTabPanel(props: TabPanelProps) { | |||
| function a11yProps(index: number) { | |||
| return { | |||
| id: `simple-tab-${index}`, | |||
| 'aria-controls': `simple-tabpanel-${index}`, | |||
| "aria-controls": `simple-tabpanel-${index}`, | |||
| }; | |||
| } | |||
| @@ -72,67 +83,117 @@ const AssignedProjectGrid: React.FC<AssignedProjectGridProps> = ({ | |||
| // return { ...row }; | |||
| // }); | |||
| const getBackgroundColor = (color: string, mode: 'light' | 'dark') => | |||
| mode === 'dark' ? darken(color, 0.7) : lighten(color, 0.7); | |||
| const getBackgroundColor = (color: string, mode: "light" | "dark") => | |||
| mode === "dark" ? darken(color, 0.7) : lighten(color, 0.7); | |||
| const getHoverBackgroundColor = (color: string, mode: 'light' | 'dark') => | |||
| mode === 'dark' ? darken(color, 0.6) : lighten(color, 0.6); | |||
| const getHoverBackgroundColor = (color: string, mode: "light" | "dark") => | |||
| mode === "dark" ? darken(color, 0.6) : lighten(color, 0.6); | |||
| const getSelectedBackgroundColor = (color: string, mode: 'light' | 'dark') => | |||
| mode === 'dark' ? darken(color, 0.5) : lighten(color, 0.5); | |||
| const getSelectedBackgroundColor = (color: string, mode: "light" | "dark") => | |||
| mode === "dark" ? darken(color, 0.5) : lighten(color, 0.5); | |||
| const getSelectedHoverBackgroundColor = (color: string, mode: 'light' | 'dark') => | |||
| mode === 'dark' ? darken(color, 0.4) : lighten(color, 0.4); | |||
| const getSelectedHoverBackgroundColor = ( | |||
| color: string, | |||
| mode: "light" | "dark", | |||
| ) => (mode === "dark" ? darken(color, 0.4) : lighten(color, 0.4)); | |||
| const StyledDataGrid = styled(DataGrid)(({ theme }) => ({ | |||
| '& .super-app-theme--Open': { | |||
| backgroundColor: getBackgroundColor(theme.palette.info.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getHoverBackgroundColor(theme.palette.info.main, theme.palette.mode) | |||
| "& .super-app-theme--Open": { | |||
| backgroundColor: getBackgroundColor( | |||
| theme.palette.info.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getHoverBackgroundColor( | |||
| theme.palette.info.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| "&.Mui-selected": { | |||
| backgroundColor: getSelectedBackgroundColor( | |||
| theme.palette.info.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getSelectedHoverBackgroundColor( | |||
| theme.palette.info.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| }, | |||
| '&.Mui-selected': { | |||
| backgroundColor: getSelectedBackgroundColor(theme.palette.info.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getSelectedHoverBackgroundColor(theme.palette.info.main, theme.palette.mode) | |||
| } | |||
| } | |||
| }, | |||
| '& .super-app-theme--finish': { | |||
| backgroundColor: getBackgroundColor(theme.palette.success.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getHoverBackgroundColor(theme.palette.success.main, theme.palette.mode) | |||
| "& .super-app-theme--finish": { | |||
| backgroundColor: getBackgroundColor( | |||
| theme.palette.success.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getHoverBackgroundColor( | |||
| theme.palette.success.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| "&.Mui-selected": { | |||
| backgroundColor: getSelectedBackgroundColor( | |||
| theme.palette.success.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getSelectedHoverBackgroundColor( | |||
| theme.palette.success.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| }, | |||
| '&.Mui-selected': { | |||
| backgroundColor: getSelectedBackgroundColor(theme.palette.success.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getSelectedHoverBackgroundColor(theme.palette.success.main, theme.palette.mode) | |||
| } | |||
| } | |||
| }, | |||
| '& .super-app-theme--danger': { | |||
| backgroundColor: getBackgroundColor(theme.palette.warning.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getHoverBackgroundColor(theme.palette.warning.main, theme.palette.mode) | |||
| "& .super-app-theme--danger": { | |||
| backgroundColor: getBackgroundColor( | |||
| theme.palette.warning.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getHoverBackgroundColor( | |||
| theme.palette.warning.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| "&.Mui-selected": { | |||
| backgroundColor: getSelectedBackgroundColor( | |||
| theme.palette.warning.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getSelectedHoverBackgroundColor( | |||
| theme.palette.warning.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| }, | |||
| '&.Mui-selected': { | |||
| backgroundColor: getSelectedBackgroundColor(theme.palette.warning.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getSelectedHoverBackgroundColor(theme.palette.warning.main, theme.palette.mode) | |||
| } | |||
| } | |||
| }, | |||
| '& .super-app-theme--warning': { | |||
| backgroundColor: getBackgroundColor(theme.palette.error.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getHoverBackgroundColor(theme.palette.error.main, theme.palette.mode) | |||
| "& .super-app-theme--warning": { | |||
| backgroundColor: getBackgroundColor( | |||
| theme.palette.error.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getHoverBackgroundColor( | |||
| theme.palette.error.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| '&.Mui-selected': { | |||
| backgroundColor: getSelectedBackgroundColor(theme.palette.error.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getSelectedHoverBackgroundColor(theme.palette.error.main, theme.palette.mode) | |||
| } | |||
| } | |||
| } | |||
| "&.Mui-selected": { | |||
| backgroundColor: getSelectedBackgroundColor( | |||
| theme.palette.error.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getSelectedHoverBackgroundColor( | |||
| theme.palette.error.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| }, | |||
| }, | |||
| })); | |||
| const [value, setValue] = React.useState(0); | |||
| @@ -142,20 +203,30 @@ const AssignedProjectGrid: React.FC<AssignedProjectGridProps> = ({ | |||
| }; | |||
| return ( | |||
| <div style={{ height: height ?? 400, width: '100%' }}> | |||
| <Card style={{ margin: "auto 20px auto 20px" }}> | |||
| {Title && <CardHeader title={Title} />} | |||
| <CardContent style={{ padding: "0px 24px 24px 24px", display: "flex", alignItems: "center" }}> | |||
| <div> | |||
| <ThemeProvider theme={TAB_THEME}> | |||
| <Box sx={{ borderBottom: 4, borderColor: 'divider' }}> | |||
| <Tabs value={value} onChange={handleChange} aria-label="Manage assigned project"> | |||
| <Tab label="All Projects" {...a11yProps(0)} /> | |||
| <Tab label="On Track" {...a11yProps(1)} /> | |||
| <Tab label="Potential Delay" {...a11yProps(2)} /> | |||
| </Tabs> | |||
| </Box> | |||
| {/* <CustomTabPanel value={value} index={0}> | |||
| <div style={{ height: height ?? 400, width: "100%" }}> | |||
| <Card style={{ margin: "auto 20px auto 20px" }}> | |||
| {Title && <CardHeader title={Title} />} | |||
| <CardContent | |||
| style={{ | |||
| padding: "0px 24px 24px 24px", | |||
| display: "flex", | |||
| alignItems: "center", | |||
| }} | |||
| > | |||
| <div> | |||
| <ThemeProvider theme={TAB_THEME}> | |||
| <Box sx={{ borderBottom: 4, borderColor: "divider" }}> | |||
| <Tabs | |||
| value={value} | |||
| onChange={handleChange} | |||
| aria-label="Manage assigned project" | |||
| > | |||
| <Tab label="All Projects" {...a11yProps(0)} /> | |||
| <Tab label="On Track" {...a11yProps(1)} /> | |||
| <Tab label="Potential Delay" {...a11yProps(2)} /> | |||
| </Tabs> | |||
| </Box> | |||
| {/* <CustomTabPanel value={value} index={0}> | |||
| Item {value} | |||
| </CustomTabPanel> | |||
| <CustomTabPanel value={value} index={1}> | |||
| @@ -164,12 +235,12 @@ const AssignedProjectGrid: React.FC<AssignedProjectGridProps> = ({ | |||
| <CustomTabPanel value={value} index={2}> | |||
| Item {value} | |||
| </CustomTabPanel> */} | |||
| </ThemeProvider> | |||
| </div> | |||
| </CardContent> | |||
| <AllProjectGrid tab={value} /> | |||
| </Card> | |||
| </div> | |||
| </ThemeProvider> | |||
| </div> | |||
| </CardContent> | |||
| <AllProjectGrid tab={value} /> | |||
| </Card> | |||
| </div> | |||
| ); | |||
| }; | |||
| @@ -39,7 +39,12 @@ const ClaimSearch: React.FC<Props> = ({ claims }) => { | |||
| label: t("Status"), | |||
| paramName: "status", | |||
| type: "select", | |||
| options: ["Not Submitted", "Waiting for Approval", "Approved", "Rejected"] | |||
| options: [ | |||
| "Not Submitted", | |||
| "Waiting for Approval", | |||
| "Approved", | |||
| "Rejected", | |||
| ], | |||
| }, | |||
| { | |||
| label: t("Remarks"), | |||
| @@ -80,10 +85,7 @@ const ClaimSearch: React.FC<Props> = ({ claims }) => { | |||
| console.log(query); | |||
| }} | |||
| /> | |||
| <SearchResults<ClaimResult> | |||
| items={filteredClaims} | |||
| columns={columns} | |||
| /> | |||
| <SearchResults<ClaimResult> items={filteredClaims} columns={columns} /> | |||
| </> | |||
| ); | |||
| }; | |||
| @@ -1,129 +1,131 @@ | |||
| "use client"; | |||
| import * as React from "react"; | |||
| import Grid from "@mui/material/Grid"; | |||
| import { useState,useEffect, useMemo } from 'react' | |||
| import { useState, useEffect, useMemo } from "react"; | |||
| import Paper from "@mui/material/Paper"; | |||
| import { TFunction } from "i18next"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import {Card,CardHeader} from '@mui/material'; | |||
| import { Card, CardHeader } from "@mui/material"; | |||
| import CustomSearchForm from "../CustomSearchForm/CustomSearchForm"; | |||
| import CustomDatagrid from '../CustomDatagrid/CustomDatagrid'; | |||
| import ReactApexChart from 'react-apexcharts'; | |||
| import { ApexOptions } from 'apexcharts'; | |||
| import { GridColDef, GridRowSelectionModel} from '@mui/x-data-grid'; | |||
| import ReportProblemIcon from '@mui/icons-material/ReportProblem'; | |||
| import dynamic from 'next/dynamic'; | |||
| import '../../app/global.css'; | |||
| import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; | |||
| import ReactApexChart from "react-apexcharts"; | |||
| import { ApexOptions } from "apexcharts"; | |||
| import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid"; | |||
| import ReportProblemIcon from "@mui/icons-material/ReportProblem"; | |||
| import dynamic from "next/dynamic"; | |||
| import "../../app/global.css"; | |||
| import { AnyARecord, AnyCnameRecord } from "dns"; | |||
| import SearchBox, { Criterion } from "../SearchBox"; | |||
| import ProgressByClientSearch from "@/components/ProgressByClientSearch"; | |||
| import { Suspense } from "react"; | |||
| import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch"; | |||
| import {Input,Label} from "reactstrap"; | |||
| import Select, {components} from 'react-select' | |||
| import { Input, Label } from "reactstrap"; | |||
| import Select, { components } from "react-select"; | |||
| const CompanyTeamCashFlow: React.FC = () => { | |||
| const todayDate = new Date; | |||
| const [selectionModel, setSelectionModel] : any[] = React.useState([]); | |||
| const [cashFlowYear, setCashFlowYear] : any[] = React.useState(todayDate.getFullYear()); | |||
| const todayDate = new Date(); | |||
| const [selectionModel, setSelectionModel]: any[] = React.useState([]); | |||
| const [cashFlowYear, setCashFlowYear]: any[] = React.useState( | |||
| todayDate.getFullYear(), | |||
| ); | |||
| const teamOptions = [ | |||
| { value: 1, label: 'XXX Team' }, | |||
| { value: 2, label: 'YYY Team' }, | |||
| { value: 3, label: 'ZZZ Team' } | |||
| ] | |||
| { value: 1, label: "XXX Team" }, | |||
| { value: 2, label: "YYY Team" }, | |||
| { value: 3, label: "ZZZ Team" }, | |||
| ]; | |||
| const columns = [ | |||
| { | |||
| id: 'projectCode', | |||
| field: 'projectCode', | |||
| id: "projectCode", | |||
| field: "projectCode", | |||
| headerName: "Project Code", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'projectName', | |||
| field: 'projectName', | |||
| }, | |||
| { | |||
| id: "projectName", | |||
| field: "projectName", | |||
| headerName: "Project Name", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'team', | |||
| field: 'team', | |||
| headerName: "Team", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'teamLeader', | |||
| field: 'teamLeader', | |||
| headerName: "Team Leader", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'startDate', | |||
| field: 'startDate', | |||
| headerName: "Start Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'targetEndDate', | |||
| field: 'targetEndDate', | |||
| headerName: "Target End Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'client', | |||
| field: 'client', | |||
| headerName: "Client", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'subsidiary', | |||
| field: 'subsidiary', | |||
| headerName: "Subsidiary", | |||
| flex: 1, | |||
| }, | |||
| }, | |||
| { | |||
| id: "team", | |||
| field: "team", | |||
| headerName: "Team", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "teamLeader", | |||
| field: "teamLeader", | |||
| headerName: "Team Leader", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "startDate", | |||
| field: "startDate", | |||
| headerName: "Start Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "targetEndDate", | |||
| field: "targetEndDate", | |||
| headerName: "Target End Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "client", | |||
| field: "client", | |||
| headerName: "Client", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "subsidiary", | |||
| field: "subsidiary", | |||
| headerName: "Subsidiary", | |||
| flex: 1, | |||
| }, | |||
| ]; | |||
| const ledgerColumns = [ | |||
| { | |||
| id: 'date', | |||
| field: 'date', | |||
| id: "date", | |||
| field: "date", | |||
| headerName: "Date", | |||
| flex: 0.5, | |||
| }, | |||
| { | |||
| id: 'expenditure', | |||
| field: 'expenditure', | |||
| }, | |||
| { | |||
| id: "expenditure", | |||
| field: "expenditure", | |||
| headerName: "Expenditure (HKD)", | |||
| flex: 0.6, | |||
| }, | |||
| { | |||
| id: 'income', | |||
| field: 'income', | |||
| headerName: "Income (HKD)", | |||
| flex: 0.6, | |||
| }, | |||
| { | |||
| id: 'cashFlowBalance', | |||
| field: 'cashFlowBalance', | |||
| headerName: "Cash Flow Balance (HKD)", | |||
| flex: 0.6, | |||
| }, | |||
| { | |||
| id: 'remarks', | |||
| field: 'remarks', | |||
| headerName: "Remarks", | |||
| flex: 1, | |||
| }, | |||
| }, | |||
| { | |||
| id: "income", | |||
| field: "income", | |||
| headerName: "Income (HKD)", | |||
| flex: 0.6, | |||
| }, | |||
| { | |||
| id: "cashFlowBalance", | |||
| field: "cashFlowBalance", | |||
| headerName: "Cash Flow Balance (HKD)", | |||
| flex: 0.6, | |||
| }, | |||
| { | |||
| id: "remarks", | |||
| field: "remarks", | |||
| headerName: "Remarks", | |||
| flex: 1, | |||
| }, | |||
| ]; | |||
| const options: ApexOptions = { | |||
| chart: { | |||
| height: 350, | |||
| type: 'line', | |||
| type: "line", | |||
| }, | |||
| stroke: { | |||
| width: [0, 0, 2, 2] | |||
| width: [0, 0, 2, 2], | |||
| }, | |||
| plotOptions: { | |||
| bar: { | |||
| @@ -132,152 +134,171 @@ const CompanyTeamCashFlow: React.FC = () => { | |||
| }, | |||
| }, | |||
| dataLabels: { | |||
| enabled: false | |||
| enabled: false, | |||
| }, | |||
| xaxis: { | |||
| categories: [ | |||
| 'Q1', | |||
| 'Q2', | |||
| 'Q3', | |||
| 'Q4', | |||
| 'Q5', | |||
| 'Q6', | |||
| 'Q7', | |||
| 'Q8', | |||
| 'Q9', | |||
| 'Q10', | |||
| 'Q11', | |||
| 'Q12', | |||
| "Q1", | |||
| "Q2", | |||
| "Q3", | |||
| "Q4", | |||
| "Q5", | |||
| "Q6", | |||
| "Q7", | |||
| "Q8", | |||
| "Q9", | |||
| "Q10", | |||
| "Q11", | |||
| "Q12", | |||
| ], | |||
| }, | |||
| yaxis: [ | |||
| { | |||
| title: { | |||
| text: 'Monthly Income and Expenditure(HKD)' | |||
| text: "Monthly Income and Expenditure(HKD)", | |||
| }, | |||
| min: 0, | |||
| max: 3700000, | |||
| tickAmount: 5 | |||
| tickAmount: 5, | |||
| }, | |||
| { | |||
| show:false, | |||
| seriesName: 'Monthly_Expenditure', | |||
| show: false, | |||
| seriesName: "Monthly_Expenditure", | |||
| title: { | |||
| text: 'Monthly Expenditure (HKD)' | |||
| text: "Monthly Expenditure (HKD)", | |||
| }, | |||
| min: 0, | |||
| max: 3700000, | |||
| tickAmount: 5 | |||
| tickAmount: 5, | |||
| }, | |||
| { | |||
| seriesName: 'Cumulative_Income', | |||
| seriesName: "Cumulative_Income", | |||
| opposite: true, | |||
| title: { | |||
| text: 'Cumulative Income and Expenditure(HKD)' | |||
| text: "Cumulative Income and Expenditure(HKD)", | |||
| }, | |||
| min: 0, | |||
| max: 21000000, | |||
| tickAmount: 5 | |||
| tickAmount: 5, | |||
| }, | |||
| { | |||
| show:false, | |||
| seriesName: 'Cumulative_Expenditure', | |||
| show: false, | |||
| seriesName: "Cumulative_Expenditure", | |||
| opposite: true, | |||
| title: { | |||
| text: 'Cumulative Expenditure (HKD)' | |||
| text: "Cumulative Expenditure (HKD)", | |||
| }, | |||
| min: 0, | |||
| max: 21000000, | |||
| tickAmount: 5 | |||
| } | |||
| ], | |||
| tickAmount: 5, | |||
| }, | |||
| ], | |||
| grid: { | |||
| borderColor: '#f1f1f1', | |||
| borderColor: "#f1f1f1", | |||
| }, | |||
| annotations: { | |||
| }, | |||
| series:[ | |||
| annotations: {}, | |||
| series: [ | |||
| { | |||
| name:"Monthly_Income", | |||
| type:"column", | |||
| name: "Monthly_Income", | |||
| type: "column", | |||
| color: "#ffde91", | |||
| data:[1280000,170000,3600000,2400000,1000000,1800000,1800000,1200000,1250000,1200000,600000,2400000], | |||
| data: [ | |||
| 1280000, 170000, 3600000, 2400000, 1000000, 1800000, 1800000, 1200000, | |||
| 1250000, 1200000, 600000, 2400000, | |||
| ], | |||
| }, | |||
| { | |||
| name:"Monthly_Expenditure", | |||
| type:"column", | |||
| name: "Monthly_Expenditure", | |||
| type: "column", | |||
| color: "#82b59a", | |||
| data:[1200000,1400000,2000000,1400000,1450000,1800000,1200000,1400000,1200000,1600000,2000000,1600000] | |||
| data: [ | |||
| 1200000, 1400000, 2000000, 1400000, 1450000, 1800000, 1200000, | |||
| 1400000, 1200000, 1600000, 2000000, 1600000, | |||
| ], | |||
| }, | |||
| { | |||
| name:"Cumulative_Income", | |||
| type:"line", | |||
| name: "Cumulative_Income", | |||
| type: "line", | |||
| color: "#EE6D7A", | |||
| data:[500000,3000000,7000000,9000000,10000000,13000000,14000000,16000000,17000000,17500000,18000000,20000000] | |||
| data: [ | |||
| 500000, 3000000, 7000000, 9000000, 10000000, 13000000, 14000000, | |||
| 16000000, 17000000, 17500000, 18000000, 20000000, | |||
| ], | |||
| }, | |||
| { | |||
| name:"Cumulative_Expenditure", | |||
| type:"line", | |||
| name: "Cumulative_Expenditure", | |||
| type: "line", | |||
| color: "#7cd3f2", | |||
| data:[400000,2800000,4000000,5200000,7100000,8000000,10000000,11000000,12100000,14000000,15400000,17200000] | |||
| } | |||
| ] | |||
| data: [ | |||
| 400000, 2800000, 4000000, 5200000, 7100000, 8000000, 10000000, | |||
| 11000000, 12100000, 14000000, 15400000, 17200000, | |||
| ], | |||
| }, | |||
| ], | |||
| }; | |||
| return ( | |||
| <> | |||
| <Grid item sm> | |||
| <div style={{display:"inline-block",width:"100%"}}> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card> | |||
| <CardHeader className="text-slate-500" title="Company and Team Cash Flow by Month"/> | |||
| <div style={{display:"inline-block",width:"99%"}}> | |||
| <div className="inline-block"> | |||
| <Label className="text-slate-500 font-medium ml-6"> | |||
| Period: | |||
| </Label> | |||
| <Input | |||
| id={'cashFlowYear'} | |||
| value={cashFlowYear} | |||
| readOnly={true} | |||
| bsSize="lg" | |||
| className="rounded-md text-base w-12" | |||
| /> | |||
| </div> | |||
| <div className="inline-block ml-1"> | |||
| <button onClick={() => setCashFlowYear(cashFlowYear - 1)} className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base"> | |||
| < | |||
| </button> | |||
| </div> | |||
| <div className="inline-block ml-1"> | |||
| <button onClick={() => setCashFlowYear(cashFlowYear + 1)} className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base"> | |||
| > | |||
| </button> | |||
| </div> | |||
| <div className="inline-block ml-2"> | |||
| <Label className="text-slate-500 font-medium"> | |||
| Team: | |||
| </Label> | |||
| </div> | |||
| <div className="inline-block ml-1 w-60"> | |||
| <Select | |||
| placeholder= "All Team" | |||
| options={teamOptions} | |||
| isClearable={true} | |||
| /> | |||
| </div> | |||
| <ReactApexChart | |||
| options={options} | |||
| series={options.series} | |||
| type="line" | |||
| height="500" | |||
| /> | |||
| </div> | |||
| </Card> | |||
| </Grid> | |||
| </div> | |||
| </Grid> | |||
| <Grid item sm> | |||
| <div style={{ display: "inline-block", width: "100%" }}> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card> | |||
| <CardHeader | |||
| className="text-slate-500" | |||
| title="Company and Team Cash Flow by Month" | |||
| /> | |||
| <div style={{ display: "inline-block", width: "99%" }}> | |||
| <div className="inline-block"> | |||
| <Label className="text-slate-500 font-medium ml-6"> | |||
| Period: | |||
| </Label> | |||
| <Input | |||
| id={"cashFlowYear"} | |||
| value={cashFlowYear} | |||
| readOnly={true} | |||
| bsSize="lg" | |||
| className="rounded-md text-base w-12" | |||
| /> | |||
| </div> | |||
| <div className="inline-block ml-1"> | |||
| <button | |||
| onClick={() => setCashFlowYear(cashFlowYear - 1)} | |||
| className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base" | |||
| > | |||
| < | |||
| </button> | |||
| </div> | |||
| <div className="inline-block ml-1"> | |||
| <button | |||
| onClick={() => setCashFlowYear(cashFlowYear + 1)} | |||
| className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base" | |||
| > | |||
| > | |||
| </button> | |||
| </div> | |||
| <div className="inline-block ml-2"> | |||
| <Label className="text-slate-500 font-medium"> | |||
| Team: | |||
| </Label> | |||
| </div> | |||
| <div className="inline-block ml-1 w-60"> | |||
| <Select | |||
| placeholder="All Team" | |||
| options={teamOptions} | |||
| isClearable={true} | |||
| /> | |||
| </div> | |||
| <ReactApexChart | |||
| options={options} | |||
| series={options.series} | |||
| type="line" | |||
| height="500" | |||
| /> | |||
| </div> | |||
| </Card> | |||
| </Grid> | |||
| </div> | |||
| </Grid> | |||
| </> | |||
| ); | |||
| }; | |||
| @@ -31,18 +31,10 @@ const ClaimDetails: React.FC = () => { | |||
| <Grid item xs={6}> | |||
| <FormControl fullWidth> | |||
| <InputLabel>{t("Related Project")}</InputLabel> | |||
| <Select | |||
| label={t("Project Category")} | |||
| > | |||
| <MenuItem value={"M1001"}> | |||
| {t("M1001")} | |||
| </MenuItem> | |||
| <MenuItem value={"M1301"}> | |||
| {t("M1301")} | |||
| </MenuItem> | |||
| <MenuItem value={"M1354"}> | |||
| {t("M1354")} | |||
| </MenuItem> | |||
| <Select label={t("Project Category")}> | |||
| <MenuItem value={"M1001"}>{t("M1001")}</MenuItem> | |||
| <MenuItem value={"M1301"}>{t("M1301")}</MenuItem> | |||
| <MenuItem value={"M1354"}>{t("M1354")}</MenuItem> | |||
| </Select> | |||
| </FormControl> | |||
| </Grid> | |||
| @@ -50,20 +42,16 @@ const ClaimDetails: React.FC = () => { | |||
| <FormControl fullWidth> | |||
| <InputLabel>{t("Expense Type")}</InputLabel> | |||
| <Select label={t("Team Lead")}> | |||
| <MenuItem value={"Petty Cash"}> | |||
| {"Petty Cash"} | |||
| </MenuItem> | |||
| <MenuItem value={"Expense"}> | |||
| {"Expense"} | |||
| </MenuItem> | |||
| <MenuItem value={"Petty Cash"}>{"Petty Cash"}</MenuItem> | |||
| <MenuItem value={"Expense"}>{"Expense"}</MenuItem> | |||
| </Select> | |||
| </FormControl> | |||
| </Grid> | |||
| </Grid> | |||
| </Box> | |||
| <Card> | |||
| <ClaimInputGrid/> | |||
| <ClaimInputGrid /> | |||
| </Card> | |||
| {/* <CardActions sx={{ justifyContent: "flex-end" }}> | |||
| @@ -8,22 +8,29 @@ import { Suspense } from "react"; | |||
| import Button from "@mui/material/Button"; | |||
| import Stack from "@mui/material/Stack"; | |||
| import Link from "next/link"; | |||
| import { t } from 'i18next'; | |||
| import { Box, Container, Modal, Select, SelectChangeEvent, Typography } from "@mui/material"; | |||
| import { Close } from '@mui/icons-material'; | |||
| import AddIcon from '@mui/icons-material/Add'; | |||
| import EditIcon from '@mui/icons-material/Edit'; | |||
| import DeleteIcon from '@mui/icons-material/DeleteOutlined'; | |||
| import SaveIcon from '@mui/icons-material/Save'; | |||
| import CancelIcon from '@mui/icons-material/Close'; | |||
| import AddPhotoAlternateOutlinedIcon from '@mui/icons-material/AddPhotoAlternateOutlined'; | |||
| import ImageNotSupportedOutlinedIcon from '@mui/icons-material/ImageNotSupportedOutlined'; | |||
| import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; | |||
| import ArrowBackIcon from '@mui/icons-material/ArrowBack'; | |||
| import { t } from "i18next"; | |||
| import { | |||
| Box, | |||
| Container, | |||
| Modal, | |||
| Select, | |||
| SelectChangeEvent, | |||
| Typography, | |||
| } from "@mui/material"; | |||
| import { Close } from "@mui/icons-material"; | |||
| import AddIcon from "@mui/icons-material/Add"; | |||
| import EditIcon from "@mui/icons-material/Edit"; | |||
| import DeleteIcon from "@mui/icons-material/DeleteOutlined"; | |||
| import SaveIcon from "@mui/icons-material/Save"; | |||
| import CancelIcon from "@mui/icons-material/Close"; | |||
| import AddPhotoAlternateOutlinedIcon from "@mui/icons-material/AddPhotoAlternateOutlined"; | |||
| import ImageNotSupportedOutlinedIcon from "@mui/icons-material/ImageNotSupportedOutlined"; | |||
| import ArrowForwardIcon from "@mui/icons-material/ArrowForward"; | |||
| import ArrowBackIcon from "@mui/icons-material/ArrowBack"; | |||
| import Swal from "sweetalert2"; | |||
| import { msg } from "../Swal/CustomAlerts"; | |||
| import React from "react"; | |||
| import { DatePicker } from '@mui/x-date-pickers/DatePicker'; | |||
| import { DatePicker } from "@mui/x-date-pickers/DatePicker"; | |||
| import { | |||
| GridRowsProp, | |||
| GridRowModesModel, | |||
| @@ -39,14 +46,14 @@ import { | |||
| GridRowEditStopReasons, | |||
| GridEditInputCell, | |||
| GridValueSetterParams, | |||
| } from '@mui/x-data-grid'; | |||
| } from "@mui/x-data-grid"; | |||
| import { LocalizationProvider } from "@mui/x-date-pickers"; | |||
| import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; | |||
| import dayjs from "dayjs"; | |||
| import { Props } from "react-intl/src/components/relative"; | |||
| import palette from "@/theme/devias-material-kit/palette"; | |||
| const weekdays = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']; | |||
| const weekdays = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]; | |||
| interface BottomBarProps { | |||
| getCostTotal: () => number; | |||
| @@ -81,58 +88,67 @@ const BottomBar = (props: BottomBarProps) => { | |||
| const handleAddClick = () => { | |||
| const id = newId; | |||
| setNewId(newId - 1); | |||
| setRows((oldRows) => [...oldRows, { id, projectCode: '', task: '', isNew: true }]); | |||
| setRows((oldRows) => [ | |||
| ...oldRows, | |||
| { id, projectCode: "", task: "", isNew: true }, | |||
| ]); | |||
| setRowModesModel((oldModel) => ({ | |||
| ...oldModel, | |||
| [id]: { mode: GridRowModes.Edit, fieldToFocus: 'projectCode' }, | |||
| [id]: { mode: GridRowModes.Edit, fieldToFocus: "projectCode" }, | |||
| })); | |||
| }; | |||
| const totalColDef = { | |||
| flex:1, | |||
| flex: 1, | |||
| // style: {color:getCostTotal('mon')>24?"red":"black"} | |||
| }; | |||
| const TotalCell = ({value}: Props) => { | |||
| const TotalCell = ({ value }: Props) => { | |||
| const [invalid, setInvalid] = useState(false); | |||
| useEffect(()=> { | |||
| useEffect(() => { | |||
| const newInvalid = (value ?? 0) < 0; | |||
| setInvalid(newInvalid); | |||
| }, [value]); | |||
| return ( | |||
| <Box flex={1} style={{color: invalid?"red":"black"}}> | |||
| <Box flex={1} style={{ color: invalid ? "red" : "black" }}> | |||
| $ {value} | |||
| </Box> | |||
| ); | |||
| } | |||
| }; | |||
| return ( | |||
| <div> | |||
| <div style={{ display: 'flex', justifyContent: 'flex', width: '100%' }}> | |||
| <Box flex={1.5} textAlign={'right'} marginRight='4rem'> | |||
| <div style={{ display: "flex", justifyContent: "flex", width: "100%" }}> | |||
| <Box flex={1.5} textAlign={"right"} marginRight="4rem"> | |||
| <b>Total:</b> | |||
| </Box> | |||
| <TotalCell value={getCostTotal()}/> | |||
| <TotalCell value={getCostTotal()} /> | |||
| </div> | |||
| <Button variant="outlined" color="primary" startIcon={<AddIcon />} onClick={handleAddClick} sx={{margin:'20px'}}> | |||
| <Button | |||
| variant="outlined" | |||
| color="primary" | |||
| startIcon={<AddIcon />} | |||
| onClick={handleAddClick} | |||
| sx={{ margin: "20px" }} | |||
| > | |||
| Add record | |||
| </Button> | |||
| </div> | |||
| ); | |||
| } | |||
| }; | |||
| const EditFooter = (props: EditFooterProps) => { | |||
| return ( | |||
| <div style={{ display: 'flex', justifyContent: 'flex', width: '100%' }}> | |||
| <div style={{ display: "flex", justifyContent: "flex", width: "100%" }}> | |||
| <Box flex={1}> | |||
| <b>Total: </b> | |||
| </Box> | |||
| <Box flex={2}>test</Box> | |||
| </div> | |||
| ); | |||
| } | |||
| }; | |||
| interface ClaimInputGridProps { | |||
| onClose?: () => void; | |||
| @@ -144,30 +160,34 @@ const initialRows: GridRowsProp = [ | |||
| date: new Date(), | |||
| description: "Taxi to client office", | |||
| cost: 169.5, | |||
| document: 'taxi_receipt.jpg', | |||
| document: "taxi_receipt.jpg", | |||
| }, | |||
| { | |||
| id: 2, | |||
| date: dayjs().add(-14, 'days').toDate(), | |||
| date: dayjs().add(-14, "days").toDate(), | |||
| description: "MTR fee to Kowloon Bay Office", | |||
| cost: 15.5, | |||
| document: 'octopus_invoice.jpg', | |||
| document: "octopus_invoice.jpg", | |||
| }, | |||
| { | |||
| id: 3, | |||
| date: dayjs().add(-44, 'days').toDate(), | |||
| date: dayjs().add(-44, "days").toDate(), | |||
| description: "Starbucks", | |||
| cost: 504, | |||
| }, | |||
| ]; | |||
| const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||
| const [rows, setRows] = useState(initialRows); | |||
| const [day, setDay] = useState(dayjs()); | |||
| const [rowModesModel, setRowModesModel] = React.useState<GridRowModesModel>({}); | |||
| const [rowModesModel, setRowModesModel] = React.useState<GridRowModesModel>( | |||
| {}, | |||
| ); | |||
| const handleRowEditStop: GridEventListener<'rowEditStop'> = (params, event) => { | |||
| const handleRowEditStop: GridEventListener<"rowEditStop"> = ( | |||
| params, | |||
| event, | |||
| ) => { | |||
| if (params.reason === GridRowEditStopReasons.rowFocusOut) { | |||
| event.defaultMuiPrevented = true; | |||
| } | |||
| @@ -178,7 +198,6 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||
| }; | |||
| const handleSaveClick = (id: GridRowId) => () => { | |||
| setRowModesModel({ ...rowModesModel, [id]: { mode: GridRowModes.View } }); | |||
| }; | |||
| @@ -211,21 +230,21 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||
| const getCostTotal = () => { | |||
| let sum = 0; | |||
| rows.forEach((row) => { | |||
| sum += row['cost']??0; | |||
| sum += row["cost"] ?? 0; | |||
| }); | |||
| return sum; | |||
| }; | |||
| const commonGridColConfig : any = { | |||
| type: 'number', | |||
| const commonGridColConfig: any = { | |||
| type: "number", | |||
| // sortable: false, | |||
| //width: 100, | |||
| flex: 1, | |||
| align: 'left', | |||
| headerAlign: 'left', | |||
| align: "left", | |||
| headerAlign: "left", | |||
| // headerClassName: 'header', | |||
| editable: true, | |||
| renderEditCell: (value : any) => ( | |||
| renderEditCell: (value: any) => ( | |||
| <GridEditInputCell | |||
| {...value} | |||
| inputProps={{ | |||
| @@ -239,26 +258,28 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||
| const columns: GridColDef[] = [ | |||
| { | |||
| field: 'actions', | |||
| type: 'actions', | |||
| headerName: 'Actions', | |||
| field: "actions", | |||
| type: "actions", | |||
| headerName: "Actions", | |||
| width: 100, | |||
| cellClassName: 'actions', | |||
| cellClassName: "actions", | |||
| getActions: ({ id }) => { | |||
| const isInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit; | |||
| if (isInEditMode) { | |||
| return [ | |||
| <GridActionsCellItem | |||
| key={`actions-${id}-save`} | |||
| icon={<SaveIcon />} | |||
| title="Save" | |||
| label="Save" | |||
| sx={{ | |||
| color: 'primary.main', | |||
| color: "primary.main", | |||
| }} | |||
| onClick={handleSaveClick(id)} | |||
| />, | |||
| <GridActionsCellItem | |||
| key={`actions-${id}-cancel`} | |||
| icon={<CancelIcon />} | |||
| title="Cancel" | |||
| label="Cancel" | |||
| @@ -271,6 +292,7 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||
| return [ | |||
| <GridActionsCellItem | |||
| key={`actions-${id}-edit`} | |||
| icon={<EditIcon />} | |||
| title="Edit" | |||
| label="Edit" | |||
| @@ -279,74 +301,80 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||
| color="inherit" | |||
| />, | |||
| <GridActionsCellItem | |||
| key={`actions-${id}-delete`} | |||
| title="Delete" | |||
| label="Delete" | |||
| icon={<DeleteIcon />} | |||
| onClick={handleDeleteClick(id)} | |||
| sx={{color:"red"}} | |||
| sx={{ color: "red" }} | |||
| />, | |||
| ]; | |||
| }, | |||
| }, | |||
| { | |||
| field: 'date', | |||
| headerName: 'Invoice Date', | |||
| field: "date", | |||
| headerName: "Invoice Date", | |||
| // width: 220, | |||
| flex: 1, | |||
| editable: true, | |||
| type: 'date', | |||
| type: "date", | |||
| }, | |||
| { | |||
| field: 'description', | |||
| headerName: 'Description', | |||
| field: "description", | |||
| headerName: "Description", | |||
| // width: 220, | |||
| flex: 2, | |||
| editable: true, | |||
| type: 'string', | |||
| type: "string", | |||
| }, | |||
| { | |||
| field: 'cost', | |||
| headerName: 'Cost (HKD)', | |||
| field: "cost", | |||
| headerName: "Cost (HKD)", | |||
| editable: true, | |||
| type: 'number', | |||
| type: "number", | |||
| valueFormatter: (params) => { | |||
| return `$ ${params.value??0}`; | |||
| return `$ ${params.value ?? 0}`; | |||
| }, | |||
| }, | |||
| { | |||
| field: 'document', | |||
| headerName: 'Supporting Document', | |||
| type: 'string', | |||
| field: "document", | |||
| headerName: "Supporting Document", | |||
| type: "string", | |||
| editable: true, | |||
| flex: 2, | |||
| renderCell: (params) => { | |||
| return params.value? | |||
| ( | |||
| return params.value ? ( | |||
| <span> | |||
| <a href="" target="_blank" rel="noopener noreferrer"> | |||
| {params.value} | |||
| </a> | |||
| </span> | |||
| ) : | |||
| (<span style={{color: palette.text.disabled}}>No Documents</span>) | |||
| ) : ( | |||
| <span style={{ color: palette.text.disabled }}>No Documents</span> | |||
| ); | |||
| }, | |||
| renderEditCell: (params) => { | |||
| return params.value? | |||
| ( | |||
| return params.value ? ( | |||
| <span> | |||
| <a href="" target="_blank" rel="noopener noreferrer"> | |||
| {params.value} | |||
| </a> | |||
| <Button title='Remove Document' onClick={(event) => console.log(event)}> | |||
| <ImageNotSupportedOutlinedIcon sx={{fontSize: '25px', color:"red"}}/> | |||
| </Button> | |||
| <a href="" target="_blank" rel="noopener noreferrer"> | |||
| {params.value} | |||
| </a> | |||
| <Button | |||
| title="Remove Document" | |||
| onClick={(event) => console.log(event)} | |||
| > | |||
| <ImageNotSupportedOutlinedIcon | |||
| sx={{ fontSize: "25px", color: "red" }} | |||
| /> | |||
| </Button> | |||
| </span> | |||
| ) : ( | |||
| <Button title='Add Document'> | |||
| <AddPhotoAlternateOutlinedIcon sx={{fontSize: '25px', color:"green"}}/> | |||
| <Button title="Add Document"> | |||
| <AddPhotoAlternateOutlinedIcon | |||
| sx={{ fontSize: "25px", color: "green" }} | |||
| /> | |||
| </Button> | |||
| ) | |||
| ); | |||
| }, | |||
| }, | |||
| ]; | |||
| @@ -355,27 +383,27 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||
| <Box | |||
| sx={{ | |||
| // marginBottom: '-5px', | |||
| display: 'flex', | |||
| 'flex-direction': 'column', | |||
| display: "flex", | |||
| "flex-direction": "column", | |||
| // 'justify-content': 'flex-end', | |||
| height: '100%',//'25rem', | |||
| width: '100%', | |||
| '& .actions': { | |||
| color: 'text.secondary', | |||
| height: "100%", //'25rem', | |||
| width: "100%", | |||
| "& .actions": { | |||
| color: "text.secondary", | |||
| }, | |||
| '& .header': { | |||
| "& .header": { | |||
| backgroundColor: "#F8F9FA", | |||
| // border: 1, | |||
| // 'border-width': '1px', | |||
| // 'border-color': 'grey', | |||
| }, | |||
| '& .textPrimary': { | |||
| color: 'text.primary', | |||
| "& .textPrimary": { | |||
| color: "text.primary", | |||
| }, | |||
| }} | |||
| > | |||
| <DataGrid | |||
| sx={{flex:1}} | |||
| sx={{ flex: 1 }} | |||
| rows={rows} | |||
| columns={columns} | |||
| editMode="row" | |||
| @@ -386,22 +414,29 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||
| disableRowSelectionOnClick={true} | |||
| disableColumnMenu={true} | |||
| hideFooterPagination={true} | |||
| slots={{ | |||
| // footer: EditFooter, | |||
| }} | |||
| slotProps={{ | |||
| // footer: { setDay, setRows, setRowModesModel }, | |||
| }} | |||
| slots={ | |||
| { | |||
| // footer: EditFooter, | |||
| } | |||
| } | |||
| slotProps={ | |||
| { | |||
| // footer: { setDay, setRows, setRowModesModel }, | |||
| } | |||
| } | |||
| initialState={{ | |||
| pagination: { paginationModel: { pageSize: 100 } }, | |||
| }} | |||
| /> | |||
| <BottomBar getCostTotal={getCostTotal} setRows={setRows} setRowModesModel={setRowModesModel} | |||
| // sx={{flex:2}} | |||
| <BottomBar | |||
| getCostTotal={getCostTotal} | |||
| setRows={setRows} | |||
| setRowModesModel={setRowModesModel} | |||
| // sx={{flex:2}} | |||
| /> | |||
| </Box> | |||
| ); | |||
| } | |||
| }; | |||
| export default ClaimInputGrid; | |||
| @@ -1,11 +1,18 @@ | |||
| import * as React from 'react'; | |||
| import { Card, CardHeader, CardContent, SxProps, Theme, Grid } from '@mui/material'; | |||
| import { DataGrid, GridColDef } from '@mui/x-data-grid'; | |||
| import { darken, lighten, styled } from '@mui/material/styles'; | |||
| import { PROJECT_CARD_STYLE } from '@/theme/colorConst'; | |||
| import { useRef, useEffect, useState } from 'react'; | |||
| import Swal from 'sweetalert2'; | |||
| import styledcmp from 'styled-components'; | |||
| import * as React from "react"; | |||
| import { | |||
| Card, | |||
| CardHeader, | |||
| CardContent, | |||
| SxProps, | |||
| Theme, | |||
| Grid, | |||
| } from "@mui/material"; | |||
| import { DataGrid, GridColDef } from "@mui/x-data-grid"; | |||
| import { darken, lighten, styled } from "@mui/material/styles"; | |||
| import { PROJECT_CARD_STYLE } from "@/theme/colorConst"; | |||
| import { useRef, useEffect, useState } from "react"; | |||
| import Swal from "sweetalert2"; | |||
| import styledcmp from "styled-components"; | |||
| const CardWrapper = styledcmp.div` | |||
| /* Styles for the card when not hovered */ | |||
| @@ -23,7 +30,7 @@ const CardWrapper = styledcmp.div` | |||
| interface CustomCardGridProps { | |||
| Title?: string; | |||
| cardsPerRow?: number; | |||
| rows?: any[]; | |||
| rows?: any[]; | |||
| columns?: any[]; | |||
| items: any[]; | |||
| columnWidth?: number; | |||
| @@ -46,73 +53,124 @@ const CustomCardGrid: React.FC<CustomCardGridProps> = ({ | |||
| dataGridHeight, | |||
| ...props | |||
| }) => { | |||
| const getBackgroundColor = (color: string, mode: 'light' | 'dark') => | |||
| mode === 'dark' ? darken(color, 0.7) : lighten(color, 0.7); | |||
| const getBackgroundColor = (color: string, mode: "light" | "dark") => | |||
| mode === "dark" ? darken(color, 0.7) : lighten(color, 0.7); | |||
| const getHoverBackgroundColor = (color: string, mode: 'light' | 'dark') => | |||
| mode === 'dark' ? darken(color, 0.6) : lighten(color, 0.6); | |||
| const getHoverBackgroundColor = (color: string, mode: "light" | "dark") => | |||
| mode === "dark" ? darken(color, 0.6) : lighten(color, 0.6); | |||
| const getSelectedBackgroundColor = (color: string, mode: 'light' | 'dark') => | |||
| mode === 'dark' ? darken(color, 0.5) : lighten(color, 0.5); | |||
| const getSelectedBackgroundColor = (color: string, mode: "light" | "dark") => | |||
| mode === "dark" ? darken(color, 0.5) : lighten(color, 0.5); | |||
| const getSelectedHoverBackgroundColor = (color: string, mode: 'light' | 'dark') => | |||
| mode === 'dark' ? darken(color, 0.4) : lighten(color, 0.4); | |||
| const getSelectedHoverBackgroundColor = ( | |||
| color: string, | |||
| mode: "light" | "dark", | |||
| ) => (mode === "dark" ? darken(color, 0.4) : lighten(color, 0.4)); | |||
| const StyledCard = styled(Card)(({ theme }) => ({ | |||
| '& .super-app-theme--Open': { | |||
| backgroundColor: getBackgroundColor(theme.palette.info.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getHoverBackgroundColor(theme.palette.info.main, theme.palette.mode) | |||
| "& .super-app-theme--Open": { | |||
| backgroundColor: getBackgroundColor( | |||
| theme.palette.info.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getHoverBackgroundColor( | |||
| theme.palette.info.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| "&.Mui-selected": { | |||
| backgroundColor: getSelectedBackgroundColor( | |||
| theme.palette.info.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getSelectedHoverBackgroundColor( | |||
| theme.palette.info.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| }, | |||
| '&.Mui-selected': { | |||
| backgroundColor: getSelectedBackgroundColor(theme.palette.info.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getSelectedHoverBackgroundColor(theme.palette.info.main, theme.palette.mode) | |||
| } | |||
| } | |||
| }, | |||
| '& .super-app-theme--finish': { | |||
| backgroundColor: getBackgroundColor(theme.palette.success.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getHoverBackgroundColor(theme.palette.success.main, theme.palette.mode) | |||
| "& .super-app-theme--finish": { | |||
| backgroundColor: getBackgroundColor( | |||
| theme.palette.success.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getHoverBackgroundColor( | |||
| theme.palette.success.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| "&.Mui-selected": { | |||
| backgroundColor: getSelectedBackgroundColor( | |||
| theme.palette.success.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getSelectedHoverBackgroundColor( | |||
| theme.palette.success.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| }, | |||
| '&.Mui-selected': { | |||
| backgroundColor: getSelectedBackgroundColor(theme.palette.success.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getSelectedHoverBackgroundColor(theme.palette.success.main, theme.palette.mode) | |||
| } | |||
| } | |||
| }, | |||
| '& .super-app-theme--danger': { | |||
| backgroundColor: getBackgroundColor(theme.palette.warning.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getHoverBackgroundColor(theme.palette.warning.main, theme.palette.mode) | |||
| "& .super-app-theme--danger": { | |||
| backgroundColor: getBackgroundColor( | |||
| theme.palette.warning.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getHoverBackgroundColor( | |||
| theme.palette.warning.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| "&.Mui-selected": { | |||
| backgroundColor: getSelectedBackgroundColor( | |||
| theme.palette.warning.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getSelectedHoverBackgroundColor( | |||
| theme.palette.warning.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| }, | |||
| '&.Mui-selected': { | |||
| backgroundColor: getSelectedBackgroundColor(theme.palette.warning.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getSelectedHoverBackgroundColor(theme.palette.warning.main, theme.palette.mode) | |||
| } | |||
| } | |||
| }, | |||
| '& .super-app-theme--warning': { | |||
| backgroundColor: getBackgroundColor(theme.palette.error.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getHoverBackgroundColor(theme.palette.error.main, theme.palette.mode) | |||
| "& .super-app-theme--warning": { | |||
| backgroundColor: getBackgroundColor( | |||
| theme.palette.error.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getHoverBackgroundColor( | |||
| theme.palette.error.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| '&.Mui-selected': { | |||
| backgroundColor: getSelectedBackgroundColor(theme.palette.error.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getSelectedHoverBackgroundColor(theme.palette.error.main, theme.palette.mode) | |||
| } | |||
| } | |||
| } | |||
| "&.Mui-selected": { | |||
| backgroundColor: getSelectedBackgroundColor( | |||
| theme.palette.error.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getSelectedHoverBackgroundColor( | |||
| theme.palette.error.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| }, | |||
| }, | |||
| })); | |||
| const CardItem = (item: any) => { | |||
| const cardItem = item.item as Record<string, string>; | |||
| return props.cardStyle?? ( | |||
| // <Grid item sx={{ m: 3 }}> | |||
| return ( | |||
| props.cardStyle ?? ( | |||
| // <Grid item sx={{ m: 3 }}> | |||
| <StyledCard style={PROJECT_CARD_STYLE}> | |||
| <CardContent> | |||
| {Object.keys(cardItem).map((key) => ( | |||
| @@ -122,28 +180,36 @@ const CustomCardGrid: React.FC<CustomCardGridProps> = ({ | |||
| ))} | |||
| </CardContent> | |||
| </StyledCard> | |||
| // </Grid> | |||
| // </Grid> | |||
| ) | |||
| ); | |||
| }; | |||
| const containerRef = useRef<HTMLDivElement>(null!); | |||
| const [cardMargin, setCardMargin] = useState(1.5); | |||
| useEffect(() => { | |||
| console.log(CardItem); | |||
| const resizeHandler = () => { | |||
| const containerWidth = containerRef.current.offsetWidth; | |||
| const cardCount = items.length; | |||
| const rootSize = parseFloat(getComputedStyle(document.documentElement).fontSize); | |||
| setCardMargin((containerWidth - cardsPerRow * (rootSize * parseInt(PROJECT_CARD_STYLE.width.slice(0, -3),10))) /(2 * cardsPerRow)); | |||
| const rootSize = parseFloat( | |||
| getComputedStyle(document.documentElement).fontSize, | |||
| ); | |||
| setCardMargin( | |||
| (containerWidth - | |||
| cardsPerRow * | |||
| (rootSize * parseInt(PROJECT_CARD_STYLE.width.slice(0, -3), 10))) / | |||
| (2 * cardsPerRow), | |||
| ); | |||
| // Set the cardMargin value using style={{margin: `${cardMargin}px`, ...PROJECT_CARD_STYLE}} | |||
| }; | |||
| window.addEventListener('resize', resizeHandler); | |||
| window.addEventListener("resize", resizeHandler); | |||
| resizeHandler(); // Initial calculation | |||
| // Swal.fire({ | |||
| // title: 'Error! ', | |||
| // text: `Card Count is ${items.length}`, | |||
| @@ -152,16 +218,19 @@ const CustomCardGrid: React.FC<CustomCardGridProps> = ({ | |||
| // }) | |||
| return () => { | |||
| window.removeEventListener('resize', resizeHandler); | |||
| window.removeEventListener("resize", resizeHandler); | |||
| }; | |||
| }, [items]); | |||
| return ( | |||
| <div ref={containerRef} style={{display:'flex', flexWrap:'wrap', alignItems: 'flex-start'}}> | |||
| <div | |||
| ref={containerRef} | |||
| style={{ display: "flex", flexWrap: "wrap", alignItems: "flex-start" }} | |||
| > | |||
| {/* <p>width is {containerRef.current == null? "idk":containerRef.current.offsetWidth}, margin is {cardMargin}</p> */} | |||
| {items.map((item, index) => ( | |||
| <div key={index}> | |||
| {props.cardStyle? props.cardStyle(item) : <CardItem item={item}/>} | |||
| {props.cardStyle ? props.cardStyle(item) : <CardItem item={item} />} | |||
| </div> | |||
| ))} | |||
| </div> | |||
| @@ -1,13 +1,13 @@ | |||
| "use client"; | |||
| import * as React from 'react'; | |||
| import { Card, CardHeader, CardContent, SxProps, Theme } from '@mui/material'; | |||
| import { DataGrid, GridColDef, GridRowSelectionModel} from '@mui/x-data-grid'; | |||
| import { darken, lighten, styled } from '@mui/material/styles'; | |||
| import { useState } from 'react' | |||
| import * as React from "react"; | |||
| import { Card, CardHeader, CardContent, SxProps, Theme } from "@mui/material"; | |||
| import { DataGrid, GridColDef, GridRowSelectionModel } from "@mui/x-data-grid"; | |||
| import { darken, lighten, styled } from "@mui/material/styles"; | |||
| import { useState } from "react"; | |||
| interface CustomDatagridProps { | |||
| Title?: string; | |||
| rows: any[]; | |||
| rows: any[]; | |||
| columns: any[]; | |||
| columnWidth?: number; | |||
| Style?: boolean; | |||
| @@ -15,7 +15,9 @@ interface CustomDatagridProps { | |||
| dataGridHeight?: number; | |||
| [key: string]: any; | |||
| checkboxSelection?: boolean; | |||
| onRowSelectionModelChange?: (newSelectionModel: GridRowSelectionModel) => void; | |||
| onRowSelectionModelChange?: ( | |||
| newSelectionModel: GridRowSelectionModel, | |||
| ) => void; | |||
| selectionModel?: any; | |||
| } | |||
| @@ -44,200 +46,262 @@ const CustomDatagrid: React.FC<CustomDatagridProps> = ({ | |||
| }); | |||
| // Event handler to be called when the selection changes | |||
| const handleSelectionModelChange = (newSelectionModel: GridRowSelectionModel) => { | |||
| const handleSelectionModelChange = ( | |||
| newSelectionModel: GridRowSelectionModel, | |||
| ) => { | |||
| // setSelectionModel(newSelectionModel); | |||
| // To log selected row data, filter rows based on the new selection model | |||
| const selectedRowsData = rows.filter((row) => | |||
| newSelectionModel.includes(row.id) | |||
| newSelectionModel.includes(row.id), | |||
| ); | |||
| console.log(selectedRowsData); | |||
| }; | |||
| const getBackgroundColor = (color: string, mode: 'light' | 'dark') => | |||
| mode === 'dark' ? darken(color, 0.7) : lighten(color, 0.7); | |||
| const getBackgroundColor = (color: string, mode: "light" | "dark") => | |||
| mode === "dark" ? darken(color, 0.7) : lighten(color, 0.7); | |||
| const getHoverBackgroundColor = (color: string, mode: 'light' | 'dark') => | |||
| mode === 'dark' ? darken(color, 0.6) : lighten(color, 0.6); | |||
| const getHoverBackgroundColor = (color: string, mode: "light" | "dark") => | |||
| mode === "dark" ? darken(color, 0.6) : lighten(color, 0.6); | |||
| const getSelectedBackgroundColor = (color: string, mode: 'light' | 'dark') => | |||
| mode === 'dark' ? darken(color, 0.5) : lighten(color, 0.5); | |||
| const getSelectedBackgroundColor = (color: string, mode: "light" | "dark") => | |||
| mode === "dark" ? darken(color, 0.5) : lighten(color, 0.5); | |||
| const getSelectedHoverBackgroundColor = (color: string, mode: 'light' | 'dark') => | |||
| mode === 'dark' ? darken(color, 0.4) : lighten(color, 0.4); | |||
| const getSelectedHoverBackgroundColor = ( | |||
| color: string, | |||
| mode: "light" | "dark", | |||
| ) => (mode === "dark" ? darken(color, 0.4) : lighten(color, 0.4)); | |||
| const StyledDataGrid = styled(DataGrid)(({ theme }) => ({ | |||
| '& .super-app-theme--Open': { | |||
| backgroundColor: getBackgroundColor(theme.palette.info.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getHoverBackgroundColor(theme.palette.info.main, theme.palette.mode) | |||
| "& .super-app-theme--Open": { | |||
| backgroundColor: getBackgroundColor( | |||
| theme.palette.info.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getHoverBackgroundColor( | |||
| theme.palette.info.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| "&.Mui-selected": { | |||
| backgroundColor: getSelectedBackgroundColor( | |||
| theme.palette.info.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getSelectedHoverBackgroundColor( | |||
| theme.palette.info.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| }, | |||
| '&.Mui-selected': { | |||
| backgroundColor: getSelectedBackgroundColor(theme.palette.info.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getSelectedHoverBackgroundColor(theme.palette.info.main, theme.palette.mode) | |||
| } | |||
| } | |||
| }, | |||
| '& .super-app-theme--finish': { | |||
| backgroundColor: getBackgroundColor(theme.palette.success.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getHoverBackgroundColor(theme.palette.success.main, theme.palette.mode) | |||
| "& .super-app-theme--finish": { | |||
| backgroundColor: getBackgroundColor( | |||
| theme.palette.success.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getHoverBackgroundColor( | |||
| theme.palette.success.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| "&.Mui-selected": { | |||
| backgroundColor: getSelectedBackgroundColor( | |||
| theme.palette.success.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getSelectedHoverBackgroundColor( | |||
| theme.palette.success.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| }, | |||
| '&.Mui-selected': { | |||
| backgroundColor: getSelectedBackgroundColor(theme.palette.success.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getSelectedHoverBackgroundColor(theme.palette.success.main, theme.palette.mode) | |||
| } | |||
| } | |||
| }, | |||
| '& .super-app-theme--danger': { | |||
| backgroundColor: getBackgroundColor(theme.palette.warning.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getHoverBackgroundColor(theme.palette.warning.main, theme.palette.mode) | |||
| "& .super-app-theme--danger": { | |||
| backgroundColor: getBackgroundColor( | |||
| theme.palette.warning.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getHoverBackgroundColor( | |||
| theme.palette.warning.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| "&.Mui-selected": { | |||
| backgroundColor: getSelectedBackgroundColor( | |||
| theme.palette.warning.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getSelectedHoverBackgroundColor( | |||
| theme.palette.warning.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| }, | |||
| '&.Mui-selected': { | |||
| backgroundColor: getSelectedBackgroundColor(theme.palette.warning.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getSelectedHoverBackgroundColor(theme.palette.warning.main, theme.palette.mode) | |||
| } | |||
| } | |||
| }, | |||
| '& .super-app-theme--warning': { | |||
| backgroundColor: getBackgroundColor(theme.palette.error.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getHoverBackgroundColor(theme.palette.error.main, theme.palette.mode) | |||
| "& .super-app-theme--warning": { | |||
| backgroundColor: getBackgroundColor( | |||
| theme.palette.error.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getHoverBackgroundColor( | |||
| theme.palette.error.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| '&.Mui-selected': { | |||
| backgroundColor: getSelectedBackgroundColor(theme.palette.error.main, theme.palette.mode), | |||
| '&:hover': { | |||
| backgroundColor: getSelectedHoverBackgroundColor(theme.palette.error.main, theme.palette.mode) | |||
| } | |||
| } | |||
| } | |||
| "&.Mui-selected": { | |||
| backgroundColor: getSelectedBackgroundColor( | |||
| theme.palette.error.main, | |||
| theme.palette.mode, | |||
| ), | |||
| "&:hover": { | |||
| backgroundColor: getSelectedHoverBackgroundColor( | |||
| theme.palette.error.main, | |||
| theme.palette.mode, | |||
| ), | |||
| }, | |||
| }, | |||
| }, | |||
| })); | |||
| return ( | |||
| <div className="mt-5 mb-5" style={{ height: dataGridHeight ?? 400, width: '100%'}}> | |||
| <div | |||
| className="mt-5 mb-5" | |||
| style={{ height: dataGridHeight ?? 400, width: "100%" }} | |||
| > | |||
| {Title ? ( | |||
| <Card style={{marginRight:10}}> | |||
| {Title && <CardHeader className="text-slate-500" title={Title} />} | |||
| <CardContent style={{ display: "flex", alignItems: "center", justifyContent: "center", marginTop:-20 }}> | |||
| {Style ? ( | |||
| <StyledDataGrid | |||
| rows={rowsWithDefaultValues} | |||
| columns={modifiedColumns} | |||
| editMode="row" | |||
| checkboxSelection={checkboxSelection} | |||
| onRowSelectionModelChange={onRowSelectionModelChange} | |||
| initialState={{ | |||
| pagination: { paginationModel: { pageSize: 10 } }, | |||
| }} | |||
| className="customDataGrid" | |||
| sx={{ | |||
| boxShadow: 1, | |||
| border: 0, | |||
| borderColor: 'primary.light', | |||
| '& .MuiDataGrid-cell:hover': { | |||
| color: 'primary.main' | |||
| }, | |||
| height: dataGridHeight ?? 400, | |||
| '& .MuiDataGrid-root': { | |||
| overflow: 'auto', | |||
| }, | |||
| '& .MuiDataGrid-columnHeaderTitle': { | |||
| fontWeight: 'bold', | |||
| }, | |||
| ...sx | |||
| }} | |||
| {...props} | |||
| /> | |||
| ) : ( | |||
| <DataGrid | |||
| rows={rowsWithDefaultValues} | |||
| columns={modifiedColumns} | |||
| editMode="row" | |||
| checkboxSelection={checkboxSelection} | |||
| onRowSelectionModelChange={onRowSelectionModelChange} | |||
| initialState={{ | |||
| pagination: { paginationModel: { pageSize: 10 } }, | |||
| }} | |||
| className="customDataGrid" | |||
| sx={{ | |||
| boxShadow: 2, | |||
| border: 2, | |||
| borderColor: 'primary.light', | |||
| '& .MuiDataGrid-cell:hover': { | |||
| color: 'primary.main' | |||
| }, | |||
| height: 300, | |||
| '& .MuiDataGrid-root': { | |||
| overflow: 'auto', | |||
| }, | |||
| ...sx | |||
| }} | |||
| {...props} | |||
| /> | |||
| )} | |||
| <Card style={{ marginRight: 10 }}> | |||
| {Title && <CardHeader className="text-slate-500" title={Title} />} | |||
| <CardContent | |||
| style={{ | |||
| display: "flex", | |||
| alignItems: "center", | |||
| justifyContent: "center", | |||
| marginTop: -20, | |||
| }} | |||
| > | |||
| {Style ? ( | |||
| <StyledDataGrid | |||
| rows={rowsWithDefaultValues} | |||
| columns={modifiedColumns} | |||
| editMode="row" | |||
| checkboxSelection={checkboxSelection} | |||
| onRowSelectionModelChange={onRowSelectionModelChange} | |||
| initialState={{ | |||
| pagination: { paginationModel: { pageSize: 10 } }, | |||
| }} | |||
| className="customDataGrid" | |||
| sx={{ | |||
| boxShadow: 1, | |||
| border: 0, | |||
| borderColor: "primary.light", | |||
| "& .MuiDataGrid-cell:hover": { | |||
| color: "primary.main", | |||
| }, | |||
| height: dataGridHeight ?? 400, | |||
| "& .MuiDataGrid-root": { | |||
| overflow: "auto", | |||
| }, | |||
| "& .MuiDataGrid-columnHeaderTitle": { | |||
| fontWeight: "bold", | |||
| }, | |||
| ...sx, | |||
| }} | |||
| {...props} | |||
| /> | |||
| ) : ( | |||
| <DataGrid | |||
| rows={rowsWithDefaultValues} | |||
| columns={modifiedColumns} | |||
| editMode="row" | |||
| checkboxSelection={checkboxSelection} | |||
| onRowSelectionModelChange={onRowSelectionModelChange} | |||
| initialState={{ | |||
| pagination: { paginationModel: { pageSize: 10 } }, | |||
| }} | |||
| className="customDataGrid" | |||
| sx={{ | |||
| boxShadow: 2, | |||
| border: 2, | |||
| borderColor: "primary.light", | |||
| "& .MuiDataGrid-cell:hover": { | |||
| color: "primary.main", | |||
| }, | |||
| height: 300, | |||
| "& .MuiDataGrid-root": { | |||
| overflow: "auto", | |||
| }, | |||
| ...sx, | |||
| }} | |||
| {...props} | |||
| /> | |||
| )} | |||
| </CardContent> | |||
| </Card>) | |||
| : (Style ? ( | |||
| <StyledDataGrid | |||
| rows={rowsWithDefaultValues} | |||
| columns={modifiedColumns} | |||
| editMode="row" | |||
| checkboxSelection={checkboxSelection} | |||
| onRowSelectionModelChange={onRowSelectionModelChange} | |||
| style={{marginRight:20}} | |||
| initialState={{ | |||
| pagination: { paginationModel: { pageSize: 10 } }, | |||
| }} | |||
| className="customDataGrid" | |||
| sx={{ | |||
| boxShadow: 1, | |||
| border: 0, | |||
| borderColor: 'primary.light', | |||
| '& .MuiDataGrid-cell:hover': { | |||
| color: 'primary.main' | |||
| }, | |||
| height: dataGridHeight ?? 400, | |||
| '& .MuiDataGrid-root': { | |||
| overflow: 'auto', | |||
| }, | |||
| '& .MuiDataGrid-columnHeaderTitle': { | |||
| fontWeight: 'bold', | |||
| }, | |||
| ...sx | |||
| }} | |||
| {...props} | |||
| /> | |||
| ) : ( | |||
| <DataGrid | |||
| rows={rowsWithDefaultValues} | |||
| columns={modifiedColumns} | |||
| editMode="row" | |||
| style={{marginRight:0}} | |||
| checkboxSelection={checkboxSelection} | |||
| onRowSelectionModelChange={onRowSelectionModelChange} | |||
| initialState={{ | |||
| pagination: { paginationModel: { pageSize: 10 } }, | |||
| }} | |||
| className="customDataGrid" | |||
| sx={{ | |||
| boxShadow: 2, | |||
| border: 2, | |||
| borderColor: 'primary.light', | |||
| '& .MuiDataGrid-cell:hover': { | |||
| color: 'primary.main' | |||
| }, | |||
| height: 300, | |||
| '& .MuiDataGrid-root': { | |||
| overflow: 'auto', | |||
| }, | |||
| ...sx | |||
| }} | |||
| {...props} | |||
| /> | |||
| ))} | |||
| </Card> | |||
| ) : Style ? ( | |||
| <StyledDataGrid | |||
| rows={rowsWithDefaultValues} | |||
| columns={modifiedColumns} | |||
| editMode="row" | |||
| checkboxSelection={checkboxSelection} | |||
| onRowSelectionModelChange={onRowSelectionModelChange} | |||
| style={{ marginRight: 20 }} | |||
| initialState={{ | |||
| pagination: { paginationModel: { pageSize: 10 } }, | |||
| }} | |||
| className="customDataGrid" | |||
| sx={{ | |||
| boxShadow: 1, | |||
| border: 0, | |||
| borderColor: "primary.light", | |||
| "& .MuiDataGrid-cell:hover": { | |||
| color: "primary.main", | |||
| }, | |||
| height: dataGridHeight ?? 400, | |||
| "& .MuiDataGrid-root": { | |||
| overflow: "auto", | |||
| }, | |||
| "& .MuiDataGrid-columnHeaderTitle": { | |||
| fontWeight: "bold", | |||
| }, | |||
| ...sx, | |||
| }} | |||
| {...props} | |||
| /> | |||
| ) : ( | |||
| <DataGrid | |||
| rows={rowsWithDefaultValues} | |||
| columns={modifiedColumns} | |||
| editMode="row" | |||
| style={{ marginRight: 0 }} | |||
| checkboxSelection={checkboxSelection} | |||
| onRowSelectionModelChange={onRowSelectionModelChange} | |||
| initialState={{ | |||
| pagination: { paginationModel: { pageSize: 10 } }, | |||
| }} | |||
| className="customDataGrid" | |||
| sx={{ | |||
| boxShadow: 2, | |||
| border: 2, | |||
| borderColor: "primary.light", | |||
| "& .MuiDataGrid-cell:hover": { | |||
| color: "primary.main", | |||
| }, | |||
| height: 300, | |||
| "& .MuiDataGrid-root": { | |||
| overflow: "auto", | |||
| }, | |||
| ...sx, | |||
| }} | |||
| {...props} | |||
| /> | |||
| )} | |||
| </div> | |||
| ); | |||
| }; | |||
| @@ -1,11 +1,21 @@ | |||
| import * as React from 'react'; | |||
| import { Card, CardHeader, CardContent, SxProps, Theme, Grid, Modal, Typography, Button } from '@mui/material'; | |||
| import { DataGrid, GridColDef } from '@mui/x-data-grid'; | |||
| import { darken, lighten, styled } from '@mui/material/styles'; | |||
| import { PROJECT_MODAL_STYLE } from '@/theme/colorConst'; | |||
| import { useRef, useEffect, useState } from 'react'; | |||
| import Swal from 'sweetalert2'; | |||
| import styledcmp from 'styled-components'; | |||
| import * as React from "react"; | |||
| import { | |||
| Card, | |||
| CardHeader, | |||
| CardContent, | |||
| SxProps, | |||
| Theme, | |||
| Grid, | |||
| Modal, | |||
| Typography, | |||
| Button, | |||
| } from "@mui/material"; | |||
| import { DataGrid, GridColDef } from "@mui/x-data-grid"; | |||
| import { darken, lighten, styled } from "@mui/material/styles"; | |||
| import { PROJECT_MODAL_STYLE } from "@/theme/colorConst"; | |||
| import { useRef, useEffect, useState } from "react"; | |||
| import Swal from "sweetalert2"; | |||
| import styledcmp from "styled-components"; | |||
| const CardWrapper = styledcmp.div` | |||
| /* Styles for the card when not hovered */ | |||
| @@ -28,35 +38,44 @@ interface CustomModalProps { | |||
| } | |||
| const CustomModal: React.FC<CustomModalProps> = ({ ...props }) => { | |||
| const ModalContent = () => { | |||
| return ( | |||
| // <Grid item sx={{ m: 3 }}> | |||
| <div > | |||
| <Typography variant="h6" id="modal-title"> | |||
| {props.title??"Modal Title"} | |||
| </Typography> | |||
| <Typography variant="h6" id="modal-title" style={{ alignSelf: 'flex-start', margin: '10px' }}> | |||
| Modal Content | |||
| </Typography> | |||
| <div style={{ display: 'flex', justifyContent: 'space-between', width: '100%' }}> | |||
| <Button variant="contained" onClick={props.onClose}> | |||
| Confirm | |||
| </Button> | |||
| <Button variant="contained" onClick={props.onClose}> | |||
| Cancel | |||
| </Button> | |||
| </div> | |||
| <div> | |||
| <Typography variant="h6" id="modal-title"> | |||
| {props.title ?? "Modal Title"} | |||
| </Typography> | |||
| <Typography | |||
| variant="h6" | |||
| id="modal-title" | |||
| style={{ alignSelf: "flex-start", margin: "10px" }} | |||
| > | |||
| Modal Content | |||
| </Typography> | |||
| <div | |||
| style={{ | |||
| display: "flex", | |||
| justifyContent: "space-between", | |||
| width: "100%", | |||
| }} | |||
| > | |||
| <Button variant="contained" onClick={props.onClose}> | |||
| Confirm | |||
| </Button> | |||
| <Button variant="contained" onClick={props.onClose}> | |||
| Cancel | |||
| </Button> | |||
| </div> | |||
| </div> | |||
| // </Grid> | |||
| ); | |||
| }; | |||
| return ( | |||
| <Modal open={props.isOpen} onClose={props.onClose}> | |||
| {props.modalStyle? <props.modalStyle props={props}/> : <ModalContent/>} | |||
| {props.modalStyle ? <props.modalStyle props={props} /> : <ModalContent />} | |||
| </Modal> | |||
| ); | |||
| }; | |||
| export default CustomModal; | |||
| export default CustomModal; | |||
| @@ -1,5 +1,5 @@ | |||
| "use client"; | |||
| import React, { useState, FC } from 'react'; | |||
| import React, { useState, FC } from "react"; | |||
| import { | |||
| Stack, | |||
| Typography, | |||
| @@ -15,16 +15,16 @@ import { | |||
| InputLabel, | |||
| Select, | |||
| MenuItem, | |||
| ThemeProvider | |||
| } from '@mui/material'; | |||
| import { useForm, Controller } from 'react-hook-form'; | |||
| import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; | |||
| import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; | |||
| import dayjs from 'dayjs'; | |||
| import SearchIcon from '@mui/icons-material/Search'; | |||
| import RefreshIcon from '@mui/icons-material/Refresh'; | |||
| import { DemoItem } from '@mui/x-date-pickers/internals/demo'; | |||
| import { DatePicker } from '@mui/x-date-pickers/DatePicker'; | |||
| ThemeProvider, | |||
| } from "@mui/material"; | |||
| import { useForm, Controller } from "react-hook-form"; | |||
| import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; | |||
| import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; | |||
| import dayjs from "dayjs"; | |||
| import SearchIcon from "@mui/icons-material/Search"; | |||
| import RefreshIcon from "@mui/icons-material/Refresh"; | |||
| import { DemoItem } from "@mui/x-date-pickers/internals/demo"; | |||
| import { DatePicker } from "@mui/x-date-pickers/DatePicker"; | |||
| interface Field { | |||
| id: any; | |||
| @@ -50,29 +50,38 @@ interface SearchFormProps { | |||
| sx?: any; | |||
| } | |||
| const FormComponent: FC<FormComponentProps> = ({ fields, onSubmit, resetForm, sx }) => { | |||
| const FormComponent: FC<FormComponentProps> = ({ | |||
| fields, | |||
| onSubmit, | |||
| resetForm, | |||
| sx, | |||
| }) => { | |||
| const { reset, register, handleSubmit, control } = useForm(); | |||
| const [fromDate, setFromDate] = useState<dayjs.Dayjs | null>(null); | |||
| const [dayRangeFromDate, setDayRangeFromDate] = useState<dayjs.Dayjs | null>(null); | |||
| const [dayRangeToDate, setDayRangeToDate] = useState<dayjs.Dayjs | null>(null); | |||
| const [dayRangeFromDate, setDayRangeFromDate] = useState<dayjs.Dayjs | null>( | |||
| null, | |||
| ); | |||
| const [dayRangeToDate, setDayRangeToDate] = useState<dayjs.Dayjs | null>( | |||
| null, | |||
| ); | |||
| const [value, setValue] = useState<{ [key: string]: any }>({}); | |||
| const [checkbox1, setCheckbox1] = useState(false); | |||
| const handleFormSubmit = (data: any) => { | |||
| if (fromDate != null || fromDate != undefined) { | |||
| data.fromDate = dayjs(fromDate).format('YYYY-MM-DD'); | |||
| data.fromDate = dayjs(fromDate).format("YYYY-MM-DD"); | |||
| } | |||
| if (value !== null) { | |||
| data.dropdownCombo = value | |||
| data.dropdownCombo = value; | |||
| } | |||
| if (value !== null) { | |||
| data.checkbox = checkbox1; | |||
| } | |||
| if (dayRangeFromDate != null || dayRangeFromDate != undefined) { | |||
| data.dayRangeFromDate = dayjs(dayRangeFromDate).format('YYYY-MM-DD'); | |||
| data.dayRangeFromDate = dayjs(dayRangeFromDate).format("YYYY-MM-DD"); | |||
| } | |||
| if (dayRangeToDate != null || dayRangeToDate != undefined) { | |||
| data.dayRangeToDate = dayjs(dayRangeToDate).format('YYYY-MM-DD'); | |||
| data.dayRangeToDate = dayjs(dayRangeToDate).format("YYYY-MM-DD"); | |||
| } | |||
| onSubmit(data); | |||
| }; | |||
| @@ -82,8 +91,8 @@ const FormComponent: FC<FormComponentProps> = ({ fields, onSubmit, resetForm, sx | |||
| resetForm(); | |||
| setFromDate(null); | |||
| fields.forEach((field) => { | |||
| if (typeof(field.setValue) === "function") { | |||
| field.setValue(typeof (field.value) === "boolean" ? false : null); | |||
| if (typeof field.setValue === "function") { | |||
| field.setValue(typeof field.value === "boolean" ? false : null); | |||
| } else if (Array.isArray(field.setValue)) { | |||
| field.setValue.forEach((setFunc) => { | |||
| setFunc(null); | |||
| @@ -96,11 +105,21 @@ const FormComponent: FC<FormComponentProps> = ({ fields, onSubmit, resetForm, sx | |||
| <form onSubmit={handleSubmit(handleFormSubmit)}> | |||
| <Grid container alignItems="center"> | |||
| {fields.map((field) => { | |||
| if (field.type === 'dropdown') { | |||
| if (field.type === "dropdown") { | |||
| return ( | |||
| <Grid item xs={12} sm={5.5} md={5.5} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }} key={field.id}> | |||
| <Grid | |||
| item | |||
| xs={12} | |||
| sm={5.5} | |||
| md={5.5} | |||
| lg={5.5} | |||
| sx={{ ml: 3, mr: 3, mb: 3 }} | |||
| key={field.id} | |||
| > | |||
| <FormControl fullWidth> | |||
| <InputLabel id={`${field.id}-label`}>{field.label}</InputLabel> | |||
| <InputLabel id={`${field.id}-label`}> | |||
| {field.label} | |||
| </InputLabel> | |||
| <Controller | |||
| name={field.id} | |||
| control={control} | |||
| @@ -115,11 +134,13 @@ const FormComponent: FC<FormComponentProps> = ({ fields, onSubmit, resetForm, sx | |||
| }} | |||
| > | |||
| {field.options?.map((option) => ( | |||
| <MenuItem | |||
| value={option.id ?? JSON.stringify(option)} | |||
| <MenuItem | |||
| value={option.id ?? JSON.stringify(option)} | |||
| key={option.id ?? JSON.stringify(option)} | |||
| > | |||
| {option.id !== undefined ? option.label : JSON.stringify(option)} | |||
| {option.id !== undefined | |||
| ? option.label | |||
| : JSON.stringify(option)} | |||
| </MenuItem> | |||
| ))} | |||
| </Select> | |||
| @@ -128,19 +149,27 @@ const FormComponent: FC<FormComponentProps> = ({ fields, onSubmit, resetForm, sx | |||
| </FormControl> | |||
| </Grid> | |||
| ); | |||
| } else if (field.type === 'date') { | |||
| } else if (field.type === "date") { | |||
| return ( | |||
| <Grid item xs={12} sm={5.5} md={5.5} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }} key={field.id}> | |||
| <Grid | |||
| item | |||
| xs={12} | |||
| sm={5.5} | |||
| md={5.5} | |||
| lg={5.5} | |||
| sx={{ ml: 3, mr: 3, mb: 3 }} | |||
| key={field.id} | |||
| > | |||
| <LocalizationProvider dateAdapter={AdapterDayjs}> | |||
| <DemoItem> | |||
| <DatePicker | |||
| slotProps={{ | |||
| textField: { | |||
| id:field.id, | |||
| id: field.id, | |||
| }, | |||
| }} | |||
| label={field.label} | |||
| value={fromDate === null ? null : dayjs(fromDate)} | |||
| value={fromDate === null ? null : dayjs(fromDate)} | |||
| onChange={(newValue) => { | |||
| setFromDate(newValue); | |||
| }} | |||
| @@ -149,16 +178,24 @@ const FormComponent: FC<FormComponentProps> = ({ fields, onSubmit, resetForm, sx | |||
| </LocalizationProvider> | |||
| </Grid> | |||
| ); | |||
| } else if (field.type === 'checkbox') { | |||
| } else if (field.type === "checkbox") { | |||
| return ( | |||
| <Grid item xs={12} sm={5.5} md={5.5} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }} key={field.id}> | |||
| <Grid | |||
| item | |||
| xs={12} | |||
| sm={5.5} | |||
| md={5.5} | |||
| lg={5.5} | |||
| sx={{ ml: 3, mr: 3, mb: 3 }} | |||
| key={field.id} | |||
| > | |||
| <FormControlLabel | |||
| control={ | |||
| <Checkbox | |||
| id={field.id} | |||
| checked={field.value} | |||
| onChange={(event) => { | |||
| if (typeof field.setValue === 'function') { | |||
| if (typeof field.setValue === "function") { | |||
| field.setValue(event.target.checked); | |||
| setCheckbox1(event.target.checked); | |||
| } | |||
| @@ -166,102 +203,176 @@ const FormComponent: FC<FormComponentProps> = ({ fields, onSubmit, resetForm, sx | |||
| color="primary" | |||
| /> | |||
| } | |||
| label={<Typography style={{fontSize:"1.15em"}}>{field.label}</Typography>} | |||
| label={ | |||
| <Typography style={{ fontSize: "1.15em" }}> | |||
| {field.label} | |||
| </Typography> | |||
| } | |||
| /> | |||
| </Grid> | |||
| ) | |||
| } else if (field.type === 'dateRange') { | |||
| ); | |||
| } else if (field.type === "dateRange") { | |||
| return ( | |||
| <Grid container key={field.id[0]}> | |||
| <Grid item xs={12} sm={7} md={7} lg={7} sx={{ ml: 3, mr: 3, mb: 3 }}> | |||
| <Grid | |||
| item | |||
| xs={12} | |||
| sm={7} | |||
| md={7} | |||
| lg={7} | |||
| sx={{ ml: 3, mr: 3, mb: 3 }} | |||
| > | |||
| <Grid container> | |||
| <Grid> | |||
| <LocalizationProvider dateAdapter={AdapterDayjs}> | |||
| <DatePicker | |||
| label={field.label[0]} | |||
| value={field.value[0]} | |||
| onChange={(newValue) => setDayRangeFromDate(newValue)} | |||
| /> | |||
| <DatePicker | |||
| label={field.label[0]} | |||
| value={field.value[0]} | |||
| onChange={(newValue) => setDayRangeFromDate(newValue)} | |||
| /> | |||
| </LocalizationProvider> | |||
| </Grid> | |||
| <Grid item xs={1.5} sm={1.5} md={1.5} lg={1.5} sx={{ display: 'flex', justifyContent: "center", alignItems: 'center' }}> | |||
| To | |||
| </Grid> | |||
| <Grid | |||
| item | |||
| xs={1.5} | |||
| sm={1.5} | |||
| md={1.5} | |||
| lg={1.5} | |||
| sx={{ | |||
| display: "flex", | |||
| justifyContent: "center", | |||
| alignItems: "center", | |||
| }} | |||
| > | |||
| To | |||
| </Grid> | |||
| <Grid item xs={5.25} sm={5.25} md={5.25} lg={5.25}> | |||
| <LocalizationProvider dateAdapter={AdapterDayjs}> | |||
| <DatePicker | |||
| label={field.label[1]} | |||
| value={field.value[1]} | |||
| onChange={(newValue) => setDayRangeToDate(newValue)} | |||
| /> | |||
| <DatePicker | |||
| label={field.label[1]} | |||
| value={field.value[1]} | |||
| onChange={(newValue) => setDayRangeToDate(newValue)} | |||
| /> | |||
| </LocalizationProvider> | |||
| </Grid> | |||
| </Grid> | |||
| </Grid> | |||
| </Grid> | |||
| ) | |||
| ); | |||
| } | |||
| return ( | |||
| <Grid item xs={12} sm={5.5} md={5.5} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }} key={field.id}> | |||
| <Grid | |||
| item | |||
| xs={12} | |||
| sm={5.5} | |||
| md={5.5} | |||
| lg={5.5} | |||
| sx={{ ml: 3, mr: 3, mb: 3 }} | |||
| key={field.id} | |||
| > | |||
| <TextField | |||
| fullWidth | |||
| {...register(field.id)} | |||
| id={field.id} | |||
| label={field.label} | |||
| defaultValue={field.value !== undefined && field.value !== null ? `${field.value}` : ''} | |||
| defaultValue={ | |||
| field.value !== undefined && field.value !== null | |||
| ? `${field.value}` | |||
| : "" | |||
| } | |||
| required={field.required === true ? field.required : false} | |||
| sx={{ ...sx }} | |||
| InputProps={{ | |||
| style: { | |||
| borderRadius: "10px", | |||
| } | |||
| }, | |||
| }} | |||
| /> | |||
| </Grid> | |||
| ); | |||
| })} | |||
| </Grid> | |||
| <Grid container maxWidth="lg" justifyContent="space-between" style={{marginTop:-20}}> | |||
| <Grid | |||
| container | |||
| maxWidth="lg" | |||
| justifyContent="space-between" | |||
| style={{ marginTop: -20 }} | |||
| > | |||
| <Stack direction="row"> | |||
| <Grid item sx={{ ml: 3, mr: 3, mb: 3, mt: 3 }}> | |||
| <Button className="h-12 w-32" style={{backgroundColor:"#92c1e9",color:"white",fontSize:"1.15em",fontWeight:100,borderRadius:10}} type="submit"> | |||
| <SearchIcon/> Search | |||
| <Button | |||
| className="h-12 w-32" | |||
| style={{ | |||
| backgroundColor: "#92c1e9", | |||
| color: "white", | |||
| fontSize: "1.15em", | |||
| fontWeight: 100, | |||
| borderRadius: 10, | |||
| }} | |||
| type="submit" | |||
| > | |||
| <SearchIcon /> | |||
| Search | |||
| </Button> | |||
| </Grid> | |||
| <Grid item sx={{ ml: 3, mr: 3, mb: 3, mt: 3 }}> | |||
| <Button className="h-12 w-32" style={{backgroundColor:"#f890a5",color:"white",fontSize:"1.15em",fontWeight:100,borderRadius:10}} onClick={handleFormReset}> | |||
| <RefreshIcon/> Reset | |||
| <Button | |||
| className="h-12 w-32" | |||
| style={{ | |||
| backgroundColor: "#f890a5", | |||
| color: "white", | |||
| fontSize: "1.15em", | |||
| fontWeight: 100, | |||
| borderRadius: 10, | |||
| }} | |||
| onClick={handleFormReset} | |||
| > | |||
| <RefreshIcon /> | |||
| Reset | |||
| </Button> | |||
| </Grid> | |||
| </Stack> | |||
| </Grid> | |||
| </Grid> | |||
| </form> | |||
| ); | |||
| }; | |||
| const CustomSearchForm: FC<SearchFormProps> = ({ applySearch, fields, title, sx }) => { | |||
| const CustomSearchForm: FC<SearchFormProps> = ({ | |||
| applySearch, | |||
| fields, | |||
| title, | |||
| sx, | |||
| }) => { | |||
| const Title = title || "Searching Criteria"; | |||
| const handleSubmit = (data: any) => { | |||
| if (applySearch) { | |||
| applySearch(data); | |||
| } else { | |||
| console.log('applySearch function is null'); | |||
| console.log("applySearch function is null"); | |||
| } | |||
| }; | |||
| const handleFormReset = () => { | |||
| console.log('Form Reset'); | |||
| console.log("Form Reset"); | |||
| }; | |||
| return ( | |||
| <Card style={{marginRight:20}}> | |||
| <CardHeader className="text-slate-500 " style={{marginTop:-5}} title={Title}></CardHeader> | |||
| <FormComponent fields={fields} onSubmit={handleSubmit} resetForm={handleFormReset} sx={sx} /> | |||
| </Card> | |||
| <Card style={{ marginRight: 20 }}> | |||
| <CardHeader | |||
| className="text-slate-500 " | |||
| style={{ marginTop: -5 }} | |||
| title={Title} | |||
| ></CardHeader> | |||
| <FormComponent | |||
| fields={fields} | |||
| onSubmit={handleSubmit} | |||
| resetForm={handleFormReset} | |||
| sx={sx} | |||
| /> | |||
| </Card> | |||
| ); | |||
| }; | |||
| @@ -1,12 +1,12 @@ | |||
| "use client" | |||
| "use client"; | |||
| import Grid from "@mui/material/Grid"; | |||
| import Paper from "@mui/material/Paper"; | |||
| import { TFunction } from "i18next"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import PageTitle from "../PageTitle/PageTitle"; | |||
| import DashboardTabButton from "./DashboardTabButton"; | |||
| import { ThemeProvider } from '@mui/material/styles'; | |||
| import theme from '../../theme'; | |||
| import { ThemeProvider } from "@mui/material/styles"; | |||
| import theme from "../../theme"; | |||
| import Tabs, { TabsProps } from "@mui/material/Tabs"; | |||
| import Tab from "@mui/material/Tab"; | |||
| import React, { useCallback, useState } from "react"; | |||
| @@ -38,7 +38,7 @@ const DashboardPage: React.FC = () => { | |||
| <Tab label="Staff Utilization" /> | |||
| </Tabs> | |||
| {tabIndex === 2 && <ProgressByClient />} | |||
| {/* <Grid container height="100vh" style={{ backgroundColor: theme.palette.background.default}}> | |||
| {/* <Grid container height="100vh" style={{ backgroundColor: theme.palette.background.default}}> | |||
| <Grid item sm> | |||
| <PageTitle BigTitle={"Dashboards"}/> | |||
| <DashboardTabButton/> | |||
| @@ -1,6 +1,6 @@ | |||
| "use client"; | |||
| import Grid from "@mui/material/Grid"; | |||
| import { useState,useCallback} from 'react' | |||
| import { useState, useCallback } from "react"; | |||
| import Paper from "@mui/material/Paper"; | |||
| import { TFunction } from "i18next"; | |||
| import { useTranslation } from "react-i18next"; | |||
| @@ -8,22 +8,22 @@ import PageTitle from "../PageTitle/PageTitle"; | |||
| import ProgressByClient from "./ProgressByClient"; | |||
| import Tabs, { TabsProps } from "@mui/material/Tabs"; | |||
| import Tab from "@mui/material/Tab"; | |||
| import '../../app/global.css'; | |||
| import "../../app/global.css"; | |||
| const DashboardTabButton: React.FC = () => { | |||
| const [activeTab, setActiveTab] = useState('financialSummary'); | |||
| const [activeTab, setActiveTab] = useState("financialSummary"); | |||
| const { t } = useTranslation("dashboard"); | |||
| const renderContent = () => { | |||
| switch (activeTab) { | |||
| case 'financialSummary': | |||
| case "financialSummary": | |||
| return <div>Project Financial Summary</div>; | |||
| case 'cashFlow': | |||
| case "cashFlow": | |||
| return <div>Project Cash Flow</div>; | |||
| case 'progressByClient': | |||
| return <ProgressByClient/>; | |||
| case 'resourceUtilization': | |||
| case "progressByClient": | |||
| return <ProgressByClient />; | |||
| case "resourceUtilization": | |||
| return <div>Project Resource Utilization</div>; | |||
| case 'staffUtilization': | |||
| case "staffUtilization": | |||
| return <div>Staff Utilization</div>; | |||
| default: | |||
| return <div>Project Financial Summary</div>; | |||
| @@ -37,40 +37,40 @@ const DashboardTabButton: React.FC = () => { | |||
| [], | |||
| ); | |||
| return ( | |||
| // <Grid item sm> | |||
| // <div style={{marginLeft:20}}> | |||
| // {activeTab !== 'financialSummary' ? | |||
| // <button onClick={() => setActiveTab('financialSummary')}className="hover:bg-sky-100 hover:cursor-pointer rounded-lg bg-transparent border-slate-400 border-solid text-slate-400 ml-0.5 mt-0.5" style={{height:40,width:250,fontSize:18}}>Project Financial Summary</button> : | |||
| // <button onClick={() => setActiveTab('financialSummary')}className="rounded-lg bg-sky-100 border-cyan-500 border-solid text-cyan-500 ml-0.5 mt-0.5" style={{height:40,width:250,fontSize:18}}>Project Financial Summary</button> | |||
| // } | |||
| // {activeTab !== 'cashFlow' ? | |||
| // <button onClick={() => setActiveTab('cashFlow')} className="hover:bg-sky-100 hover:cursor-pointer rounded-lg bg-transparent border-slate-400 border-solid text-slate-400 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Project Cash Flow</button> : | |||
| // <button onClick={() => setActiveTab('cashFlow')} className="rounded-lg bg-sky-100 border-cyan-500 border-solid text-cyan-500 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Project Cash Flow</button> | |||
| // } | |||
| // {activeTab !== 'progressByClient' ? | |||
| // <button onClick={() => setActiveTab('progressByClient')} className="hover:bg-sky-100 hover:cursor-pointer rounded-lg bg-transparent border-slate-400 border-solid text-slate-400 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Project Progress by Client</button> : | |||
| // <button onClick={() => setActiveTab('progressByClient')} className="rounded-lg bg-sky-100 border-cyan-500 border-solid text-cyan-500 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Project Progress by Client</button> | |||
| // } | |||
| // {activeTab !== 'resourceUtilization' ? | |||
| // <button onClick={() => setActiveTab('resourceUtilization')} className="hover:bg-sky-100 hover:cursor-pointer rounded-lg bg-transparent border-slate-400 border-solid text-slate-400 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Project Resource Utilization</button> : | |||
| // <button onClick={() => setActiveTab('resourceUtilization')} className="rounded-lg bg-sky-100 border-cyan-500 border-solid text-cyan-500 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Project Resource Utilization</button> | |||
| // } | |||
| // {activeTab !== 'staffUtilization' ? | |||
| // <button onClick={() => setActiveTab('staffUtilization')} className="hover:bg-sky-100 hover:cursor-pointer rounded-lg bg-transparent border-slate-400 border-solid text-slate-400 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Staff Utilization</button> : | |||
| // <button onClick={() => setActiveTab('staffUtilization')} className="rounded-lg bg-sky-100 border-cyan-500 border-solid text-cyan-500 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Staff Utilization</button> | |||
| // } | |||
| // </div> | |||
| // <div style={{marginLeft:20,marginTop:20}}> | |||
| // {renderContent()} | |||
| // </div> | |||
| // </Grid> | |||
| <Tabs value={tabIndex} onChange={handleTabChange} variant="scrollable"> | |||
| <Tab label="Project Financial Summary" /> | |||
| <Tab label="Project Cash Flow" /> | |||
| <Tab label="Project Progress by Client" /> | |||
| <Tab label="Project Resource Utilization" /> | |||
| <Tab label="Staff Utilization" /> | |||
| </Tabs> | |||
| // <Grid item sm> | |||
| // <div style={{marginLeft:20}}> | |||
| // {activeTab !== 'financialSummary' ? | |||
| // <button onClick={() => setActiveTab('financialSummary')}className="hover:bg-sky-100 hover:cursor-pointer rounded-lg bg-transparent border-slate-400 border-solid text-slate-400 ml-0.5 mt-0.5" style={{height:40,width:250,fontSize:18}}>Project Financial Summary</button> : | |||
| // <button onClick={() => setActiveTab('financialSummary')}className="rounded-lg bg-sky-100 border-cyan-500 border-solid text-cyan-500 ml-0.5 mt-0.5" style={{height:40,width:250,fontSize:18}}>Project Financial Summary</button> | |||
| // } | |||
| // {activeTab !== 'cashFlow' ? | |||
| // <button onClick={() => setActiveTab('cashFlow')} className="hover:bg-sky-100 hover:cursor-pointer rounded-lg bg-transparent border-slate-400 border-solid text-slate-400 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Project Cash Flow</button> : | |||
| // <button onClick={() => setActiveTab('cashFlow')} className="rounded-lg bg-sky-100 border-cyan-500 border-solid text-cyan-500 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Project Cash Flow</button> | |||
| // } | |||
| // {activeTab !== 'progressByClient' ? | |||
| // <button onClick={() => setActiveTab('progressByClient')} className="hover:bg-sky-100 hover:cursor-pointer rounded-lg bg-transparent border-slate-400 border-solid text-slate-400 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Project Progress by Client</button> : | |||
| // <button onClick={() => setActiveTab('progressByClient')} className="rounded-lg bg-sky-100 border-cyan-500 border-solid text-cyan-500 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Project Progress by Client</button> | |||
| // } | |||
| // {activeTab !== 'resourceUtilization' ? | |||
| // <button onClick={() => setActiveTab('resourceUtilization')} className="hover:bg-sky-100 hover:cursor-pointer rounded-lg bg-transparent border-slate-400 border-solid text-slate-400 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Project Resource Utilization</button> : | |||
| // <button onClick={() => setActiveTab('resourceUtilization')} className="rounded-lg bg-sky-100 border-cyan-500 border-solid text-cyan-500 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Project Resource Utilization</button> | |||
| // } | |||
| // {activeTab !== 'staffUtilization' ? | |||
| // <button onClick={() => setActiveTab('staffUtilization')} className="hover:bg-sky-100 hover:cursor-pointer rounded-lg bg-transparent border-slate-400 border-solid text-slate-400 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Staff Utilization</button> : | |||
| // <button onClick={() => setActiveTab('staffUtilization')} className="rounded-lg bg-sky-100 border-cyan-500 border-solid text-cyan-500 ml-0.5 mt-0.5" style={{height:39,width:250,fontSize:18}}>Staff Utilization</button> | |||
| // } | |||
| // </div> | |||
| // <div style={{marginLeft:20,marginTop:20}}> | |||
| // {renderContent()} | |||
| // </div> | |||
| // </Grid> | |||
| <Tabs value={tabIndex} onChange={handleTabChange} variant="scrollable"> | |||
| <Tab label="Project Financial Summary" /> | |||
| <Tab label="Project Cash Flow" /> | |||
| <Tab label="Project Progress by Client" /> | |||
| <Tab label="Project Resource Utilization" /> | |||
| <Tab label="Staff Utilization" /> | |||
| </Tabs> | |||
| ); | |||
| }; | |||
| @@ -1,76 +1,160 @@ | |||
| import * as React from "react"; | |||
| import Grid from "@mui/material/Grid"; | |||
| import { useState,useEffect, useMemo } from 'react' | |||
| import { useState, useEffect, useMemo } from "react"; | |||
| import Paper from "@mui/material/Paper"; | |||
| import { TFunction } from "i18next"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import {Card,CardHeader} from '@mui/material'; | |||
| import { Card, CardHeader } from "@mui/material"; | |||
| import CustomSearchForm from "../CustomSearchForm/CustomSearchForm"; | |||
| import CustomDatagrid from '../CustomDatagrid/CustomDatagrid'; | |||
| import ReactApexChart from 'react-apexcharts'; | |||
| import { ApexOptions } from 'apexcharts'; | |||
| import { GridColDef, GridRowSelectionModel} from '@mui/x-data-grid'; | |||
| import ReportProblemIcon from '@mui/icons-material/ReportProblem'; | |||
| import dynamic from 'next/dynamic'; | |||
| import '../../app/global.css'; | |||
| import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; | |||
| import ReactApexChart from "react-apexcharts"; | |||
| import { ApexOptions } from "apexcharts"; | |||
| import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid"; | |||
| import ReportProblemIcon from "@mui/icons-material/ReportProblem"; | |||
| import dynamic from "next/dynamic"; | |||
| import "../../app/global.css"; | |||
| import { AnyARecord } from "dns"; | |||
| import SearchBox, { Criterion } from "../SearchBox"; | |||
| import ProgressByClientSearch from "@/components/ProgressByClientSearch"; | |||
| import { Suspense } from "react"; | |||
| const ProgressByClient: React.FC = () => { | |||
| const [activeTab, setActiveTab] = useState('financialSummary'); | |||
| const [SearchCriteria, setSearchCriteria] = React.useState({}) | |||
| const [activeTab, setActiveTab] = useState("financialSummary"); | |||
| const [SearchCriteria, setSearchCriteria] = React.useState({}); | |||
| const { t } = useTranslation("dashboard"); | |||
| const [clientCode, setClientCode] = useState(''); | |||
| const [clientName, setClientName] = useState(''); | |||
| const [subsidiaryClientCode, setSubsidiaryClientCode] = useState(''); | |||
| const [subsidiaryClientName, setSubsidiaryClientName] = useState(''); | |||
| const [projectArray, setProjectArray] : any[] = useState([]); | |||
| const [percentageArray, setPercentageArray] : any[] = useState([]); | |||
| const [selectionModel, setSelectionModel] : any[] = React.useState([]); | |||
| const [dropdownDemo, setDropdownDemo] = useState(''); | |||
| const [clientCode, setClientCode] = useState(""); | |||
| const [clientName, setClientName] = useState(""); | |||
| const [subsidiaryClientCode, setSubsidiaryClientCode] = useState(""); | |||
| const [subsidiaryClientName, setSubsidiaryClientName] = useState(""); | |||
| const [projectArray, setProjectArray]: any[] = useState([]); | |||
| const [percentageArray, setPercentageArray]: any[] = useState([]); | |||
| const [selectionModel, setSelectionModel]: any[] = React.useState([]); | |||
| const [dropdownDemo, setDropdownDemo] = useState(""); | |||
| const [dateDemo, setDateDemo] = useState(null); | |||
| const [checkboxDemo, setCheckboxDemo] = useState(false); | |||
| const [receiptFromDate, setReceiptFromDate] = useState(null); | |||
| const [receiptToDate, setReceiptToDate] = useState(null); | |||
| const [selectedRows, setSelectedRows] = useState([]); | |||
| const 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"} | |||
| ] | |||
| const rows2 = [{id: 1,project:"Consultancy Project 123",team:"XXX", teamLeader:"XXX", currentStage:"Contract Documentation", budgetedManhour:"200.00",spentManhour:"120.00",remainedManhour:"80.00",comingPaymentMilestone:"31/03/2024",alert:false}, | |||
| {id: 2,project:"Consultancy Project 456",team:"XXX", teamLeader:"XXX", currentStage:"Report Preparation", budgetedManhour:"400.00",spentManhour:"200.00",remainedManhour:"200.00",comingPaymentMilestone:"20/02/2024",alert:false}, | |||
| {id: 3,project:"Construction Project A",team:"YYY", teamLeader:"YYY", currentStage:"Construction", budgetedManhour:"187.50",spentManhour:"200.00",remainedManhour:"12.50",comingPaymentMilestone:"13/12/2023",alert:true}, | |||
| {id: 4,project:"Construction Project B",team:"XXX", teamLeader:"XXX", currentStage:"Post Construction", budgetedManhour:"100.00",spentManhour:"40.00",remainedManhour:"60.00",comingPaymentMilestone:"05/01/2024",alert:false}, | |||
| {id: 5,project:"Construction Project C",team:"YYY", teamLeader:"YYY", currentStage:"Construction", budgetedManhour:"300.00",spentManhour:"150.00",remainedManhour:"150.00",comingPaymentMilestone:"31/03/2024",alert:false}, | |||
| ] | |||
| 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", | |||
| }, | |||
| ]; | |||
| const rows2 = [ | |||
| { | |||
| id: 1, | |||
| project: "Consultancy Project 123", | |||
| team: "XXX", | |||
| teamLeader: "XXX", | |||
| currentStage: "Contract Documentation", | |||
| budgetedManhour: "200.00", | |||
| spentManhour: "120.00", | |||
| remainedManhour: "80.00", | |||
| comingPaymentMilestone: "31/03/2024", | |||
| alert: false, | |||
| }, | |||
| { | |||
| id: 2, | |||
| project: "Consultancy Project 456", | |||
| team: "XXX", | |||
| teamLeader: "XXX", | |||
| currentStage: "Report Preparation", | |||
| budgetedManhour: "400.00", | |||
| spentManhour: "200.00", | |||
| remainedManhour: "200.00", | |||
| comingPaymentMilestone: "20/02/2024", | |||
| alert: false, | |||
| }, | |||
| { | |||
| id: 3, | |||
| project: "Construction Project A", | |||
| team: "YYY", | |||
| teamLeader: "YYY", | |||
| currentStage: "Construction", | |||
| budgetedManhour: "187.50", | |||
| spentManhour: "200.00", | |||
| remainedManhour: "12.50", | |||
| comingPaymentMilestone: "13/12/2023", | |||
| alert: true, | |||
| }, | |||
| { | |||
| id: 4, | |||
| project: "Construction Project B", | |||
| team: "XXX", | |||
| teamLeader: "XXX", | |||
| currentStage: "Post Construction", | |||
| budgetedManhour: "100.00", | |||
| spentManhour: "40.00", | |||
| remainedManhour: "60.00", | |||
| comingPaymentMilestone: "05/01/2024", | |||
| alert: false, | |||
| }, | |||
| { | |||
| id: 5, | |||
| project: "Construction Project C", | |||
| team: "YYY", | |||
| teamLeader: "YYY", | |||
| currentStage: "Construction", | |||
| budgetedManhour: "300.00", | |||
| spentManhour: "150.00", | |||
| remainedManhour: "150.00", | |||
| comingPaymentMilestone: "31/03/2024", | |||
| alert: false, | |||
| }, | |||
| ]; | |||
| const columns = [ | |||
| { | |||
| id: 'clientCode', | |||
| field: 'clientCode', | |||
| headerName: "Client Code", | |||
| flex: 1, | |||
| { | |||
| id: "clientCode", | |||
| field: "clientCode", | |||
| headerName: "Client Code", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'clientName', | |||
| field: 'clientName', | |||
| headerName: "Client Name", | |||
| flex: 1, | |||
| id: "clientName", | |||
| field: "clientName", | |||
| headerName: "Client Name", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'clientSubsidiaryCode', | |||
| field: 'clientSubsidiaryCode', | |||
| id: "clientSubsidiaryCode", | |||
| field: "clientSubsidiaryCode", | |||
| headerName: "Client Subsidiary Code", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'noOfProjects', | |||
| field: 'noOfProjects', | |||
| id: "noOfProjects", | |||
| field: "noOfProjects", | |||
| headerName: "No. of Projects", | |||
| flex: 1, | |||
| }, | |||
| @@ -78,99 +162,119 @@ const ProgressByClient: React.FC = () => { | |||
| const columns2 = [ | |||
| { | |||
| id: 'project', | |||
| field: 'project', | |||
| id: "project", | |||
| field: "project", | |||
| headerName: "Project", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'team', | |||
| field: 'team', | |||
| }, | |||
| { | |||
| id: "team", | |||
| field: "team", | |||
| headerName: "Team", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'teamLeader', | |||
| field: 'teamLeader', | |||
| headerName: "Team Leader", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'currentStage', | |||
| field: 'currentStage', | |||
| headerName: "Current Stage", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'budgetedManhour', | |||
| field: 'budgetedManhour', | |||
| headerName: "Budgeted Manhour", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'spentManhour', | |||
| field: 'spentManhour', | |||
| headerName: "Spent Manhour", | |||
| renderCell: (params:any) => { | |||
| if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | |||
| return( | |||
| <span className="text-red-300">{params.row.spentManhour}</span> | |||
| ) | |||
| } else { | |||
| return ( | |||
| <span>{params.row.spentManhour}</span> | |||
| ) | |||
| } | |||
| }, | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'remainedManhour', | |||
| field: 'remainedManhour', | |||
| headerName: "Remained Manhour", | |||
| renderCell: (params:any) => { | |||
| if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | |||
| return( | |||
| <span className="text-red-300">({params.row.remainedManhour})</span> | |||
| ) | |||
| } else { | |||
| return ( | |||
| <span>{params.row.remainedManhour}</span> | |||
| ) | |||
| } | |||
| { | |||
| id: "teamLeader", | |||
| field: "teamLeader", | |||
| headerName: "Team Leader", | |||
| flex: 1, | |||
| }, | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'comingPaymentMilestone', | |||
| field: 'comingPaymentMilestone', | |||
| headerName: "Coming Payment Milestone", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'alert', | |||
| field: 'alert', | |||
| headerName: "Alert", | |||
| renderCell: (params:any) => { | |||
| if (params.row.alert === true) { | |||
| return ( | |||
| <span className="text-red-300 text-center"><ReportProblemIcon/></span> | |||
| ) | |||
| } else { | |||
| return ( | |||
| <span></span> | |||
| ) | |||
| } | |||
| { | |||
| id: "currentStage", | |||
| field: "currentStage", | |||
| headerName: "Current Stage", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "budgetedManhour", | |||
| field: "budgetedManhour", | |||
| headerName: "Budgeted Manhour", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "spentManhour", | |||
| field: "spentManhour", | |||
| headerName: "Spent Manhour", | |||
| renderCell: (params: any) => { | |||
| if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | |||
| return ( | |||
| <span className="text-red-300">{params.row.spentManhour}</span> | |||
| ); | |||
| } else { | |||
| return <span>{params.row.spentManhour}</span>; | |||
| } | |||
| }, | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "remainedManhour", | |||
| field: "remainedManhour", | |||
| headerName: "Remained Manhour", | |||
| renderCell: (params: any) => { | |||
| if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | |||
| return ( | |||
| <span className="text-red-300">({params.row.remainedManhour})</span> | |||
| ); | |||
| } else { | |||
| return <span>{params.row.remainedManhour}</span>; | |||
| } | |||
| }, | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "comingPaymentMilestone", | |||
| field: "comingPaymentMilestone", | |||
| headerName: "Coming Payment Milestone", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "alert", | |||
| field: "alert", | |||
| headerName: "Alert", | |||
| renderCell: (params: any) => { | |||
| if (params.row.alert === true) { | |||
| return ( | |||
| <span className="text-red-300 text-center"> | |||
| <ReportProblemIcon /> | |||
| </span> | |||
| ); | |||
| } else { | |||
| return <span></span>; | |||
| } | |||
| }, | |||
| flex: 1, | |||
| }, | |||
| flex: 1, | |||
| }, | |||
| ]; | |||
| ]; | |||
| const InputFields = [ | |||
| { id: "clientCode", label: "Client Code", type: 'text', value: clientCode, setValue: setClientCode }, | |||
| { id: "clientName", label: "Client Name", type: 'text', value: clientName, setValue: setClientName }, | |||
| { id: "subsidiaryClientCode", label: "Subsidiary Client Code", type:'text', value:subsidiaryClientCode, setValue: setSubsidiaryClientCode}, | |||
| { id: "subsidiaryClientName", label: "Subsidiary Client Name", type:'text', value:subsidiaryClientName, setValue: setSubsidiaryClientName}, | |||
| { | |||
| id: "clientCode", | |||
| label: "Client Code", | |||
| type: "text", | |||
| value: clientCode, | |||
| setValue: setClientCode, | |||
| }, | |||
| { | |||
| id: "clientName", | |||
| label: "Client Name", | |||
| type: "text", | |||
| value: clientName, | |||
| setValue: setClientName, | |||
| }, | |||
| { | |||
| id: "subsidiaryClientCode", | |||
| label: "Subsidiary Client Code", | |||
| type: "text", | |||
| value: subsidiaryClientCode, | |||
| setValue: setSubsidiaryClientCode, | |||
| }, | |||
| { | |||
| id: "subsidiaryClientName", | |||
| label: "Subsidiary Client Name", | |||
| type: "text", | |||
| value: subsidiaryClientName, | |||
| setValue: setSubsidiaryClientName, | |||
| }, | |||
| // { 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 }, | |||
| @@ -178,54 +282,66 @@ const ProgressByClient: React.FC = () => { | |||
| // setValue: [setReceiptFromDate, setReceiptToDate],type: 'dateRange' }, | |||
| ]; | |||
| const stageDeadline = ["31/03/2024","20/02/2024","01/12/2023","05/01/2024","31/03/2023"] | |||
| const stageDeadline = [ | |||
| "31/03/2024", | |||
| "20/02/2024", | |||
| "01/12/2023", | |||
| "05/01/2024", | |||
| "31/03/2023", | |||
| ]; | |||
| const series2: ApexAxisChartSeries | ApexNonAxisChartSeries = [{ | |||
| data: [17.1, 28.6, 5.7, 48.6], | |||
| }]; | |||
| const series2: ApexAxisChartSeries | ApexNonAxisChartSeries = [ | |||
| { | |||
| data: [17.1, 28.6, 5.7, 48.6], | |||
| }, | |||
| ]; | |||
| const series: ApexAxisChartSeries | ApexNonAxisChartSeries = [{ | |||
| name: 'Current Stage Completion Percentage', | |||
| data: [80, 55, 40, 65, 70], | |||
| }]; | |||
| const options2 : ApexOptions = { | |||
| const series: ApexAxisChartSeries | ApexNonAxisChartSeries = [ | |||
| { | |||
| name: "Current Stage Completion Percentage", | |||
| data: [80, 55, 40, 65, 70], | |||
| }, | |||
| ]; | |||
| const options2: ApexOptions = { | |||
| chart: { | |||
| type: 'donut', | |||
| type: "donut", | |||
| }, | |||
| plotOptions: { | |||
| pie: { | |||
| donut:{ | |||
| labels:{ | |||
| show:false, | |||
| } | |||
| } | |||
| donut: { | |||
| labels: { | |||
| show: false, | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| labels: [projectArray], | |||
| legend: { | |||
| show: false, | |||
| }, | |||
| responsive: [{ | |||
| breakpoint: 480, | |||
| options: { | |||
| chart: { | |||
| width: 200 | |||
| responsive: [ | |||
| { | |||
| breakpoint: 480, | |||
| options: { | |||
| chart: { | |||
| width: 200, | |||
| }, | |||
| legend: { | |||
| position: "bottom", | |||
| show: false, | |||
| }, | |||
| }, | |||
| legend: { | |||
| position: 'bottom', | |||
| show:false | |||
| } | |||
| } | |||
| }] | |||
| } | |||
| }, | |||
| ], | |||
| }; | |||
| const options: ApexOptions = { | |||
| chart: { | |||
| type: 'bar', | |||
| height: 350 | |||
| type: "bar", | |||
| height: 350, | |||
| }, | |||
| colors: ['#FF4560', '#00E396', '#008FFB', '#775DD0', '#FEB019'], | |||
| colors: ["#FF4560", "#00E396", "#008FFB", "#775DD0", "#FEB019"], | |||
| plotOptions: { | |||
| bar: { | |||
| horizontal: true, | |||
| @@ -233,91 +349,93 @@ const ProgressByClient: React.FC = () => { | |||
| }, | |||
| }, | |||
| dataLabels: { | |||
| enabled: false | |||
| enabled: false, | |||
| }, | |||
| xaxis: { | |||
| categories: [ | |||
| 'Consultancy Project 123', | |||
| 'Consultancy Project 456', | |||
| 'Construction Project A', | |||
| 'Construction Project B', | |||
| 'Construction Project C', | |||
| "Consultancy Project 123", | |||
| "Consultancy Project 456", | |||
| "Construction Project A", | |||
| "Construction Project B", | |||
| "Construction Project C", | |||
| ], | |||
| }, | |||
| yaxis: { | |||
| title: { | |||
| text: 'Projects' | |||
| text: "Projects", | |||
| }, | |||
| labels: { | |||
| maxWidth: 200, | |||
| maxWidth: 200, | |||
| style: { | |||
| cssClass: 'apexcharts-yaxis-label', | |||
| cssClass: "apexcharts-yaxis-label", | |||
| }, | |||
| }, | |||
| }, | |||
| title: { | |||
| text: 'Current Stage Completion Percentage', | |||
| align: 'center' | |||
| text: "Current Stage Completion Percentage", | |||
| align: "center", | |||
| }, | |||
| grid: { | |||
| borderColor: '#f1f1f1', | |||
| borderColor: "#f1f1f1", | |||
| }, | |||
| annotations: { | |||
| } | |||
| annotations: {}, | |||
| }; | |||
| const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => { | |||
| const selectedRowsData = rows2.filter((row) => | |||
| newSelectionModel.includes(row.id) | |||
| newSelectionModel.includes(row.id), | |||
| ); | |||
| console.log(selectedRowsData) | |||
| const projectArray:any[] = [] | |||
| let otherPercentage = 100 | |||
| let totalBudgetManhour = 0 | |||
| const percentageArray = [] | |||
| console.log(selectedRowsData); | |||
| const projectArray: any[] = []; | |||
| let otherPercentage = 100; | |||
| let totalBudgetManhour = 0; | |||
| const percentageArray = []; | |||
| for (let i = 0; i <= selectedRowsData.length; i++) { | |||
| if (i === selectedRowsData.length) { | |||
| projectArray.push("Other") | |||
| projectArray.push("Other"); | |||
| } else { | |||
| projectArray.push(selectedRowsData[i].project) | |||
| totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour) | |||
| projectArray.push(selectedRowsData[i].project); | |||
| totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour); | |||
| } | |||
| } | |||
| for (let i = 0; i <= selectedRowsData.length; i++) { | |||
| if (i === selectedRowsData.length) { | |||
| percentageArray.push(otherPercentage) | |||
| percentageArray.push(otherPercentage); | |||
| } else { | |||
| let percentage = ((Number(selectedRowsData[i].spentManhour) / totalBudgetManhour) * 100).toFixed(1) | |||
| percentageArray.push(Number(percentage)) | |||
| otherPercentage -= Number(percentage) | |||
| const percentage = ( | |||
| (Number(selectedRowsData[i].spentManhour) / totalBudgetManhour) * | |||
| 100 | |||
| ).toFixed(1); | |||
| percentageArray.push(Number(percentage)); | |||
| otherPercentage -= Number(percentage); | |||
| } | |||
| } | |||
| setSelectionModel(newSelectionModel) | |||
| setProjectArray(projectArray) | |||
| setPercentageArray(percentageArray) | |||
| setSelectionModel(newSelectionModel); | |||
| setProjectArray(projectArray); | |||
| setPercentageArray(percentageArray); | |||
| }; | |||
| const applySearch = (data: any) => { | |||
| console.log(data) | |||
| setSearchCriteria(data) | |||
| } | |||
| console.log(data); | |||
| setSearchCriteria(data); | |||
| }; | |||
| return ( | |||
| <Grid item sm> | |||
| {/* <CustomSearchForm applySearch={applySearch} fields={InputFields}/> */} | |||
| {/* <CustomDatagrid rows={rows} columns={columns} columnWidth={200} dataGridHeight={300}/> */} | |||
| <div style={{display:"inline-block",width:"70%"}}> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card> | |||
| <CardHeader className="text-slate-500" title="Project Progress"/> | |||
| <div style={{display:"inline-block",width:"99%"}}> | |||
| <ReactApexChart | |||
| options={options} | |||
| series={series} | |||
| type="bar" | |||
| height={350} | |||
| /> | |||
| </div> | |||
| {/* <div style={{display:"inline-block",width:"20%",verticalAlign:"top",textAlign:"center"}}> | |||
| <Grid item sm> | |||
| {/* <CustomSearchForm applySearch={applySearch} fields={InputFields}/> */} | |||
| {/* <CustomDatagrid rows={rows} columns={columns} columnWidth={200} dataGridHeight={300}/> */} | |||
| <div style={{ display: "inline-block", width: "70%" }}> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card> | |||
| <CardHeader className="text-slate-500" title="Project Progress" /> | |||
| <div style={{ display: "inline-block", width: "99%" }}> | |||
| <ReactApexChart | |||
| options={options} | |||
| series={series} | |||
| type="bar" | |||
| height={350} | |||
| /> | |||
| </div> | |||
| {/* <div style={{display:"inline-block",width:"20%",verticalAlign:"top",textAlign:"center"}}> | |||
| <p><strong><u>Stage Deadline</u></strong></p> | |||
| {stageDeadline.map((date, index) => { | |||
| const marginTop = index === 0 ? 25 : 20; | |||
| @@ -326,26 +444,49 @@ const ProgressByClient: React.FC = () => { | |||
| ); | |||
| })} | |||
| </div> */} | |||
| <CardHeader className="text-slate-500" title="Current Stage Due Date"/> | |||
| <div style={{display:"inline-block",width:"99%",marginLeft:10}}> | |||
| <CustomDatagrid rows={rows2} columns={columns2} columnWidth={200} dataGridHeight={300} checkboxSelection={true} onRowSelectionModelChange={handleSelectionChange} selectionModel={selectionModel}/> | |||
| </div> | |||
| </Card> | |||
| </Grid> | |||
| </div> | |||
| <div style={{display:"inline-block",width:"30%",verticalAlign:"top",marginLeft:0}}> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card style={{marginLeft:15,marginRight:20}}> | |||
| <CardHeader className="text-slate-500" title="Overall Progress per Project"/> | |||
| <ReactApexChart | |||
| options={options2} | |||
| series={percentageArray} | |||
| type="donut" | |||
| /> | |||
| </Card> | |||
| </Grid> | |||
| <CardHeader | |||
| className="text-slate-500" | |||
| title="Current Stage Due Date" | |||
| /> | |||
| <div | |||
| style={{ display: "inline-block", width: "99%", marginLeft: 10 }} | |||
| > | |||
| <CustomDatagrid | |||
| rows={rows2} | |||
| columns={columns2} | |||
| columnWidth={200} | |||
| dataGridHeight={300} | |||
| checkboxSelection={true} | |||
| onRowSelectionModelChange={handleSelectionChange} | |||
| selectionModel={selectionModel} | |||
| /> | |||
| </div> | |||
| </Grid> | |||
| </Card> | |||
| </Grid> | |||
| </div> | |||
| <div | |||
| style={{ | |||
| display: "inline-block", | |||
| width: "30%", | |||
| verticalAlign: "top", | |||
| marginLeft: 0, | |||
| }} | |||
| > | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card style={{ marginLeft: 15, marginRight: 20 }}> | |||
| <CardHeader | |||
| className="text-slate-500" | |||
| title="Overall Progress per Project" | |||
| /> | |||
| <ReactApexChart | |||
| options={options2} | |||
| series={percentageArray} | |||
| type="donut" | |||
| /> | |||
| </Card> | |||
| </Grid> | |||
| </div> | |||
| </Grid> | |||
| ); | |||
| }; | |||
| @@ -8,14 +8,14 @@ import PageTitle from "../PageTitle/PageTitle"; | |||
| import { Suspense } from "react"; | |||
| import Button from "@mui/material/Button"; | |||
| import Stack from "@mui/material/Stack"; | |||
| import { Add } from '@mui/icons-material'; | |||
| import { Add } from "@mui/icons-material"; | |||
| import Link from "next/link"; | |||
| import { t } from 'i18next'; | |||
| import { t } from "i18next"; | |||
| import { Card, Modal, Typography } from "@mui/material"; | |||
| import CustomModal from "../CustomModal/CustomModal"; | |||
| import { PROJECT_MODAL_STYLE } from "@/theme/colorConst"; | |||
| import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; | |||
| import { DataGrid } from '@mui/x-data-grid'; | |||
| import { DataGrid } from "@mui/x-data-grid"; | |||
| import TimesheetInputGrid from "./TimesheetInputGrid"; | |||
| interface EnterTimesheetModalProps { | |||
| @@ -24,55 +24,75 @@ interface EnterTimesheetModalProps { | |||
| modalStyle?: any; | |||
| } | |||
| const EnterTimesheetModal: React.FC<EnterTimesheetModalProps> = ({ ...props }) => { | |||
| const EnterTimesheetModal: React.FC<EnterTimesheetModalProps> = ({ | |||
| ...props | |||
| }) => { | |||
| const [lockConfirm, setLockConfirm] = useState(false); | |||
| const columns = [ | |||
| { | |||
| id: 'projectCode', | |||
| field: 'projectCode', | |||
| id: "projectCode", | |||
| field: "projectCode", | |||
| headerName: "Project Code and Name", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'task', | |||
| field: 'task', | |||
| headerName: "Task", | |||
| flex: 1, | |||
| id: "task", | |||
| field: "task", | |||
| headerName: "Task", | |||
| flex: 1, | |||
| }, | |||
| ]; | |||
| const rows = [{ | |||
| id: 1, projectCode: "M1001", task: "1.2" | |||
| const rows = [ | |||
| { | |||
| id: 1, | |||
| projectCode: "M1001", | |||
| task: "1.2", | |||
| }, | |||
| { | |||
| id: 2, projectCode: "M1301", task: "1.1" | |||
| }]; | |||
| id: 2, | |||
| projectCode: "M1301", | |||
| task: "1.1", | |||
| }, | |||
| ]; | |||
| return ( | |||
| <Modal open={props.isOpen} onClose={props.onClose}> | |||
| <div> | |||
| {/* <Typography variant="h5" id="modal-title" sx={{flex:1}}> | |||
| <div> | |||
| {/* <Typography variant="h5" id="modal-title" sx={{flex:1}}> | |||
| <div style={{ display: 'flex', justifyContent: 'space-between', width: '100%' }}> | |||
| Timesheet Input | |||
| </div> | |||
| </Typography> */} | |||
| <Card style={{flex: 10, marginBottom:'20px'}}> | |||
| {/* <TimesheetInputGrid setLockConfirm={setLockConfirm}/> */} | |||
| </Card> | |||
| <Card style={{ flex: 10, marginBottom: "20px" }}> | |||
| {/* <TimesheetInputGrid setLockConfirm={setLockConfirm}/> */} | |||
| </Card> | |||
| <div style={{ | |||
| display: 'flex', justifyContent: 'space-between', width: '100%', flex: 1 | |||
| }}> | |||
| <Button disabled={lockConfirm} variant="contained" onClick={props.onClose}> | |||
| Confirm | |||
| </Button> | |||
| <Button variant="contained" onClick={props.onClose} | |||
| sx={{"background-color":"#F890A5"}}> | |||
| Cancel | |||
| </Button> | |||
| </div> | |||
| <div | |||
| style={{ | |||
| display: "flex", | |||
| justifyContent: "space-between", | |||
| width: "100%", | |||
| flex: 1, | |||
| }} | |||
| > | |||
| <Button | |||
| disabled={lockConfirm} | |||
| variant="contained" | |||
| onClick={props.onClose} | |||
| > | |||
| Confirm | |||
| </Button> | |||
| <Button | |||
| variant="contained" | |||
| onClick={props.onClose} | |||
| sx={{ "background-color": "#F890A5" }} | |||
| > | |||
| Cancel | |||
| </Button> | |||
| </div> | |||
| </div> | |||
| </Modal> | |||
| ); | |||
| }; | |||
| @@ -8,20 +8,27 @@ import { Suspense } from "react"; | |||
| import Button from "@mui/material/Button"; | |||
| import Stack from "@mui/material/Stack"; | |||
| import Link from "next/link"; | |||
| import { t } from 'i18next'; | |||
| import { Box, Container, Modal, Select, SelectChangeEvent, Typography } from "@mui/material"; | |||
| import { Close } from '@mui/icons-material'; | |||
| import AddIcon from '@mui/icons-material/Add'; | |||
| import EditIcon from '@mui/icons-material/Edit'; | |||
| import DeleteIcon from '@mui/icons-material/DeleteOutlined'; | |||
| import SaveIcon from '@mui/icons-material/Save'; | |||
| import CancelIcon from '@mui/icons-material/Close'; | |||
| import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; | |||
| import ArrowBackIcon from '@mui/icons-material/ArrowBack'; | |||
| import { t } from "i18next"; | |||
| import { | |||
| Box, | |||
| Container, | |||
| Modal, | |||
| Select, | |||
| SelectChangeEvent, | |||
| Typography, | |||
| } from "@mui/material"; | |||
| import { Close } from "@mui/icons-material"; | |||
| import AddIcon from "@mui/icons-material/Add"; | |||
| import EditIcon from "@mui/icons-material/Edit"; | |||
| import DeleteIcon from "@mui/icons-material/DeleteOutlined"; | |||
| import SaveIcon from "@mui/icons-material/Save"; | |||
| import CancelIcon from "@mui/icons-material/Close"; | |||
| import ArrowForwardIcon from "@mui/icons-material/ArrowForward"; | |||
| import ArrowBackIcon from "@mui/icons-material/ArrowBack"; | |||
| import Swal from "sweetalert2"; | |||
| import { msg } from "../Swal/CustomAlerts"; | |||
| import React from "react"; | |||
| import { DatePicker } from '@mui/x-date-pickers/DatePicker'; | |||
| import { DatePicker } from "@mui/x-date-pickers/DatePicker"; | |||
| import { | |||
| GridRowsProp, | |||
| GridRowModesModel, | |||
| @@ -37,17 +44,17 @@ import { | |||
| GridRowEditStopReasons, | |||
| GridEditInputCell, | |||
| GridValueSetterParams, | |||
| } from '@mui/x-data-grid'; | |||
| } from "@mui/x-data-grid"; | |||
| import { LocalizationProvider } from "@mui/x-date-pickers"; | |||
| import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; | |||
| import dayjs from "dayjs"; | |||
| import { Props } from "react-intl/src/components/relative"; | |||
| const weekdays = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']; | |||
| const weekdays = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]; | |||
| interface BottomBarProps { | |||
| getHoursTotal: (column: string) => number; | |||
| setLockConfirm: (newLock: (oldLock: Boolean) => Boolean) => void; | |||
| setLockConfirm: (newLock: (oldLock: boolean) => boolean) => void; | |||
| setRows: (newRows: (oldRows: GridRowsProp) => GridRowsProp) => void; | |||
| setRowModesModel: ( | |||
| newModel: (oldModel: GridRowModesModel) => GridRowModesModel, | |||
| @@ -76,13 +83,16 @@ const EditToolbar = (props: EditToolbarProps) => { | |||
| const handleClickLeft = () => { | |||
| if (selectedDate) { | |||
| const newDate = selectedDate.add(-7, 'day'); | |||
| const newDate = selectedDate.add(-7, "day"); | |||
| setSelectedDate(newDate); | |||
| } | |||
| }; | |||
| const handleClickRight = () => { | |||
| if (selectedDate) { | |||
| const newDate = selectedDate.add(7, 'day') > dayjs()? dayjs(): selectedDate.add(7, 'day'); | |||
| const newDate = | |||
| selectedDate.add(7, "day") > dayjs() | |||
| ? dayjs() | |||
| : selectedDate.add(7, "day"); | |||
| setSelectedDate(newDate); | |||
| } | |||
| }; | |||
| @@ -98,24 +108,40 @@ const EditToolbar = (props: EditToolbarProps) => { | |||
| return ( | |||
| <LocalizationProvider dateAdapter={AdapterDayjs}> | |||
| <div style={{ display: 'flex', justifyContent: 'flex-end', width: '100%', paddingBottom:'20px'}}> | |||
| <Typography variant="h5" id="modal-title" sx={{flex:1}}> | |||
| Timesheet Input | |||
| </Typography> | |||
| <Button sx={{"border-radius":"30%", marginRight:'20px'}} variant="contained" onClick={handleClickLeft}> | |||
| <ArrowBackIcon/> | |||
| <div | |||
| style={{ | |||
| display: "flex", | |||
| justifyContent: "flex-end", | |||
| width: "100%", | |||
| paddingBottom: "20px", | |||
| }} | |||
| > | |||
| <Typography variant="h5" id="modal-title" sx={{ flex: 1 }}> | |||
| Timesheet Input | |||
| </Typography> | |||
| <Button | |||
| sx={{ "border-radius": "30%", marginRight: "20px" }} | |||
| variant="contained" | |||
| onClick={handleClickLeft} | |||
| > | |||
| <ArrowBackIcon /> | |||
| </Button> | |||
| <DatePicker | |||
| value={selectedDate} | |||
| onChange={handleDateChange} | |||
| disableFuture={true}/> | |||
| <Button sx={{"border-radius":"30%", margin:'0px 20px 0px 20px'}} variant="contained" onClick={handleClickRight}> | |||
| <ArrowForwardIcon/> | |||
| value={selectedDate} | |||
| onChange={handleDateChange} | |||
| disableFuture={true} | |||
| /> | |||
| <Button | |||
| sx={{ "border-radius": "30%", margin: "0px 20px 0px 20px" }} | |||
| variant="contained" | |||
| onClick={handleClickRight} | |||
| > | |||
| <ArrowForwardIcon /> | |||
| </Button> | |||
| </div> | |||
| </LocalizationProvider> | |||
| ); | |||
| } | |||
| }; | |||
| const BottomBar = (props: BottomBarProps) => { | |||
| const { setRows, setRowModesModel, getHoursTotal, setLockConfirm } = props; | |||
| @@ -126,75 +152,84 @@ const BottomBar = (props: BottomBarProps) => { | |||
| const handleAddClick = () => { | |||
| const id = newId; | |||
| setNewId(newId - 1); | |||
| setRows((oldRows) => [...oldRows, { id, projectCode: '', task: '', isNew: true }]); | |||
| setRows((oldRows) => [ | |||
| ...oldRows, | |||
| { id, projectCode: "", task: "", isNew: true }, | |||
| ]); | |||
| setRowModesModel((oldModel) => ({ | |||
| ...oldModel, | |||
| [id]: { mode: GridRowModes.Edit, fieldToFocus: 'projectCode' }, | |||
| [id]: { mode: GridRowModes.Edit, fieldToFocus: "projectCode" }, | |||
| })); | |||
| }; | |||
| const totalColDef = { | |||
| flex:1, | |||
| flex: 1, | |||
| // style: {color:getHoursTotal('mon')>24?"red":"black"} | |||
| }; | |||
| const TotalCell = ({value}: Props) => { | |||
| const TotalCell = ({ value }: Props) => { | |||
| const [invalid, setInvalid] = useState(false); | |||
| useEffect(()=> { | |||
| const newInvalid = (value??0)>24; | |||
| useEffect(() => { | |||
| const newInvalid = (value ?? 0) > 24; | |||
| setInvalid(newInvalid); | |||
| }, [value]); | |||
| return ( | |||
| <Box flex={1} style={{color: invalid?"red":"black"}}> | |||
| <Box flex={1} style={{ color: invalid ? "red" : "black" }}> | |||
| {value} | |||
| </Box> | |||
| ); | |||
| } | |||
| }; | |||
| const checkUnlockConfirmBtn = () => { | |||
| // setLockConfirm((oldLock)=> valid); | |||
| setLockConfirm((oldLock)=> weekdays.every(weekday => { | |||
| getHoursTotal(weekday) <= 24 | |||
| })); | |||
| } | |||
| setLockConfirm((oldLock) => | |||
| weekdays.every((weekday) => { | |||
| getHoursTotal(weekday) <= 24; | |||
| }), | |||
| ); | |||
| }; | |||
| return ( | |||
| <div> | |||
| <div style={{ display: 'flex', justifyContent: 'flex', width: '100%' }}> | |||
| <Box flex={5.7} textAlign={'right'} marginRight='4rem'> | |||
| <div style={{ display: "flex", justifyContent: "flex", width: "100%" }}> | |||
| <Box flex={5.7} textAlign={"right"} marginRight="4rem"> | |||
| <b>Total:</b> | |||
| </Box> | |||
| <TotalCell value={getHoursTotal('mon')}/> | |||
| <TotalCell value={getHoursTotal('tue')}/> | |||
| <TotalCell value={getHoursTotal('wed')}/> | |||
| <TotalCell value={getHoursTotal('thu')}/> | |||
| <TotalCell value={getHoursTotal('fri')}/> | |||
| <TotalCell value={getHoursTotal('sat')}/> | |||
| <TotalCell value={getHoursTotal('sun')}/> | |||
| <TotalCell value={getHoursTotal("mon")} /> | |||
| <TotalCell value={getHoursTotal("tue")} /> | |||
| <TotalCell value={getHoursTotal("wed")} /> | |||
| <TotalCell value={getHoursTotal("thu")} /> | |||
| <TotalCell value={getHoursTotal("fri")} /> | |||
| <TotalCell value={getHoursTotal("sat")} /> | |||
| <TotalCell value={getHoursTotal("sun")} /> | |||
| </div> | |||
| <Button variant="outlined" color="primary" startIcon={<AddIcon />} onClick={handleAddClick}> | |||
| <Button | |||
| variant="outlined" | |||
| color="primary" | |||
| startIcon={<AddIcon />} | |||
| onClick={handleAddClick} | |||
| > | |||
| Add record | |||
| </Button> | |||
| </div> | |||
| ); | |||
| } | |||
| }; | |||
| const EditFooter = (props: EditFooterProps) => { | |||
| return ( | |||
| <div style={{ display: 'flex', justifyContent: 'flex', width: '100%' }}> | |||
| <div style={{ display: "flex", justifyContent: "flex", width: "100%" }}> | |||
| <Box flex={1}> | |||
| <b>Total: </b> | |||
| </Box> | |||
| <Box flex={2}>ssss</Box> | |||
| </div> | |||
| ); | |||
| } | |||
| }; | |||
| interface TimesheetInputGridProps { | |||
| setLockConfirm: (newLock: (oldLock: Boolean) => Boolean) => void; | |||
| setLockConfirm: (newLock: (oldLock: boolean) => boolean) => void; | |||
| onClose?: () => void; | |||
| } | |||
| @@ -213,30 +248,37 @@ const initialRows: GridRowsProp = [ | |||
| }, | |||
| ]; | |||
| const options=["M1001", "M1301", "M1354", "M1973"]; | |||
| const options2=[ | |||
| const options = ["M1001", "M1301", "M1354", "M1973"]; | |||
| const options2 = [ | |||
| "1.1 - Preparation of preliminary Cost Estimate / Cost Plan", | |||
| "1.2 - Cash flow forecast", | |||
| "1.3 - Cost studies fo alterative design solutions", | |||
| "1.4 = Attend design co-ordination / project review meetings", | |||
| "1.5 - Prepare / Review RIC"]; | |||
| "1.5 - Prepare / Review RIC", | |||
| ]; | |||
| const getDateForHeader = (date : dayjs.Dayjs, weekday : number) => { | |||
| const getDateForHeader = (date: dayjs.Dayjs, weekday: number) => { | |||
| if (date.day() == 0) { | |||
| return date.add((weekday - date.day() - 7), 'day').format('DD MMM'); | |||
| return date.add(weekday - date.day() - 7, "day").format("DD MMM"); | |||
| } else { | |||
| return date.add(weekday - date.day(), 'day').format('DD MMM'); | |||
| return date.add(weekday - date.day(), "day").format("DD MMM"); | |||
| } | |||
| } | |||
| const TimesheetInputGrid: React.FC<TimesheetInputGridProps> = ({ ...props }) => { | |||
| }; | |||
| const TimesheetInputGrid: React.FC<TimesheetInputGridProps> = ({ | |||
| ...props | |||
| }) => { | |||
| const [rows, setRows] = useState(initialRows); | |||
| const [day, setDay] = useState(dayjs()); | |||
| const [rowModesModel, setRowModesModel] = React.useState<GridRowModesModel>({}); | |||
| const [rowModesModel, setRowModesModel] = React.useState<GridRowModesModel>( | |||
| {}, | |||
| ); | |||
| const { setLockConfirm } = props; | |||
| const handleRowEditStop: GridEventListener<'rowEditStop'> = (params, event) => { | |||
| const handleRowEditStop: GridEventListener<"rowEditStop"> = ( | |||
| params, | |||
| event, | |||
| ) => { | |||
| if (params.reason === GridRowEditStopReasons.rowFocusOut) { | |||
| event.defaultMuiPrevented = true; | |||
| } | |||
| @@ -247,7 +289,6 @@ const TimesheetInputGrid: React.FC<TimesheetInputGridProps> = ({ ...props }) => | |||
| }; | |||
| const handleSaveClick = (id: GridRowId) => () => { | |||
| setRowModesModel({ ...rowModesModel, [id]: { mode: GridRowModes.View } }); | |||
| }; | |||
| @@ -277,23 +318,23 @@ const TimesheetInputGrid: React.FC<TimesheetInputGridProps> = ({ ...props }) => | |||
| setRowModesModel(newRowModesModel); | |||
| }; | |||
| const getHoursTotal = (column : any) => { | |||
| const getHoursTotal = (column: any) => { | |||
| let sum = 0; | |||
| rows.forEach((row) => { | |||
| sum += row[column]??0; | |||
| sum += row[column] ?? 0; | |||
| }); | |||
| return sum; | |||
| }; | |||
| const weekdayColConfig : any = { | |||
| type: 'number', | |||
| const weekdayColConfig: any = { | |||
| type: "number", | |||
| // sortable: false, | |||
| //width: 100, | |||
| flex: 1, | |||
| align: 'left', | |||
| headerAlign: 'left', | |||
| align: "left", | |||
| headerAlign: "left", | |||
| editable: true, | |||
| renderEditCell: (value : any) => ( | |||
| renderEditCell: (value: any) => ( | |||
| <GridEditInputCell | |||
| {...value} | |||
| inputProps={{ | |||
| @@ -307,26 +348,28 @@ const TimesheetInputGrid: React.FC<TimesheetInputGridProps> = ({ ...props }) => | |||
| const columns: GridColDef[] = [ | |||
| { | |||
| field: 'actions', | |||
| type: 'actions', | |||
| headerName: 'Actions', | |||
| field: "actions", | |||
| type: "actions", | |||
| headerName: "Actions", | |||
| width: 100, | |||
| cellClassName: 'actions', | |||
| cellClassName: "actions", | |||
| getActions: ({ id }) => { | |||
| const isInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit; | |||
| if (isInEditMode) { | |||
| return [ | |||
| <GridActionsCellItem | |||
| key={`actions-${id}-save`} | |||
| icon={<SaveIcon />} | |||
| title="Save" | |||
| label="Save" | |||
| sx={{ | |||
| color: 'primary.main', | |||
| color: "primary.main", | |||
| }} | |||
| onClick={handleSaveClick(id)} | |||
| />, | |||
| <GridActionsCellItem | |||
| key={`actions-${id}-cancel`} | |||
| icon={<CancelIcon />} | |||
| title="Cancel" | |||
| label="Cancel" | |||
| @@ -339,6 +382,7 @@ const TimesheetInputGrid: React.FC<TimesheetInputGridProps> = ({ ...props }) => | |||
| return [ | |||
| <GridActionsCellItem | |||
| key={`actions-${id}-edit`} | |||
| icon={<EditIcon />} | |||
| title="Edit" | |||
| label="Edit" | |||
| @@ -347,100 +391,89 @@ const TimesheetInputGrid: React.FC<TimesheetInputGridProps> = ({ ...props }) => | |||
| color="inherit" | |||
| />, | |||
| <GridActionsCellItem | |||
| key={`actions-${id}-delete`} | |||
| title="Delete" | |||
| label="Delete" | |||
| icon={<DeleteIcon />} | |||
| onClick={handleDeleteClick(id)} | |||
| sx={{color:"red"}} | |||
| sx={{ color: "red" }} | |||
| />, | |||
| ]; | |||
| }, | |||
| }, | |||
| { | |||
| field: 'projectCode', | |||
| headerName: 'Project Code', | |||
| field: "projectCode", | |||
| headerName: "Project Code", | |||
| // width: 220, | |||
| flex: 2, | |||
| editable: true, | |||
| type: 'singleSelect', | |||
| type: "singleSelect", | |||
| valueOptions: options, | |||
| }, | |||
| { | |||
| field: 'task', | |||
| headerName: 'Task', | |||
| field: "task", | |||
| headerName: "Task", | |||
| // width: 220, | |||
| flex: 3, | |||
| editable: true, | |||
| type: 'singleSelect', | |||
| type: "singleSelect", | |||
| valueOptions: options2, | |||
| }, | |||
| { | |||
| // Mon | |||
| field: 'mon', | |||
| field: "mon", | |||
| ...weekdayColConfig, | |||
| renderHeader: () => { | |||
| return ( | |||
| <div>Mon - {getDateForHeader(day, 1)}</div> | |||
| ); | |||
| return <div>Mon - {getDateForHeader(day, 1)}</div>; | |||
| }, | |||
| }, | |||
| { | |||
| // Tue | |||
| field: 'tue', | |||
| field: "tue", | |||
| ...weekdayColConfig, | |||
| renderHeader: () => { | |||
| return ( | |||
| <div>Tue - {getDateForHeader(day, 2)}</div> | |||
| ); | |||
| return <div>Tue - {getDateForHeader(day, 2)}</div>; | |||
| }, | |||
| }, | |||
| { | |||
| // Wed | |||
| field: 'wed', | |||
| field: "wed", | |||
| ...weekdayColConfig, | |||
| renderHeader: () => { | |||
| return ( | |||
| <div>Wed - {getDateForHeader(day, 3)}</div> | |||
| ); | |||
| return <div>Wed - {getDateForHeader(day, 3)}</div>; | |||
| }, | |||
| }, | |||
| { | |||
| // Thu | |||
| field: 'thu', | |||
| field: "thu", | |||
| ...weekdayColConfig, | |||
| renderHeader: () => { | |||
| return ( | |||
| <div>Thu - {getDateForHeader(day, 4)}</div> | |||
| ); | |||
| return <div>Thu - {getDateForHeader(day, 4)}</div>; | |||
| }, | |||
| }, | |||
| { | |||
| // Fri | |||
| field: 'fri', | |||
| field: "fri", | |||
| ...weekdayColConfig, | |||
| renderHeader: () => { | |||
| return ( | |||
| <div>Fri - {getDateForHeader(day, 5)}</div> | |||
| ); | |||
| return <div>Fri - {getDateForHeader(day, 5)}</div>; | |||
| }, | |||
| }, | |||
| { | |||
| // Sat | |||
| field: 'sat', | |||
| field: "sat", | |||
| ...weekdayColConfig, | |||
| renderHeader: () => { | |||
| return ( | |||
| <div>Sat - {getDateForHeader(day, 6)}</div> | |||
| ); | |||
| return <div>Sat - {getDateForHeader(day, 6)}</div>; | |||
| }, | |||
| }, | |||
| { | |||
| // Sun | |||
| field: 'sun', | |||
| field: "sun", | |||
| ...weekdayColConfig, | |||
| renderHeader: () => { | |||
| return ( | |||
| <div style={{color:"red"}}>Sun - {getDateForHeader(day, 7)}</div> | |||
| <div style={{ color: "red" }}>Sun - {getDateForHeader(day, 7)}</div> | |||
| ); | |||
| }, | |||
| }, | |||
| @@ -457,22 +490,22 @@ const TimesheetInputGrid: React.FC<TimesheetInputGridProps> = ({ ...props }) => | |||
| <Box | |||
| sx={{ | |||
| // marginBottom: '-5px', | |||
| display: 'flex', | |||
| 'flex-direction': 'column', | |||
| display: "flex", | |||
| "flex-direction": "column", | |||
| // 'justify-content': 'flex-end', | |||
| padding: '20px', | |||
| height: '100%',//'30rem', | |||
| width: '100%', | |||
| '& .actions': { | |||
| color: 'text.secondary', | |||
| padding: "20px", | |||
| height: "100%", //'30rem', | |||
| width: "100%", | |||
| "& .actions": { | |||
| color: "text.secondary", | |||
| }, | |||
| '& .header': { | |||
| "& .header": { | |||
| // border: 1, | |||
| // 'border-width': '1px', | |||
| // 'border-color': 'grey', | |||
| }, | |||
| '& .textPrimary': { | |||
| color: 'text.primary', | |||
| "& .textPrimary": { | |||
| color: "text.primary", | |||
| }, | |||
| }} | |||
| > | |||
| @@ -498,14 +531,18 @@ const TimesheetInputGrid: React.FC<TimesheetInputGridProps> = ({ ...props }) => | |||
| initialState={{ | |||
| pagination: { paginationModel: { pageSize: 100 } }, | |||
| }} | |||
| sx={{flex:1}} | |||
| sx={{ flex: 1 }} | |||
| /> | |||
| <BottomBar getHoursTotal={getHoursTotal} setRows={setRows} setRowModesModel={setRowModesModel} setLockConfirm={setLockConfirm} | |||
| // sx={{flex:3}} | |||
| <BottomBar | |||
| getHoursTotal={getHoursTotal} | |||
| setRows={setRows} | |||
| setRowModesModel={setRowModesModel} | |||
| setLockConfirm={setLockConfirm} | |||
| // sx={{flex:3}} | |||
| /> | |||
| </Box> | |||
| ); | |||
| } | |||
| }; | |||
| export default TimesheetInputGrid; | |||
| @@ -7,11 +7,11 @@ import ListItemText from "@mui/material/ListItemText"; | |||
| import ListItemIcon from "@mui/material/ListItemIcon"; | |||
| import WorkHistory from "@mui/icons-material/WorkHistory"; | |||
| import Dashboard from "@mui/icons-material/Dashboard"; | |||
| import SummarizeIcon from '@mui/icons-material/Summarize'; | |||
| import PaymentsIcon from '@mui/icons-material/Payments'; | |||
| import AccountTreeIcon from '@mui/icons-material/AccountTree'; | |||
| import SummarizeIcon from "@mui/icons-material/Summarize"; | |||
| import PaymentsIcon from "@mui/icons-material/Payments"; | |||
| import AccountTreeIcon from "@mui/icons-material/AccountTree"; | |||
| import RequestQuote from "@mui/icons-material/RequestQuote"; | |||
| import PeopleIcon from '@mui/icons-material/People'; | |||
| import PeopleIcon from "@mui/icons-material/People"; | |||
| import Task from "@mui/icons-material/Task"; | |||
| import Assignment from "@mui/icons-material/Assignment"; | |||
| import Settings from "@mui/icons-material/Settings"; | |||
| @@ -22,8 +22,8 @@ import Typography from "@mui/material/Typography"; | |||
| import { usePathname } from "next/navigation"; | |||
| import Link from "next/link"; | |||
| import { NAVIGATION_CONTENT_WIDTH } from "@/config/uiConfig"; | |||
| import ArrowCircleLeftOutlinedIcon from '@mui/icons-material/ArrowCircleLeftOutlined'; | |||
| import ArrowCircleLeftRoundedIcon from '@mui/icons-material/ArrowCircleLeftRounded'; | |||
| import ArrowCircleLeftOutlinedIcon from "@mui/icons-material/ArrowCircleLeftOutlined"; | |||
| import ArrowCircleLeftRoundedIcon from "@mui/icons-material/ArrowCircleLeftRounded"; | |||
| interface NavigationItem { | |||
| icon: React.ReactNode; | |||
| @@ -34,17 +34,55 @@ interface NavigationItem { | |||
| const navigationItems: NavigationItem[] = [ | |||
| { icon: <WorkHistory />, label: "User Workspace", path: "/home" }, | |||
| { icon: <Dashboard />, label: "Dashboard", path: "", children: [ | |||
| { icon: <SummarizeIcon />, label: "Project Financial Summary", path: "/dashboard/ProjectFinancialSummary" }, | |||
| { icon: <PaymentsIcon />, label: "Company / Team Cash Flow", path: "/dashboard/CompanyTeamCashFlow" }, | |||
| { icon: <PaymentsIcon />, label: "Project Cash Flow", path: "/dashboard/ProjectCashFlow" }, | |||
| { icon: <AccountTreeIcon />, label: "Project Status by Client", path: "/dashboard/ProjectStatusByClient" }, | |||
| { icon: <PeopleIcon />, label: "Staff Utilization", path: "/dashboard/StaffUtilization" }, | |||
| ]}, | |||
| { icon: <RequestQuote />, label: "Staff Reimbursement", path: "/staffReimbursement", children: [ | |||
| { icon: <RequestQuote />, label: "ClaimApproval", path: "/staffReimbursement/ClaimApproval"}, | |||
| { icon: <RequestQuote />, label: "ClaimSummary", path: "/staffReimbursement/ClaimSummary"} | |||
| ] }, | |||
| { | |||
| icon: <Dashboard />, | |||
| label: "Dashboard", | |||
| path: "", | |||
| children: [ | |||
| { | |||
| icon: <SummarizeIcon />, | |||
| label: "Project Financial Summary", | |||
| path: "/dashboard/ProjectFinancialSummary", | |||
| }, | |||
| { | |||
| icon: <PaymentsIcon />, | |||
| label: "Company / Team Cash Flow", | |||
| path: "/dashboard/CompanyTeamCashFlow", | |||
| }, | |||
| { | |||
| icon: <PaymentsIcon />, | |||
| label: "Project Cash Flow", | |||
| path: "/dashboard/ProjectCashFlow", | |||
| }, | |||
| { | |||
| icon: <AccountTreeIcon />, | |||
| label: "Project Status by Client", | |||
| path: "/dashboard/ProjectStatusByClient", | |||
| }, | |||
| { | |||
| icon: <PeopleIcon />, | |||
| label: "Staff Utilization", | |||
| path: "/dashboard/StaffUtilization", | |||
| }, | |||
| ], | |||
| }, | |||
| { | |||
| icon: <RequestQuote />, | |||
| label: "Staff Reimbursement", | |||
| path: "/staffReimbursement", | |||
| children: [ | |||
| { | |||
| icon: <RequestQuote />, | |||
| label: "ClaimApproval", | |||
| path: "/staffReimbursement/ClaimApproval", | |||
| }, | |||
| { | |||
| icon: <RequestQuote />, | |||
| label: "ClaimSummary", | |||
| path: "/staffReimbursement/ClaimSummary", | |||
| }, | |||
| ], | |||
| }, | |||
| { icon: <Assignment />, label: "Project Management", path: "/projects" }, | |||
| { icon: <Task />, label: "Task Template", path: "/tasks" }, | |||
| { icon: <Payments />, label: "Invoice", path: "/invoice" }, | |||
| @@ -58,10 +96,10 @@ const NavigationContent: React.FC = () => { | |||
| const [openItems, setOpenItems] = React.useState<string[]>([]); | |||
| const toggleItem = (path: string) => { | |||
| setOpenItems(prevOpenItems => | |||
| setOpenItems((prevOpenItems) => | |||
| prevOpenItems.includes(path) | |||
| ? prevOpenItems.filter(item => item !== path) | |||
| : [...prevOpenItems, path] | |||
| ? prevOpenItems.filter((item) => item !== path) | |||
| : [...prevOpenItems, path], | |||
| ); | |||
| }; | |||
| @@ -84,25 +122,27 @@ const NavigationContent: React.FC = () => { | |||
| </ListItemButton> | |||
| {item.children && isOpen && ( | |||
| <List sx={{ pl: 2 }}> | |||
| {item.children.map(child => renderNavigationItem(child))} | |||
| {item.children.map((child) => renderNavigationItem(child))} | |||
| </List> | |||
| )} | |||
| </Box> | |||
| ); | |||
| }; | |||
| return ( | |||
| <Box sx={{ width: NAVIGATION_CONTENT_WIDTH }}> | |||
| <Box sx={{ p: "1.5rem" }}> | |||
| {/* Replace this with company logo and/or name */} | |||
| <Typography style={{display:"inline-block"}}variant="h4">TSMS</Typography> | |||
| <Typography style={{ display: "inline-block" }} variant="h4"> | |||
| TSMS | |||
| </Typography> | |||
| {/* <button className="float-right bg-transparent border-transparent" > | |||
| <ArrowCircleLeftRoundedIcon className="text-slate-400 hover:text-blue-400 hover:cursor-pointer " style={{ fontSize: '35px' }} /> | |||
| </button> */} | |||
| </Box> | |||
| <Divider /> | |||
| <List component="nav"> | |||
| {navigationItems.map(item => renderNavigationItem(item))} | |||
| {navigationItems.map((item) => renderNavigationItem(item))} | |||
| {/* {navigationItems.map(({ icon, label, path }, index) => { | |||
| return ( | |||
| <Box | |||
| @@ -11,36 +11,155 @@ type PageTitleProps = { | |||
| FourthTitle?: string; | |||
| }; | |||
| const PageTitle: React.FC<PageTitleProps> = ({ BigTitle, SecondTitle = '', ThirdTitle = '', FourthTitle = ''}) => { | |||
| const PageTitle: React.FC<PageTitleProps> = ({ | |||
| BigTitle, | |||
| SecondTitle = "", | |||
| ThirdTitle = "", | |||
| FourthTitle = "", | |||
| }) => { | |||
| const { t } = useTranslation("dashboard"); | |||
| return ( | |||
| <Grid item sm> | |||
| <div style={{marginTop:20,marginLeft:20}}> | |||
| <h1 style={{display:"inline-block",color:"#636363",verticalAlign:"top"}}>{BigTitle}</h1> | |||
| <hr color="#D6DCE1" style={{display:"inline-block",width:1,height:35,marginTop:25}} /> | |||
| <h3 style={{display:"inline-block",color:"#6BAFD8",verticalAlign:"top",marginTop:32}}>Overview</h3> | |||
| <h3 style={{display:"inline-block",color:"#6E6B7B",verticalAlign:"top",marginTop:32}}>{">"}</h3> | |||
| <h3 style={{display:"inline-block",color:"#6E6B7B",verticalAlign:"top",marginTop:32}}>{BigTitle}</h3> | |||
| {SecondTitle !== '' ? | |||
| <h3 style={{display:"inline-block",color:"#6E6B7B",verticalAlign:"top",marginTop:32}}>{">"} </h3> | |||
| : ""} | |||
| {SecondTitle !== '' ? | |||
| <h3 style={{display:"inline-block",color:"#6E6B7B",verticalAlign:"top",marginTop:32}}>{SecondTitle} </h3> | |||
| : ""} | |||
| {ThirdTitle !== '' ? | |||
| <h3 style={{display:"inline-block",color:"#6E6B7B",verticalAlign:"top",marginTop:32}}>{">"} </h3> | |||
| : ""} | |||
| {ThirdTitle !== '' ? | |||
| <h3 style={{display:"inline-block",color:"#6E6B7B",verticalAlign:"top",marginTop:32}}>{ThirdTitle} </h3> | |||
| : ""} | |||
| {FourthTitle !== '' ? | |||
| <h3 style={{display:"inline-block",color:"#6E6B7B",verticalAlign:"top",marginTop:32}}>{">"} </h3> | |||
| : ""} | |||
| {FourthTitle !== '' ? | |||
| <h3 style={{display:"inline-block",color:"#6E6B7B",verticalAlign:"top",marginTop:32}}>{FourthTitle} </h3> | |||
| : ""} | |||
| </div> | |||
| </Grid> | |||
| <Grid item sm> | |||
| <div style={{ marginTop: 20, marginLeft: 20 }}> | |||
| <h1 | |||
| style={{ | |||
| display: "inline-block", | |||
| color: "#636363", | |||
| verticalAlign: "top", | |||
| }} | |||
| > | |||
| {BigTitle} | |||
| </h1> | |||
| | |||
| <hr | |||
| color="#D6DCE1" | |||
| style={{ | |||
| display: "inline-block", | |||
| width: 1, | |||
| height: 35, | |||
| marginTop: 25, | |||
| }} | |||
| /> | |||
| | |||
| <h3 | |||
| style={{ | |||
| display: "inline-block", | |||
| color: "#6BAFD8", | |||
| verticalAlign: "top", | |||
| marginTop: 32, | |||
| }} | |||
| > | |||
| Overview | |||
| </h3> | |||
| | |||
| <h3 | |||
| style={{ | |||
| display: "inline-block", | |||
| color: "#6E6B7B", | |||
| verticalAlign: "top", | |||
| marginTop: 32, | |||
| }} | |||
| > | |||
| {">"} | |||
| </h3> | |||
| | |||
| <h3 | |||
| style={{ | |||
| display: "inline-block", | |||
| color: "#6E6B7B", | |||
| verticalAlign: "top", | |||
| marginTop: 32, | |||
| }} | |||
| > | |||
| {BigTitle} | |||
| </h3> | |||
| | |||
| {SecondTitle !== "" ? ( | |||
| <h3 | |||
| style={{ | |||
| display: "inline-block", | |||
| color: "#6E6B7B", | |||
| verticalAlign: "top", | |||
| marginTop: 32, | |||
| }} | |||
| > | |||
| {">"} | |||
| </h3> | |||
| ) : ( | |||
| "" | |||
| )} | |||
| {SecondTitle !== "" ? ( | |||
| <h3 | |||
| style={{ | |||
| display: "inline-block", | |||
| color: "#6E6B7B", | |||
| verticalAlign: "top", | |||
| marginTop: 32, | |||
| }} | |||
| > | |||
| {SecondTitle} | |||
| </h3> | |||
| ) : ( | |||
| "" | |||
| )} | |||
| {ThirdTitle !== "" ? ( | |||
| <h3 | |||
| style={{ | |||
| display: "inline-block", | |||
| color: "#6E6B7B", | |||
| verticalAlign: "top", | |||
| marginTop: 32, | |||
| }} | |||
| > | |||
| {">"} | |||
| </h3> | |||
| ) : ( | |||
| "" | |||
| )} | |||
| {ThirdTitle !== "" ? ( | |||
| <h3 | |||
| style={{ | |||
| display: "inline-block", | |||
| color: "#6E6B7B", | |||
| verticalAlign: "top", | |||
| marginTop: 32, | |||
| }} | |||
| > | |||
| {ThirdTitle} | |||
| </h3> | |||
| ) : ( | |||
| "" | |||
| )} | |||
| {FourthTitle !== "" ? ( | |||
| <h3 | |||
| style={{ | |||
| display: "inline-block", | |||
| color: "#6E6B7B", | |||
| verticalAlign: "top", | |||
| marginTop: 32, | |||
| }} | |||
| > | |||
| {">"} | |||
| </h3> | |||
| ) : ( | |||
| "" | |||
| )} | |||
| {FourthTitle !== "" ? ( | |||
| <h3 | |||
| style={{ | |||
| display: "inline-block", | |||
| color: "#6E6B7B", | |||
| verticalAlign: "top", | |||
| marginTop: 32, | |||
| }} | |||
| > | |||
| {FourthTitle} | |||
| </h3> | |||
| ) : ( | |||
| "" | |||
| )} | |||
| </div> | |||
| </Grid> | |||
| ); | |||
| }; | |||
| @@ -1,84 +1,175 @@ | |||
| "use client"; | |||
| import * as React from "react"; | |||
| import Grid from "@mui/material/Grid"; | |||
| import { useState,useEffect, useMemo } from 'react' | |||
| import { useState, useEffect, useMemo } from "react"; | |||
| import Paper from "@mui/material/Paper"; | |||
| import { TFunction } from "i18next"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import {Card,CardHeader} from '@mui/material'; | |||
| import { Card, CardHeader } from "@mui/material"; | |||
| import CustomSearchForm from "../CustomSearchForm/CustomSearchForm"; | |||
| import CustomDatagrid from '../CustomDatagrid/CustomDatagrid'; | |||
| import ReactApexChart from 'react-apexcharts'; | |||
| import { ApexOptions } from 'apexcharts'; | |||
| import { GridColDef, GridRowSelectionModel} from '@mui/x-data-grid'; | |||
| import ReportProblemIcon from '@mui/icons-material/ReportProblem'; | |||
| import dynamic from 'next/dynamic'; | |||
| import '../../app/global.css'; | |||
| import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; | |||
| import ReactApexChart from "react-apexcharts"; | |||
| import { ApexOptions } from "apexcharts"; | |||
| import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid"; | |||
| import ReportProblemIcon from "@mui/icons-material/ReportProblem"; | |||
| import dynamic from "next/dynamic"; | |||
| import "../../app/global.css"; | |||
| import { AnyARecord, AnyCnameRecord } from "dns"; | |||
| import SearchBox, { Criterion } from "../SearchBox"; | |||
| import ProgressByClientSearch from "@/components/ProgressByClientSearch"; | |||
| import { Suspense } from "react"; | |||
| const ProgressByClient: React.FC = () => { | |||
| const [activeTab, setActiveTab] = useState('financialSummary'); | |||
| const [SearchCriteria, setSearchCriteria] = React.useState({}) | |||
| const [activeTab, setActiveTab] = useState("financialSummary"); | |||
| const [SearchCriteria, setSearchCriteria] = React.useState({}); | |||
| const { t } = useTranslation("dashboard"); | |||
| const [clientCode, setClientCode] = useState(''); | |||
| const [clientName, setClientName] = useState(''); | |||
| const [subsidiaryClientCode, setSubsidiaryClientCode] = useState(''); | |||
| const [subsidiaryClientName, setSubsidiaryClientName] = useState(''); | |||
| const [projectArray, setProjectArray] : any[] = useState([]); | |||
| const [percentageArray, setPercentageArray] : any[] = useState([]); | |||
| const [colorArray, setColorArray] : any[] = useState([]); | |||
| const [selectionModel, setSelectionModel] : any[] = React.useState([]); | |||
| const [pieChartColor, setPieChartColor] : any[] = React.useState([]); | |||
| const [totalSpentPercentage, setTotalSpentPercentage] : any = React.useState(); | |||
| const [projectBudgetManhour, setProjectBudgetManhour] :any = React.useState('-'); | |||
| const [actualManhourSpent, setActualManhourSpent] :any = React.useState('-'); | |||
| const [remainedManhour, setRemainedManhour] :any = React.useState('-'); | |||
| const [lastUpdate, setLastUpdate] :any = React.useState('-'); | |||
| const [dropdownDemo, setDropdownDemo] = useState(''); | |||
| const [clientCode, setClientCode] = useState(""); | |||
| const [clientName, setClientName] = useState(""); | |||
| const [subsidiaryClientCode, setSubsidiaryClientCode] = useState(""); | |||
| const [subsidiaryClientName, setSubsidiaryClientName] = useState(""); | |||
| const [projectArray, setProjectArray]: any[] = useState([]); | |||
| const [percentageArray, setPercentageArray]: any[] = useState([]); | |||
| const [colorArray, setColorArray]: any[] = useState([]); | |||
| const [selectionModel, setSelectionModel]: any[] = React.useState([]); | |||
| const [pieChartColor, setPieChartColor]: any[] = React.useState([]); | |||
| const [totalSpentPercentage, setTotalSpentPercentage]: any = React.useState(); | |||
| const [projectBudgetManhour, setProjectBudgetManhour]: any = | |||
| React.useState("-"); | |||
| const [actualManhourSpent, setActualManhourSpent]: any = React.useState("-"); | |||
| const [remainedManhour, setRemainedManhour]: any = React.useState("-"); | |||
| const [lastUpdate, setLastUpdate]: any = React.useState("-"); | |||
| const [dropdownDemo, setDropdownDemo] = useState(""); | |||
| const [dateDemo, setDateDemo] = useState(null); | |||
| const [checkboxDemo, setCheckboxDemo] = useState(false); | |||
| const [receiptFromDate, setReceiptFromDate] = useState(null); | |||
| const [receiptToDate, setReceiptToDate] = useState(null); | |||
| const [selectedRows, setSelectedRows] = useState([]); | |||
| const 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"} | |||
| ] | |||
| 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 rows2 = [{id: 1,project:"Consultancy Project 123",team:"XXX", teamLeader:"XXX", currentStage:"Contract Documentation", budgetedManhour:"200.00",spentManhour:"120.00",remainedManhour:"80.00",comingPaymentMilestone:"31/03/2024",alert:false,color:"#f57f90"}, | |||
| {id: 2,project:"Consultancy Project 456",team:"XXX", teamLeader:"XXX", currentStage:"Report Preparation", budgetedManhour:"400.00",spentManhour:"200.00",remainedManhour:"200.00",comingPaymentMilestone:"20/02/2024",alert:false,color:"#94f7d6"}, | |||
| {id: 3,project:"Construction Project A",team:"YYY", teamLeader:"YYY", currentStage:"Construction", budgetedManhour:"187.50",spentManhour:"200.00",remainedManhour:"12.50",comingPaymentMilestone:"13/12/2023",alert:true,color:"#87c5f5"}, | |||
| {id: 4,project:"Construction Project B",team:"XXX", teamLeader:"XXX", currentStage:"Post Construction", budgetedManhour:"100.00",spentManhour:"40.00",remainedManhour:"60.00",comingPaymentMilestone:"05/01/2024",alert:false,color:"#ab95f5"}, | |||
| {id: 5,project:"Construction Project C",team:"YYY", teamLeader:"YYY", currentStage:"Construction", budgetedManhour:"300.00",spentManhour:"150.00",remainedManhour:"150.00",comingPaymentMilestone:"31/03/2024",alert:false,color:"#fcd68b"}, | |||
| ] | |||
| const rows2 = [ | |||
| { | |||
| id: 1, | |||
| project: "Consultancy Project 123", | |||
| team: "XXX", | |||
| teamLeader: "XXX", | |||
| currentStage: "Contract Documentation", | |||
| budgetedManhour: "200.00", | |||
| spentManhour: "120.00", | |||
| remainedManhour: "80.00", | |||
| comingPaymentMilestone: "31/03/2024", | |||
| alert: false, | |||
| color: "#f57f90", | |||
| }, | |||
| { | |||
| id: 2, | |||
| project: "Consultancy Project 456", | |||
| team: "XXX", | |||
| teamLeader: "XXX", | |||
| currentStage: "Report Preparation", | |||
| budgetedManhour: "400.00", | |||
| spentManhour: "200.00", | |||
| remainedManhour: "200.00", | |||
| comingPaymentMilestone: "20/02/2024", | |||
| alert: false, | |||
| color: "#94f7d6", | |||
| }, | |||
| { | |||
| id: 3, | |||
| project: "Construction Project A", | |||
| team: "YYY", | |||
| teamLeader: "YYY", | |||
| currentStage: "Construction", | |||
| budgetedManhour: "187.50", | |||
| spentManhour: "200.00", | |||
| remainedManhour: "12.50", | |||
| comingPaymentMilestone: "13/12/2023", | |||
| alert: true, | |||
| color: "#87c5f5", | |||
| }, | |||
| { | |||
| id: 4, | |||
| project: "Construction Project B", | |||
| team: "XXX", | |||
| teamLeader: "XXX", | |||
| currentStage: "Post Construction", | |||
| budgetedManhour: "100.00", | |||
| spentManhour: "40.00", | |||
| remainedManhour: "60.00", | |||
| comingPaymentMilestone: "05/01/2024", | |||
| alert: false, | |||
| color: "#ab95f5", | |||
| }, | |||
| { | |||
| id: 5, | |||
| project: "Construction Project C", | |||
| team: "YYY", | |||
| teamLeader: "YYY", | |||
| currentStage: "Construction", | |||
| budgetedManhour: "300.00", | |||
| spentManhour: "150.00", | |||
| remainedManhour: "150.00", | |||
| comingPaymentMilestone: "31/03/2024", | |||
| alert: false, | |||
| color: "#fcd68b", | |||
| }, | |||
| ]; | |||
| const columns = [ | |||
| { | |||
| id: 'clientCode', | |||
| field: 'clientCode', | |||
| headerName: "Client Code", | |||
| flex: 1, | |||
| { | |||
| id: "clientCode", | |||
| field: "clientCode", | |||
| headerName: "Client Code", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'clientName', | |||
| field: 'clientName', | |||
| headerName: "Client Name", | |||
| flex: 1, | |||
| id: "clientName", | |||
| field: "clientName", | |||
| headerName: "Client Name", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'clientSubsidiaryCode', | |||
| field: 'clientSubsidiaryCode', | |||
| id: "clientSubsidiaryCode", | |||
| field: "clientSubsidiaryCode", | |||
| headerName: "Client Subsidiary Code", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'noOfProjects', | |||
| field: 'noOfProjects', | |||
| id: "noOfProjects", | |||
| field: "noOfProjects", | |||
| headerName: "No. of Projects", | |||
| flex: 1, | |||
| }, | |||
| @@ -86,110 +177,139 @@ const ProgressByClient: React.FC = () => { | |||
| const columns2 = [ | |||
| { | |||
| id:"color", | |||
| field:'color', | |||
| headerName:'', | |||
| renderCell: (params:any) => { | |||
| id: "color", | |||
| field: "color", | |||
| headerName: "", | |||
| renderCell: (params: any) => { | |||
| return ( | |||
| <span className="dot" style={{height:"15px",width:"15px",borderRadius:"50%",backgroundColor:`${params.row.color}`,display:"inline-block"}}></span> | |||
| ) | |||
| <span | |||
| className="dot" | |||
| style={{ | |||
| height: "15px", | |||
| width: "15px", | |||
| borderRadius: "50%", | |||
| backgroundColor: `${params.row.color}`, | |||
| display: "inline-block", | |||
| }} | |||
| ></span> | |||
| ); | |||
| }, | |||
| flex:0.1, | |||
| flex: 0.1, | |||
| }, | |||
| { | |||
| id: 'project', | |||
| field: 'project', | |||
| id: "project", | |||
| field: "project", | |||
| headerName: "Project", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'team', | |||
| field: 'team', | |||
| }, | |||
| { | |||
| id: "team", | |||
| field: "team", | |||
| headerName: "Team", | |||
| flex: 0.8, | |||
| }, | |||
| { | |||
| id: 'teamLeader', | |||
| field: 'teamLeader', | |||
| headerName: "Team Leader", | |||
| flex: 0.8, | |||
| }, | |||
| { | |||
| id: 'currentStage', | |||
| field: 'currentStage', | |||
| headerName: "Current Stage", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'budgetedManhour', | |||
| field: 'budgetedManhour', | |||
| headerName: "Budgeted Manhour", | |||
| flex: 0.8, | |||
| }, | |||
| { | |||
| id: 'spentManhour', | |||
| field: 'spentManhour', | |||
| headerName: "Spent Manhour", | |||
| renderCell: (params:any) => { | |||
| if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | |||
| return( | |||
| <span className="text-red-300">{params.row.spentManhour}</span> | |||
| ) | |||
| } else { | |||
| return ( | |||
| <span>{params.row.spentManhour}</span> | |||
| ) | |||
| } | |||
| }, | |||
| flex: 0.8, | |||
| }, | |||
| { | |||
| id: 'remainedManhour', | |||
| field: 'remainedManhour', | |||
| headerName: "Remained Manhour", | |||
| renderCell: (params:any) => { | |||
| if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | |||
| return( | |||
| <span className="text-red-300">({params.row.remainedManhour})</span> | |||
| ) | |||
| } else { | |||
| return ( | |||
| <span>{params.row.remainedManhour}</span> | |||
| ) | |||
| } | |||
| { | |||
| id: "teamLeader", | |||
| field: "teamLeader", | |||
| headerName: "Team Leader", | |||
| flex: 0.8, | |||
| }, | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'comingPaymentMilestone', | |||
| field: 'comingPaymentMilestone', | |||
| headerName: "Coming Payment Milestone", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'alert', | |||
| field: 'alert', | |||
| headerName: "Alert", | |||
| renderCell: (params:any) => { | |||
| if (params.row.alert === true) { | |||
| return ( | |||
| <span className="text-red-300 text-center"><ReportProblemIcon/></span> | |||
| ) | |||
| } else { | |||
| return ( | |||
| <span></span> | |||
| ) | |||
| } | |||
| { | |||
| id: "currentStage", | |||
| field: "currentStage", | |||
| headerName: "Current Stage", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "budgetedManhour", | |||
| field: "budgetedManhour", | |||
| headerName: "Budgeted Manhour", | |||
| flex: 0.8, | |||
| }, | |||
| flex: 0.2, | |||
| }, | |||
| ]; | |||
| { | |||
| id: "spentManhour", | |||
| field: "spentManhour", | |||
| headerName: "Spent Manhour", | |||
| renderCell: (params: any) => { | |||
| if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | |||
| return ( | |||
| <span className="text-red-300">{params.row.spentManhour}</span> | |||
| ); | |||
| } else { | |||
| return <span>{params.row.spentManhour}</span>; | |||
| } | |||
| }, | |||
| flex: 0.8, | |||
| }, | |||
| { | |||
| id: "remainedManhour", | |||
| field: "remainedManhour", | |||
| headerName: "Remained Manhour", | |||
| renderCell: (params: any) => { | |||
| if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | |||
| return ( | |||
| <span className="text-red-300">({params.row.remainedManhour})</span> | |||
| ); | |||
| } else { | |||
| return <span>{params.row.remainedManhour}</span>; | |||
| } | |||
| }, | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "comingPaymentMilestone", | |||
| field: "comingPaymentMilestone", | |||
| headerName: "Coming Payment Milestone", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "alert", | |||
| field: "alert", | |||
| headerName: "Alert", | |||
| renderCell: (params: any) => { | |||
| if (params.row.alert === true) { | |||
| return ( | |||
| <span className="text-red-300 text-center"> | |||
| <ReportProblemIcon /> | |||
| </span> | |||
| ); | |||
| } else { | |||
| return <span></span>; | |||
| } | |||
| }, | |||
| flex: 0.2, | |||
| }, | |||
| ]; | |||
| const InputFields = [ | |||
| { id: "clientCode", label: "Client Code", type: 'text', value: clientCode, setValue: setClientCode }, | |||
| { id: "clientName", label: "Client Name", type: 'text', value: clientName, setValue: setClientName }, | |||
| { id: "subsidiaryClientCode", label: "Subsidiary Client Code", type:'text', value:subsidiaryClientCode, setValue: setSubsidiaryClientCode}, | |||
| { id: "subsidiaryClientName", label: "Subsidiary Client Name", type:'text', value:subsidiaryClientName, setValue: setSubsidiaryClientName}, | |||
| { | |||
| id: "clientCode", | |||
| label: "Client Code", | |||
| type: "text", | |||
| value: clientCode, | |||
| setValue: setClientCode, | |||
| }, | |||
| { | |||
| id: "clientName", | |||
| label: "Client Name", | |||
| type: "text", | |||
| value: clientName, | |||
| setValue: setClientName, | |||
| }, | |||
| { | |||
| id: "subsidiaryClientCode", | |||
| label: "Subsidiary Client Code", | |||
| type: "text", | |||
| value: subsidiaryClientCode, | |||
| setValue: setSubsidiaryClientCode, | |||
| }, | |||
| { | |||
| id: "subsidiaryClientName", | |||
| label: "Subsidiary Client Name", | |||
| type: "text", | |||
| value: subsidiaryClientName, | |||
| setValue: setSubsidiaryClientName, | |||
| }, | |||
| // { 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 }, | |||
| @@ -197,73 +317,85 @@ const ProgressByClient: React.FC = () => { | |||
| // setValue: [setReceiptFromDate, setReceiptToDate],type: 'dateRange' }, | |||
| ]; | |||
| const stageDeadline = ["31/03/2024","20/02/2024","01/12/2023","05/01/2024","31/03/2023"] | |||
| const stageDeadline = [ | |||
| "31/03/2024", | |||
| "20/02/2024", | |||
| "01/12/2023", | |||
| "05/01/2024", | |||
| "31/03/2023", | |||
| ]; | |||
| const series2: ApexAxisChartSeries | ApexNonAxisChartSeries = [ | |||
| { | |||
| data: [17.1, 28.6, 5.7, 48.6], | |||
| }, | |||
| ]; | |||
| const series2: ApexAxisChartSeries | ApexNonAxisChartSeries = [{ | |||
| data: [17.1, 28.6, 5.7, 48.6], | |||
| }]; | |||
| const series: ApexAxisChartSeries | ApexNonAxisChartSeries = [ | |||
| { | |||
| name: "Current Stage Completion Percentage", | |||
| data: [80, 55, 40, 65, 70], | |||
| }, | |||
| ]; | |||
| const series: ApexAxisChartSeries | ApexNonAxisChartSeries = [{ | |||
| name: 'Current Stage Completion Percentage', | |||
| data: [80, 55, 40, 65, 70], | |||
| }]; | |||
| const options2 : ApexOptions = { | |||
| const options2: ApexOptions = { | |||
| chart: { | |||
| type: 'donut', | |||
| type: "donut", | |||
| }, | |||
| colors: colorArray, | |||
| plotOptions: { | |||
| pie: { | |||
| donut:{ | |||
| labels:{ | |||
| show:true, | |||
| name:{ | |||
| show:true, | |||
| donut: { | |||
| labels: { | |||
| show: true, | |||
| name: { | |||
| show: true, | |||
| }, | |||
| value:{ | |||
| show:true, | |||
| value: { | |||
| show: true, | |||
| fontWeight: 500, | |||
| fontSize: '30px', | |||
| fontSize: "30px", | |||
| color: "#3e98c7", | |||
| }, | |||
| total:{ | |||
| total: { | |||
| show: true, | |||
| showAlways: true, | |||
| label: 'Spent', | |||
| fontFamily: 'sans-serif', | |||
| label: "Spent", | |||
| fontFamily: "sans-serif", | |||
| formatter: function (val) { | |||
| return totalSpentPercentage + "%" | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return totalSpentPercentage + "%"; | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| labels: projectArray, | |||
| legend: { | |||
| show: false, | |||
| }, | |||
| responsive: [{ | |||
| breakpoint: 480, | |||
| options: { | |||
| chart: { | |||
| width: 200 | |||
| responsive: [ | |||
| { | |||
| breakpoint: 480, | |||
| options: { | |||
| chart: { | |||
| width: 200, | |||
| }, | |||
| legend: { | |||
| position: "bottom", | |||
| show: false, | |||
| }, | |||
| }, | |||
| legend: { | |||
| position: 'bottom', | |||
| show:false | |||
| } | |||
| } | |||
| }] | |||
| } | |||
| }, | |||
| ], | |||
| }; | |||
| const options: ApexOptions = { | |||
| chart: { | |||
| type: 'bar', | |||
| height: 350 | |||
| type: "bar", | |||
| height: 350, | |||
| }, | |||
| colors: ['#f57f90', '#94f7d6', '#87c5f5', '#ab95f5', '#fcd68b'], | |||
| colors: ["#f57f90", "#94f7d6", "#87c5f5", "#ab95f5", "#fcd68b"], | |||
| plotOptions: { | |||
| bar: { | |||
| horizontal: true, | |||
| @@ -271,107 +403,116 @@ const ProgressByClient: React.FC = () => { | |||
| }, | |||
| }, | |||
| dataLabels: { | |||
| enabled: false | |||
| enabled: false, | |||
| }, | |||
| xaxis: { | |||
| categories: [ | |||
| 'Consultancy Project 123', | |||
| 'Consultancy Project 456', | |||
| 'Construction Project A', | |||
| 'Construction Project B', | |||
| 'Construction Project C', | |||
| "Consultancy Project 123", | |||
| "Consultancy Project 456", | |||
| "Construction Project A", | |||
| "Construction Project B", | |||
| "Construction Project C", | |||
| ], | |||
| }, | |||
| yaxis: { | |||
| title: { | |||
| text: 'Projects' | |||
| text: "Projects", | |||
| }, | |||
| labels: { | |||
| maxWidth: 200, | |||
| maxWidth: 200, | |||
| style: { | |||
| cssClass: 'apexcharts-yaxis-label', | |||
| cssClass: "apexcharts-yaxis-label", | |||
| }, | |||
| }, | |||
| }, | |||
| title: { | |||
| text: 'Current Stage Completion Percentage', | |||
| align: 'center' | |||
| text: "Current Stage Completion Percentage", | |||
| align: "center", | |||
| }, | |||
| grid: { | |||
| borderColor: '#f1f1f1', | |||
| borderColor: "#f1f1f1", | |||
| }, | |||
| annotations: { | |||
| } | |||
| annotations: {}, | |||
| }; | |||
| const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => { | |||
| const selectedRowsData = rows2.filter((row) => | |||
| newSelectionModel.includes(row.id) | |||
| newSelectionModel.includes(row.id), | |||
| ); | |||
| console.log(selectedRowsData) | |||
| const projectArray = [] | |||
| const pieChartColorArray = [] | |||
| let totalSpent = 0 | |||
| let totalBudgetManhour = 0 | |||
| const percentageArray = [] | |||
| console.log(selectedRowsData); | |||
| const projectArray = []; | |||
| const pieChartColorArray = []; | |||
| let totalSpent = 0; | |||
| let totalBudgetManhour = 0; | |||
| const percentageArray = []; | |||
| for (let i = 0; i <= selectedRowsData.length; i++) { | |||
| if (i === selectedRowsData.length && i > 0) { | |||
| projectArray.push("Remained") | |||
| projectArray.push("Remained"); | |||
| } else if (selectedRowsData.length > 0) { | |||
| projectArray.push(selectedRowsData[i].project) | |||
| totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour) | |||
| totalSpent += Number(selectedRowsData[i].spentManhour) | |||
| pieChartColorArray.push(selectedRowsData[i].color) | |||
| projectArray.push(selectedRowsData[i].project); | |||
| totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour); | |||
| totalSpent += Number(selectedRowsData[i].spentManhour); | |||
| pieChartColorArray.push(selectedRowsData[i].color); | |||
| } | |||
| } | |||
| for (let i = 0; i <= selectedRowsData.length; i++) { | |||
| if (i === selectedRowsData.length && i > 0) { | |||
| const remainedManhour = (totalBudgetManhour - totalSpent) | |||
| percentageArray.push(Number(((remainedManhour / totalBudgetManhour) * 100).toFixed(1))) | |||
| const remainedManhour = totalBudgetManhour - totalSpent; | |||
| percentageArray.push( | |||
| Number(((remainedManhour / totalBudgetManhour) * 100).toFixed(1)), | |||
| ); | |||
| } else if (selectedRowsData.length > 0) { | |||
| let percentage = ((Number(selectedRowsData[i].spentManhour) / totalBudgetManhour) * 100).toFixed(1) | |||
| percentageArray.push(Number(percentage)) | |||
| const percentage = ( | |||
| (Number(selectedRowsData[i].spentManhour) / totalBudgetManhour) * | |||
| 100 | |||
| ).toFixed(1); | |||
| percentageArray.push(Number(percentage)); | |||
| } | |||
| } | |||
| setProjectBudgetManhour(totalBudgetManhour.toFixed(2)) | |||
| setActualManhourSpent(totalSpent.toFixed(2)) | |||
| setRemainedManhour((totalBudgetManhour - totalSpent).toFixed(2)) | |||
| setLastUpdate(new Date().toLocaleDateString('en-GB')) | |||
| setSelectionModel(newSelectionModel) | |||
| console.log(projectArray) | |||
| setProjectArray(projectArray) | |||
| setPercentageArray(percentageArray) | |||
| console.log(percentageArray) | |||
| setTotalSpentPercentage(((totalSpent/totalBudgetManhour)*100).toFixed(1)) | |||
| setProjectBudgetManhour(totalBudgetManhour.toFixed(2)); | |||
| setActualManhourSpent(totalSpent.toFixed(2)); | |||
| setRemainedManhour((totalBudgetManhour - totalSpent).toFixed(2)); | |||
| setLastUpdate(new Date().toLocaleDateString("en-GB")); | |||
| setSelectionModel(newSelectionModel); | |||
| console.log(projectArray); | |||
| setProjectArray(projectArray); | |||
| setPercentageArray(percentageArray); | |||
| console.log(percentageArray); | |||
| setTotalSpentPercentage( | |||
| ((totalSpent / totalBudgetManhour) * 100).toFixed(1), | |||
| ); | |||
| if (projectArray.length > 0 && projectArray.includes("Remained")) { | |||
| const nonLastRecordColors = pieChartColorArray; | |||
| setColorArray([...nonLastRecordColors.slice(0, projectArray.length - 1), "#a3a3a3"]); | |||
| setColorArray([ | |||
| ...nonLastRecordColors.slice(0, projectArray.length - 1), | |||
| "#a3a3a3", | |||
| ]); | |||
| } else { | |||
| setColorArray(pieChartColorArray); | |||
| } | |||
| }; | |||
| const applySearch = (data: any) => { | |||
| console.log(data) | |||
| setSearchCriteria(data) | |||
| } | |||
| console.log(data); | |||
| setSearchCriteria(data); | |||
| }; | |||
| return ( | |||
| <Grid item sm> | |||
| {/* <CustomSearchForm applySearch={applySearch} fields={InputFields}/> */} | |||
| {/* <CustomDatagrid rows={rows} columns={columns} columnWidth={200} dataGridHeight={300}/> */} | |||
| <div style={{display:"inline-block",width:"70%"}}> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card> | |||
| <CardHeader className="text-slate-500" title="Project Progress"/> | |||
| <div style={{display:"inline-block",width:"99%"}}> | |||
| <ReactApexChart | |||
| options={options} | |||
| series={series} | |||
| type="bar" | |||
| height={350} | |||
| /> | |||
| </div> | |||
| {/* <div style={{display:"inline-block",width:"20%",verticalAlign:"top",textAlign:"center"}}> | |||
| <Grid item sm> | |||
| {/* <CustomSearchForm applySearch={applySearch} fields={InputFields}/> */} | |||
| {/* <CustomDatagrid rows={rows} columns={columns} columnWidth={200} dataGridHeight={300}/> */} | |||
| <div style={{ display: "inline-block", width: "70%" }}> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card> | |||
| <CardHeader className="text-slate-500" title="Project Progress" /> | |||
| <div style={{ display: "inline-block", width: "99%" }}> | |||
| <ReactApexChart | |||
| options={options} | |||
| series={series} | |||
| type="bar" | |||
| height={350} | |||
| /> | |||
| </div> | |||
| {/* <div style={{display:"inline-block",width:"20%",verticalAlign:"top",textAlign:"center"}}> | |||
| <p><strong><u>Stage Deadline</u></strong></p> | |||
| {stageDeadline.map((date, index) => { | |||
| const marginTop = index === 0 ? 25 : 20; | |||
| @@ -380,54 +521,122 @@ const ProgressByClient: React.FC = () => { | |||
| ); | |||
| })} | |||
| </div> */} | |||
| <CardHeader className="text-slate-500" title="Current Stage Due Date"/> | |||
| <div style={{display:"inline-block",width:"99%",marginLeft:10}}> | |||
| <CustomDatagrid rows={rows2} columns={columns2} columnWidth={200} dataGridHeight={300} checkboxSelection={true} onRowSelectionModelChange={handleSelectionChange} selectionModel={selectionModel}/> | |||
| </div> | |||
| </Card> | |||
| </Grid> | |||
| <CardHeader | |||
| className="text-slate-500" | |||
| title="Current Stage Due Date" | |||
| /> | |||
| <div | |||
| style={{ display: "inline-block", width: "99%", marginLeft: 10 }} | |||
| > | |||
| <CustomDatagrid | |||
| rows={rows2} | |||
| columns={columns2} | |||
| columnWidth={200} | |||
| dataGridHeight={300} | |||
| checkboxSelection={true} | |||
| onRowSelectionModelChange={handleSelectionChange} | |||
| selectionModel={selectionModel} | |||
| /> | |||
| </div> | |||
| </Card> | |||
| </Grid> | |||
| </div> | |||
| <div | |||
| style={{ | |||
| display: "inline-block", | |||
| width: "30%", | |||
| verticalAlign: "top", | |||
| marginLeft: 0, | |||
| }} | |||
| > | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card style={{ marginLeft: 15, marginRight: 20 }}> | |||
| <CardHeader | |||
| className="text-slate-500" | |||
| title="Overall Progress per Project" | |||
| /> | |||
| {percentageArray.length === 0 && ( | |||
| <div | |||
| className="mt-10 mb-10 ml-5 mr-5 text-lg font-medium text-center" | |||
| style={{ color: "#898d8d" }} | |||
| > | |||
| Please select the project you want to check. | |||
| </div> | |||
| )} | |||
| {percentageArray.length > 0 && ( | |||
| <ReactApexChart | |||
| options={options2} | |||
| series={percentageArray} | |||
| type="donut" | |||
| /> | |||
| )} | |||
| </Card> | |||
| </Grid> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card style={{ marginLeft: 15, marginRight: 20, marginTop: 20 }}> | |||
| <div> | |||
| <div | |||
| className="mt-5 text-lg font-medium" | |||
| style={{ color: "#898d8d" }} | |||
| > | |||
| <span style={{ marginLeft: "5%" }}>Project Budget Manhour</span> | |||
| </div> | |||
| <div | |||
| className="mt-2 text-2xl font-extrabold" | |||
| style={{ color: "#6b87cf" }} | |||
| > | |||
| <span style={{ marginLeft: "5%" }}>{projectBudgetManhour}</span> | |||
| </div> | |||
| </div> | |||
| <hr /> | |||
| <div> | |||
| <div | |||
| className="mt-2 text-lg font-medium" | |||
| style={{ color: "#898d8d" }} | |||
| > | |||
| <span style={{ marginLeft: "5%" }}>Actual Manhour Spent</span> | |||
| </div> | |||
| <div | |||
| className="mt-2 text-2xl font-extrabold" | |||
| style={{ color: "#6b87cf" }} | |||
| > | |||
| <span style={{ marginLeft: "5%" }}>{actualManhourSpent}</span> | |||
| </div> | |||
| </div> | |||
| <hr /> | |||
| <div> | |||
| <div | |||
| className="mt-2 text-lg font-medium" | |||
| style={{ color: "#898d8d" }} | |||
| > | |||
| <span style={{ marginLeft: "5%" }}>Remained Manhour</span> | |||
| </div> | |||
| <div | |||
| className="mt-2 text-2xl font-extrabold" | |||
| style={{ color: "#6b87cf" }} | |||
| > | |||
| <span style={{ marginLeft: "5%" }}>{remainedManhour}</span> | |||
| </div> | |||
| </div> | |||
| <div style={{display:"inline-block",width:"30%",verticalAlign:"top",marginLeft:0}}> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card style={{marginLeft:15,marginRight:20}}> | |||
| <CardHeader className="text-slate-500" title="Overall Progress per Project"/> | |||
| {percentageArray.length === 0 &&( | |||
| <div className="mt-10 mb-10 ml-5 mr-5 text-lg font-medium text-center" style={{color:"#898d8d"}}>Please select the project you want to check.</div> | |||
| )} | |||
| {percentageArray.length > 0 &&( | |||
| <ReactApexChart | |||
| options={options2} | |||
| series={percentageArray} | |||
| type="donut" | |||
| /> | |||
| )} | |||
| </Card> | |||
| </Grid> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card style={{marginLeft:15,marginRight:20,marginTop:20}}> | |||
| <div> | |||
| <div className="mt-5 text-lg font-medium" style={{color:"#898d8d"}}><span style={{marginLeft:"5%"}}>Project Budget Manhour</span></div> | |||
| <div className="mt-2 text-2xl font-extrabold" style={{color:"#6b87cf"}}><span style={{marginLeft:"5%"}}>{projectBudgetManhour}</span></div> | |||
| </div> | |||
| <hr/> | |||
| <div> | |||
| <div className="mt-2 text-lg font-medium" style={{color:"#898d8d"}}><span style={{marginLeft:"5%"}}>Actual Manhour Spent</span></div> | |||
| <div className="mt-2 text-2xl font-extrabold" style={{color:"#6b87cf"}}><span style={{marginLeft:"5%"}}>{actualManhourSpent}</span></div> | |||
| </div> | |||
| <hr/> | |||
| <div> | |||
| <div className="mt-2 text-lg font-medium" style={{color:"#898d8d"}}><span style={{marginLeft:"5%"}}>Remained Manhour</span></div> | |||
| <div className="mt-2 text-2xl font-extrabold" style={{color:"#6b87cf"}}><span style={{marginLeft:"5%"}}>{remainedManhour}</span></div> | |||
| </div> | |||
| <hr/> | |||
| <div> | |||
| <div className="mt-2 text-lg font-medium" style={{color:"#898d8d"}}><span style={{marginLeft:"5%"}}>Last Update</span></div> | |||
| <div className="mt-2 mb-5 text-2xl font-extrabold" style={{color:"#6b87cf"}}><span style={{marginLeft:"5%"}}>{lastUpdate}</span></div> | |||
| </div> | |||
| </Card> | |||
| </Grid> | |||
| <hr /> | |||
| <div> | |||
| <div | |||
| className="mt-2 text-lg font-medium" | |||
| style={{ color: "#898d8d" }} | |||
| > | |||
| <span style={{ marginLeft: "5%" }}>Last Update</span> | |||
| </div> | |||
| <div | |||
| className="mt-2 mb-5 text-2xl font-extrabold" | |||
| style={{ color: "#6b87cf" }} | |||
| > | |||
| <span style={{ marginLeft: "5%" }}>{lastUpdate}</span> | |||
| </div> | |||
| </div> | |||
| </Grid> | |||
| </Card> | |||
| </Grid> | |||
| </div> | |||
| </Grid> | |||
| ); | |||
| }; | |||
| @@ -6,9 +6,9 @@ import SearchBox, { Criterion } from "../SearchBox"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import SearchResults, { Column } from "../SearchResults"; | |||
| import { CashFlow } from "@/app/api/cashflow"; | |||
| import CustomDatagrid from '../CustomDatagrid/CustomDatagrid'; | |||
| import { GridColDef, GridRowSelectionModel} from '@mui/x-data-grid'; | |||
| import ProjectCashFlow from '../ProjectCashFlow' | |||
| import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; | |||
| import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid"; | |||
| import ProjectCashFlow from "../ProjectCashFlow"; | |||
| interface Props { | |||
| projects: CashFlow[]; | |||
| @@ -16,70 +16,101 @@ interface Props { | |||
| type SearchQuery = Partial<Omit<CashFlow, "id">>; | |||
| type SearchParamNames = keyof SearchQuery; | |||
| const ProgressByClientSearch: React.FC<Props> = ({ projects}) => { | |||
| const ProgressByClientSearch: React.FC<Props> = ({ projects }) => { | |||
| const { t } = useTranslation("projects"); | |||
| const [selectionModel, setSelectionModel] : any[] = React.useState([]); | |||
| const [selectionModel, setSelectionModel]: any[] = React.useState([]); | |||
| const columns = [ | |||
| { | |||
| id: 'projectCode', | |||
| field: 'projectCode', | |||
| id: "projectCode", | |||
| field: "projectCode", | |||
| headerName: "Project Code", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'projectName', | |||
| field: 'projectName', | |||
| }, | |||
| { | |||
| id: "projectName", | |||
| field: "projectName", | |||
| headerName: "Project Name", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'team', | |||
| field: 'team', | |||
| headerName: "Team", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'teamLeader', | |||
| field: 'teamLeader', | |||
| headerName: "Team Leader", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'startDate', | |||
| field: 'startDate', | |||
| headerName: "Start Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'targetEndDate', | |||
| field: 'targetEndDate', | |||
| headerName: "Target End Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'client', | |||
| field: 'client', | |||
| headerName: "Client", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'subsidiary', | |||
| field: 'subsidiary', | |||
| headerName: "Subsidiary", | |||
| flex: 1, | |||
| }, | |||
| ]; | |||
| const rows = [{id: 1,projectCode:"M1001",projectName:"Consultancy Project A", team:"XXX", teamLeader:"XXX", startDate:"01/07/2022", targetEndDate: "01/04/2024", client:"Client B", subsidiary:"N/A"}, | |||
| {id: 2,projectCode:"M1301",projectName:"Consultancy Project AAAA", team:"XXX", teamLeader:"XXX", startDate:"01/09/2022", targetEndDate: "20/02/2024", client:"Client C", subsidiary:"Subsidiary A"}, | |||
| {id: 3,projectCode:"M1354",projectName:"Consultancy Project BBB", team:"YYY", teamLeader:"YYY", startDate:"01/02/2023", targetEndDate: "31/01/2024", client:"Client D", subsidiary:"Subsidiary C"} | |||
| ] | |||
| const [selectedTeamData, setSelectedTeamData] : any[] = React.useState(rows); | |||
| }, | |||
| { | |||
| id: "team", | |||
| field: "team", | |||
| headerName: "Team", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "teamLeader", | |||
| field: "teamLeader", | |||
| headerName: "Team Leader", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "startDate", | |||
| field: "startDate", | |||
| headerName: "Start Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "targetEndDate", | |||
| field: "targetEndDate", | |||
| headerName: "Target End Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "client", | |||
| field: "client", | |||
| headerName: "Client", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "subsidiary", | |||
| field: "subsidiary", | |||
| headerName: "Subsidiary", | |||
| flex: 1, | |||
| }, | |||
| ]; | |||
| const rows = [ | |||
| { | |||
| id: 1, | |||
| projectCode: "M1001", | |||
| projectName: "Consultancy Project A", | |||
| team: "XXX", | |||
| teamLeader: "XXX", | |||
| startDate: "01/07/2022", | |||
| targetEndDate: "01/04/2024", | |||
| client: "Client B", | |||
| subsidiary: "N/A", | |||
| }, | |||
| { | |||
| id: 2, | |||
| projectCode: "M1301", | |||
| projectName: "Consultancy Project AAAA", | |||
| team: "XXX", | |||
| teamLeader: "XXX", | |||
| startDate: "01/09/2022", | |||
| targetEndDate: "20/02/2024", | |||
| client: "Client C", | |||
| subsidiary: "Subsidiary A", | |||
| }, | |||
| { | |||
| id: 3, | |||
| projectCode: "M1354", | |||
| projectName: "Consultancy Project BBB", | |||
| team: "YYY", | |||
| teamLeader: "YYY", | |||
| startDate: "01/02/2023", | |||
| targetEndDate: "31/01/2024", | |||
| client: "Client D", | |||
| subsidiary: "Subsidiary C", | |||
| }, | |||
| ]; | |||
| const [selectedTeamData, setSelectedTeamData]: any[] = React.useState(rows); | |||
| const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => { | |||
| const selectedRowsData = selectedTeamData.filter((row:any) => | |||
| newSelectionModel.includes(row.id) | |||
| const selectedRowsData = selectedTeamData.filter((row: any) => | |||
| newSelectionModel.includes(row.id), | |||
| ); | |||
| console.log(selectedRowsData) | |||
| } | |||
| console.log(selectedRowsData); | |||
| }; | |||
| // If project searching is done on the server-side, then no need for this. | |||
| const [filteredProjects, setFilteredProjects] = useState(projects); | |||
| @@ -88,7 +119,12 @@ const ProgressByClientSearch: React.FC<Props> = ({ projects}) => { | |||
| () => [ | |||
| { label: "Project Code", paramName: "projectCode", type: "text" }, | |||
| { label: "Project Name", paramName: "projectName", type: "text" }, | |||
| { label: "Start Date From",label2: "Start Date To", paramName: "startDateFrom", type: "dateRange" }, | |||
| { | |||
| label: "Start Date From", | |||
| label2: "Start Date To", | |||
| paramName: "startDateFrom", | |||
| type: "dateRange", | |||
| }, | |||
| ], | |||
| [t], | |||
| ); | |||
| @@ -1,121 +1,123 @@ | |||
| "use client"; | |||
| import * as React from "react"; | |||
| import Grid from "@mui/material/Grid"; | |||
| import { useState,useEffect, useMemo } from 'react' | |||
| import { useState, useEffect, useMemo } from "react"; | |||
| import Paper from "@mui/material/Paper"; | |||
| import { TFunction } from "i18next"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import {Card,CardHeader} from '@mui/material'; | |||
| import { Card, CardHeader } from "@mui/material"; | |||
| import CustomSearchForm from "../CustomSearchForm/CustomSearchForm"; | |||
| import CustomDatagrid from '../CustomDatagrid/CustomDatagrid'; | |||
| import ReactApexChart from 'react-apexcharts'; | |||
| import { ApexOptions } from 'apexcharts'; | |||
| import { GridColDef, GridRowSelectionModel} from '@mui/x-data-grid'; | |||
| import ReportProblemIcon from '@mui/icons-material/ReportProblem'; | |||
| import dynamic from 'next/dynamic'; | |||
| import '../../app/global.css'; | |||
| import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; | |||
| import ReactApexChart from "react-apexcharts"; | |||
| import { ApexOptions } from "apexcharts"; | |||
| import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid"; | |||
| import ReportProblemIcon from "@mui/icons-material/ReportProblem"; | |||
| import dynamic from "next/dynamic"; | |||
| import "../../app/global.css"; | |||
| import { AnyARecord, AnyCnameRecord } from "dns"; | |||
| import SearchBox, { Criterion } from "../SearchBox"; | |||
| import ProgressByClientSearch from "@/components/ProgressByClientSearch"; | |||
| import { Suspense } from "react"; | |||
| import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch"; | |||
| import {Input,Label} from "reactstrap"; | |||
| import { Input, Label } from "reactstrap"; | |||
| const ProjectCashFlow: React.FC = () => { | |||
| const todayDate = new Date; | |||
| const [selectionModel, setSelectionModel] : any[] = React.useState([]); | |||
| const [cashFlowYear, setCashFlowYear] : any[] = React.useState(todayDate.getFullYear()); | |||
| const todayDate = new Date(); | |||
| const [selectionModel, setSelectionModel]: any[] = React.useState([]); | |||
| const [cashFlowYear, setCashFlowYear]: any[] = React.useState( | |||
| todayDate.getFullYear(), | |||
| ); | |||
| const columns = [ | |||
| { | |||
| id: 'projectCode', | |||
| field: 'projectCode', | |||
| id: "projectCode", | |||
| field: "projectCode", | |||
| headerName: "Project Code", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'projectName', | |||
| field: 'projectName', | |||
| }, | |||
| { | |||
| id: "projectName", | |||
| field: "projectName", | |||
| headerName: "Project Name", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'team', | |||
| field: 'team', | |||
| headerName: "Team", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'teamLeader', | |||
| field: 'teamLeader', | |||
| headerName: "Team Leader", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'startDate', | |||
| field: 'startDate', | |||
| headerName: "Start Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'targetEndDate', | |||
| field: 'targetEndDate', | |||
| headerName: "Target End Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'client', | |||
| field: 'client', | |||
| headerName: "Client", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'subsidiary', | |||
| field: 'subsidiary', | |||
| headerName: "Subsidiary", | |||
| flex: 1, | |||
| }, | |||
| }, | |||
| { | |||
| id: "team", | |||
| field: "team", | |||
| headerName: "Team", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "teamLeader", | |||
| field: "teamLeader", | |||
| headerName: "Team Leader", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "startDate", | |||
| field: "startDate", | |||
| headerName: "Start Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "targetEndDate", | |||
| field: "targetEndDate", | |||
| headerName: "Target End Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "client", | |||
| field: "client", | |||
| headerName: "Client", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "subsidiary", | |||
| field: "subsidiary", | |||
| headerName: "Subsidiary", | |||
| flex: 1, | |||
| }, | |||
| ]; | |||
| const ledgerColumns = [ | |||
| { | |||
| id: 'date', | |||
| field: 'date', | |||
| id: "date", | |||
| field: "date", | |||
| headerName: "Date", | |||
| flex: 0.5, | |||
| }, | |||
| { | |||
| id: 'expenditure', | |||
| field: 'expenditure', | |||
| }, | |||
| { | |||
| id: "expenditure", | |||
| field: "expenditure", | |||
| headerName: "Expenditure (HKD)", | |||
| flex: 0.6, | |||
| }, | |||
| { | |||
| id: 'income', | |||
| field: 'income', | |||
| headerName: "Income (HKD)", | |||
| flex: 0.6, | |||
| }, | |||
| { | |||
| id: 'cashFlowBalance', | |||
| field: 'cashFlowBalance', | |||
| headerName: "Cash Flow Balance (HKD)", | |||
| flex: 0.6, | |||
| }, | |||
| { | |||
| id: 'remarks', | |||
| field: 'remarks', | |||
| headerName: "Remarks", | |||
| flex: 1, | |||
| }, | |||
| }, | |||
| { | |||
| id: "income", | |||
| field: "income", | |||
| headerName: "Income (HKD)", | |||
| flex: 0.6, | |||
| }, | |||
| { | |||
| id: "cashFlowBalance", | |||
| field: "cashFlowBalance", | |||
| headerName: "Cash Flow Balance (HKD)", | |||
| flex: 0.6, | |||
| }, | |||
| { | |||
| id: "remarks", | |||
| field: "remarks", | |||
| headerName: "Remarks", | |||
| flex: 1, | |||
| }, | |||
| ]; | |||
| const options: ApexOptions = { | |||
| chart: { | |||
| height: 350, | |||
| type: 'line', | |||
| type: "line", | |||
| }, | |||
| stroke: { | |||
| width: [0, 0, 2, 2] | |||
| width: [0, 0, 2, 2], | |||
| }, | |||
| plotOptions: { | |||
| bar: { | |||
| @@ -124,160 +126,167 @@ const ProjectCashFlow: React.FC = () => { | |||
| }, | |||
| }, | |||
| dataLabels: { | |||
| enabled: false | |||
| enabled: false, | |||
| }, | |||
| xaxis: { | |||
| categories: [ | |||
| 'Q1', | |||
| 'Q2', | |||
| 'Q3', | |||
| 'Q4', | |||
| 'Q5', | |||
| 'Q6', | |||
| 'Q7', | |||
| 'Q8', | |||
| 'Q9', | |||
| 'Q10', | |||
| 'Q11', | |||
| 'Q12', | |||
| "Q1", | |||
| "Q2", | |||
| "Q3", | |||
| "Q4", | |||
| "Q5", | |||
| "Q6", | |||
| "Q7", | |||
| "Q8", | |||
| "Q9", | |||
| "Q10", | |||
| "Q11", | |||
| "Q12", | |||
| ], | |||
| }, | |||
| yaxis: [ | |||
| { | |||
| title: { | |||
| text: 'Monthly Income and Expenditure(HKD)' | |||
| text: "Monthly Income and Expenditure(HKD)", | |||
| }, | |||
| min: 0, | |||
| max: 350000, | |||
| tickAmount: 5 | |||
| tickAmount: 5, | |||
| }, | |||
| { | |||
| show:false, | |||
| seriesName: 'Monthly_Expenditure', | |||
| show: false, | |||
| seriesName: "Monthly_Expenditure", | |||
| title: { | |||
| text: 'Monthly Expenditure (HKD)' | |||
| text: "Monthly Expenditure (HKD)", | |||
| }, | |||
| min: 0, | |||
| max: 350000, | |||
| tickAmount: 5 | |||
| tickAmount: 5, | |||
| }, | |||
| { | |||
| seriesName: 'Cumulative_Income', | |||
| seriesName: "Cumulative_Income", | |||
| opposite: true, | |||
| title: { | |||
| text: 'Cumulative Income and Expenditure(HKD)' | |||
| text: "Cumulative Income and Expenditure(HKD)", | |||
| }, | |||
| min: 0, | |||
| max: 850000, | |||
| tickAmount: 5 | |||
| tickAmount: 5, | |||
| }, | |||
| { | |||
| show:false, | |||
| seriesName: 'Cumulative_Expenditure', | |||
| show: false, | |||
| seriesName: "Cumulative_Expenditure", | |||
| opposite: true, | |||
| title: { | |||
| text: 'Cumulative Expenditure (HKD)' | |||
| text: "Cumulative Expenditure (HKD)", | |||
| }, | |||
| min: 0, | |||
| max: 850000, | |||
| tickAmount: 5 | |||
| } | |||
| ], | |||
| tickAmount: 5, | |||
| }, | |||
| ], | |||
| grid: { | |||
| borderColor: '#f1f1f1', | |||
| borderColor: "#f1f1f1", | |||
| }, | |||
| annotations: { | |||
| }, | |||
| series:[ | |||
| annotations: {}, | |||
| series: [ | |||
| { | |||
| name:"Monthly_Income", | |||
| type:"column", | |||
| name: "Monthly_Income", | |||
| type: "column", | |||
| color: "#ffde91", | |||
| data:[0,110000,0,0,185000,0,0,189000,0,0,300000,0], | |||
| data: [0, 110000, 0, 0, 185000, 0, 0, 189000, 0, 0, 300000, 0], | |||
| }, | |||
| { | |||
| name:"Monthly_Expenditure", | |||
| type:"column", | |||
| name: "Monthly_Expenditure", | |||
| type: "column", | |||
| color: "#82b59a", | |||
| data:[0,160000,120000,120000,55000,55000,55000,55000,55000,70000,55000,55000] | |||
| data: [ | |||
| 0, 160000, 120000, 120000, 55000, 55000, 55000, 55000, 55000, 70000, | |||
| 55000, 55000, | |||
| ], | |||
| }, | |||
| { | |||
| name:"Cumulative_Income", | |||
| type:"line", | |||
| name: "Cumulative_Income", | |||
| type: "line", | |||
| color: "#EE6D7A", | |||
| data:[0,100000,100000,100000,300000,300000,300000,500000,500000,500000,800000,800000] | |||
| data: [ | |||
| 0, 100000, 100000, 100000, 300000, 300000, 300000, 500000, 500000, | |||
| 500000, 800000, 800000, | |||
| ], | |||
| }, | |||
| { | |||
| name:"Cumulative_Expenditure", | |||
| type:"line", | |||
| name: "Cumulative_Expenditure", | |||
| type: "line", | |||
| color: "#7cd3f2", | |||
| data:[0,198000,240000,400000,410000,430000,510000,580000,600000,710000,730000,790000] | |||
| } | |||
| ] | |||
| data: [ | |||
| 0, 198000, 240000, 400000, 410000, 430000, 510000, 580000, 600000, | |||
| 710000, 730000, 790000, | |||
| ], | |||
| }, | |||
| ], | |||
| }; | |||
| const accountsReceivableOptions: ApexOptions = { | |||
| colors: ["#20E647"], | |||
| series: [80], | |||
| chart: { | |||
| height: 350, | |||
| type: 'radialBar', | |||
| colors: ["#20E647"], | |||
| series: [80], | |||
| chart: { | |||
| height: 350, | |||
| type: "radialBar", | |||
| }, | |||
| plotOptions: { | |||
| radialBar: { | |||
| hollow: { | |||
| size: "70%", | |||
| background: "#ffffff", | |||
| }, | |||
| plotOptions: { | |||
| radialBar: { | |||
| hollow: { | |||
| size: '70%', | |||
| background: "#ffffff" | |||
| }, | |||
| track: { | |||
| dropShadow: { | |||
| enabled: true, | |||
| top: 2, | |||
| left: 0, | |||
| blur: 4, | |||
| opacity: 0.15 | |||
| } | |||
| }, | |||
| dataLabels: { | |||
| name:{ | |||
| show:false, | |||
| }, | |||
| value: { | |||
| color: "#3e98c7", | |||
| fontSize: "3em", | |||
| show: true | |||
| } | |||
| }, | |||
| track: { | |||
| dropShadow: { | |||
| enabled: true, | |||
| top: 2, | |||
| left: 0, | |||
| blur: 4, | |||
| opacity: 0.15, | |||
| }, | |||
| }, | |||
| fill: { | |||
| type: "gradient", | |||
| gradient: { | |||
| shade: "dark", | |||
| type: "vertical", | |||
| gradientToColors: ["#87D4F9"], | |||
| stops: [0, 100] | |||
| } | |||
| }, | |||
| stroke: { | |||
| lineCap: "round" | |||
| dataLabels: { | |||
| name: { | |||
| show: false, | |||
| }, | |||
| value: { | |||
| color: "#3e98c7", | |||
| fontSize: "3em", | |||
| show: true, | |||
| }, | |||
| }, | |||
| labels: ['AccountsReceivable'], | |||
| }, | |||
| }, | |||
| fill: { | |||
| type: "gradient", | |||
| gradient: { | |||
| shade: "dark", | |||
| type: "vertical", | |||
| gradientToColors: ["#87D4F9"], | |||
| stops: [0, 100], | |||
| }, | |||
| }, | |||
| stroke: { | |||
| lineCap: "round", | |||
| }, | |||
| labels: ["AccountsReceivable"], | |||
| }; | |||
| const expenditureOptions: ApexOptions = { | |||
| colors: ["#20E647"], | |||
| series: [95], | |||
| chart: { | |||
| chart: { | |||
| height: 350, | |||
| type: 'radialBar', | |||
| type: "radialBar", | |||
| }, | |||
| plotOptions: { | |||
| radialBar: { | |||
| hollow: { | |||
| size: '70%', | |||
| background: "#ffffff" | |||
| size: "70%", | |||
| background: "#ffffff", | |||
| }, | |||
| track: { | |||
| dropShadow: { | |||
| @@ -285,18 +294,18 @@ const ProjectCashFlow: React.FC = () => { | |||
| top: 2, | |||
| left: 0, | |||
| blur: 4, | |||
| opacity: 0.15 | |||
| } | |||
| opacity: 0.15, | |||
| }, | |||
| }, | |||
| dataLabels: { | |||
| name:{ | |||
| show:false, | |||
| name: { | |||
| show: false, | |||
| }, | |||
| value: { | |||
| color: "#3e98c7", | |||
| fontSize: "3em", | |||
| show: true | |||
| } | |||
| show: true, | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| @@ -306,132 +315,322 @@ const ProjectCashFlow: React.FC = () => { | |||
| shade: "dark", | |||
| type: "vertical", | |||
| gradientToColors: ["#87D4F9"], | |||
| stops: [0, 100] | |||
| } | |||
| stops: [0, 100], | |||
| }, | |||
| }, | |||
| stroke: { | |||
| lineCap: "round" | |||
| lineCap: "round", | |||
| }, | |||
| labels: ['AccountsReceivable'], | |||
| }; | |||
| labels: ["AccountsReceivable"], | |||
| }; | |||
| const rows = [{id: 1,projectCode:"M1001",projectName:"Consultancy Project A", team:"XXX", teamLeader:"XXX", startDate:"01/07/2022", targetEndDate: "01/04/2024", client:"Client B", subsidiary:"N/A"}, | |||
| {id: 2,projectCode:"M1301",projectName:"Consultancy Project AAAA", team:"XXX", teamLeader:"XXX", startDate:"01/09/2022", targetEndDate: "20/02/2024", client:"Client C", subsidiary:"Subsidiary A"}, | |||
| {id: 3,projectCode:"M1354",projectName:"Consultancy Project BBB", team:"YYY", teamLeader:"YYY", startDate:"01/02/2023", targetEndDate: "31/01/2024", client:"Client D", subsidiary:"Subsidiary C"} | |||
| ] | |||
| const rows = [ | |||
| { | |||
| id: 1, | |||
| projectCode: "M1001", | |||
| projectName: "Consultancy Project A", | |||
| team: "XXX", | |||
| teamLeader: "XXX", | |||
| startDate: "01/07/2022", | |||
| targetEndDate: "01/04/2024", | |||
| client: "Client B", | |||
| subsidiary: "N/A", | |||
| }, | |||
| { | |||
| id: 2, | |||
| projectCode: "M1301", | |||
| projectName: "Consultancy Project AAAA", | |||
| team: "XXX", | |||
| teamLeader: "XXX", | |||
| startDate: "01/09/2022", | |||
| targetEndDate: "20/02/2024", | |||
| client: "Client C", | |||
| subsidiary: "Subsidiary A", | |||
| }, | |||
| { | |||
| id: 3, | |||
| projectCode: "M1354", | |||
| projectName: "Consultancy Project BBB", | |||
| team: "YYY", | |||
| teamLeader: "YYY", | |||
| startDate: "01/02/2023", | |||
| targetEndDate: "31/01/2024", | |||
| client: "Client D", | |||
| subsidiary: "Subsidiary C", | |||
| }, | |||
| ]; | |||
| const ledgerRows = [{id: 1,date:"Feb 2023",expenditure:"-", income:"100,000.00", cashFlowBalance:"100,000.00", remarks:"Payment Milestone 1 (10%)"}, | |||
| {id: 2,date:"Feb 2023",expenditure:"160,000.00", income:"-", cashFlowBalance:"(60,000.00)", remarks:"Monthly Manpower Expenditure"}, | |||
| {id: 3,date:"Mar 2023",expenditure:"160,000.00", income:"-", cashFlowBalance:"(180,000.00)", remarks:"Monthly Manpower Expenditure"}, | |||
| {id: 4,date:"Apr 2023",expenditure:"120,000.00", income:"-", cashFlowBalance:"(300,000.00)", remarks:"Monthly Manpower Expenditure"}, | |||
| {id: 5,date:"May 2023",expenditure:"-", income:"200,000.00", cashFlowBalance:"(100,000.00)", remarks:"Payment Milestone 2 (20%)"}, | |||
| {id: 6,date:"May 2023",expenditure:"40,000.00", income:"-", cashFlowBalance:"(140,000.00)", remarks:"Monthly Manpower Expenditure"} | |||
| ] | |||
| const ledgerRows = [ | |||
| { | |||
| id: 1, | |||
| date: "Feb 2023", | |||
| expenditure: "-", | |||
| income: "100,000.00", | |||
| cashFlowBalance: "100,000.00", | |||
| remarks: "Payment Milestone 1 (10%)", | |||
| }, | |||
| { | |||
| id: 2, | |||
| date: "Feb 2023", | |||
| expenditure: "160,000.00", | |||
| income: "-", | |||
| cashFlowBalance: "(60,000.00)", | |||
| remarks: "Monthly Manpower Expenditure", | |||
| }, | |||
| { | |||
| id: 3, | |||
| date: "Mar 2023", | |||
| expenditure: "160,000.00", | |||
| income: "-", | |||
| cashFlowBalance: "(180,000.00)", | |||
| remarks: "Monthly Manpower Expenditure", | |||
| }, | |||
| { | |||
| id: 4, | |||
| date: "Apr 2023", | |||
| expenditure: "120,000.00", | |||
| income: "-", | |||
| cashFlowBalance: "(300,000.00)", | |||
| remarks: "Monthly Manpower Expenditure", | |||
| }, | |||
| { | |||
| id: 5, | |||
| date: "May 2023", | |||
| expenditure: "-", | |||
| income: "200,000.00", | |||
| cashFlowBalance: "(100,000.00)", | |||
| remarks: "Payment Milestone 2 (20%)", | |||
| }, | |||
| { | |||
| id: 6, | |||
| date: "May 2023", | |||
| expenditure: "40,000.00", | |||
| income: "-", | |||
| cashFlowBalance: "(140,000.00)", | |||
| remarks: "Monthly Manpower Expenditure", | |||
| }, | |||
| ]; | |||
| const [projectData, setProjectData] : any[] = React.useState(rows); | |||
| const [ledgerData, setLedgerData] : any[] = React.useState(ledgerRows); | |||
| const [projectData, setProjectData]: any[] = React.useState(rows); | |||
| const [ledgerData, setLedgerData]: any[] = React.useState(ledgerRows); | |||
| const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => { | |||
| const selectedRowsData = projectData.filter((row:any) => | |||
| newSelectionModel.includes(row.id) | |||
| const selectedRowsData = projectData.filter((row: any) => | |||
| newSelectionModel.includes(row.id), | |||
| ); | |||
| console.log(selectedRowsData) | |||
| } | |||
| console.log(selectedRowsData); | |||
| }; | |||
| return ( | |||
| <> | |||
| <Suspense fallback={<ProgressCashFlowSearch.Loading />}> | |||
| <ProgressCashFlowSearch/> | |||
| <ProgressCashFlowSearch /> | |||
| </Suspense> | |||
| <CustomDatagrid rows={projectData} columns={columns} columnWidth={200} dataGridHeight={300} checkboxSelection={true} onRowSelectionModelChange={handleSelectionChange} selectionModel={selectionModel}/> | |||
| <Grid item sm> | |||
| <div style={{display:"inline-block",width:"50%"}}> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card> | |||
| <CardHeader className="text-slate-500" title="Project Cash Flow by Month"/> | |||
| <div style={{display:"inline-block",width:"99%"}}> | |||
| <div className="inline-block"> | |||
| <Label className="text-slate-500 font-medium ml-6"> | |||
| Period: | |||
| </Label> | |||
| <Input | |||
| id={'cashFlowYear'} | |||
| value={cashFlowYear} | |||
| readOnly={true} | |||
| bsSize="lg" | |||
| className="rounded-md text-base w-12" | |||
| /> | |||
| </div> | |||
| <div className="inline-block ml-1"> | |||
| <button onClick={() => setCashFlowYear(cashFlowYear - 1)} className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base"> | |||
| < | |||
| </button> | |||
| </div> | |||
| <div className="inline-block ml-1"> | |||
| <button onClick={() => setCashFlowYear(cashFlowYear + 1)} className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base"> | |||
| > | |||
| </button> | |||
| </div> | |||
| <ReactApexChart | |||
| options={options} | |||
| series={options.series} | |||
| type="line" | |||
| height="auto" | |||
| /> | |||
| </div> | |||
| </Card> | |||
| </Grid> | |||
| </div> | |||
| <div style={{display:"inline-block",width:"24%", verticalAlign:"top", marginLeft:10}}> | |||
| <CustomDatagrid | |||
| rows={projectData} | |||
| columns={columns} | |||
| columnWidth={200} | |||
| dataGridHeight={300} | |||
| checkboxSelection={true} | |||
| onRowSelectionModelChange={handleSelectionChange} | |||
| selectionModel={selectionModel} | |||
| /> | |||
| <Grid item sm> | |||
| <div style={{ display: "inline-block", width: "50%" }}> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card> | |||
| <CardHeader className="text-slate-500" title="Accounts Receivable (HKD)"/> | |||
| <Card> | |||
| <CardHeader | |||
| className="text-slate-500" | |||
| title="Project Cash Flow by Month" | |||
| /> | |||
| <div style={{ display: "inline-block", width: "99%" }}> | |||
| <div className="inline-block"> | |||
| <Label className="text-slate-500 font-medium ml-6"> | |||
| Period: | |||
| </Label> | |||
| <Input | |||
| id={"cashFlowYear"} | |||
| value={cashFlowYear} | |||
| readOnly={true} | |||
| bsSize="lg" | |||
| className="rounded-md text-base w-12" | |||
| /> | |||
| </div> | |||
| <div className="inline-block ml-1"> | |||
| <button | |||
| onClick={() => setCashFlowYear(cashFlowYear - 1)} | |||
| className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base" | |||
| > | |||
| < | |||
| </button> | |||
| </div> | |||
| <div className="inline-block ml-1"> | |||
| <button | |||
| onClick={() => setCashFlowYear(cashFlowYear + 1)} | |||
| className="hover:cursor-pointer hover:bg-slate-200 bg-transparent rounded-md w-8 h-8 text-base" | |||
| > | |||
| > | |||
| </button> | |||
| </div> | |||
| <ReactApexChart | |||
| options={accountsReceivableOptions} | |||
| series={accountsReceivableOptions.series} | |||
| type="radialBar" | |||
| /> | |||
| <Card className="ml-2 mr-2 mb-4 rounded-none border-solid border-slate-100"> | |||
| <div className="text-sm font-medium ml-5 mt-2" style={{color:"#898d8d"}}>Total A. Receivable</div> | |||
| <div className="text-lg font-medium ml-5" style={{color:"#6b87cf"}}>1,000,000.00</div><hr/> | |||
| <div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Amount Received</div> | |||
| <div className="text-lg font-medium ml-5" style={{color:"#6b87cf"}}>800,000.00</div><hr/> | |||
| <div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Remaining Balance</div> | |||
| <div className="text-lg font-medium ml-5 mb-2" style={{color:"#6b87cf"}}>200,000.00</div> | |||
| </Card> | |||
| </Card> | |||
| options={options} | |||
| series={options.series} | |||
| type="line" | |||
| height="auto" | |||
| /> | |||
| </div> | |||
| </Card> | |||
| </Grid> | |||
| </div> | |||
| <div style={{display:"inline-block",width:"24%", verticalAlign:"top", marginLeft:10}}> | |||
| </div> | |||
| <div | |||
| style={{ | |||
| display: "inline-block", | |||
| width: "24%", | |||
| verticalAlign: "top", | |||
| marginLeft: 10, | |||
| }} | |||
| > | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card> | |||
| <CardHeader className="text-slate-500" title="Expenditure (HKD)"/> | |||
| <ReactApexChart | |||
| options={expenditureOptions} | |||
| series={expenditureOptions.series} | |||
| type="radialBar" | |||
| /> | |||
| <Card className="ml-2 mr-2 mb-4 rounded-none border-solid border-slate-100"> | |||
| <div className="text-sm font-medium ml-5 mt-2" style={{color:"#898d8d"}}>Budgeted Expenditure</div> | |||
| <div className="text-lg font-medium ml-5" style={{color:"#6b87cf"}}>800,000.00</div><hr/> | |||
| <div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Actual Expenditure</div> | |||
| <div className="text-lg font-medium ml-5" style={{color:"#6b87cf"}}>760,000.00</div><hr/> | |||
| <div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Remaining Balance</div> | |||
| <div className="text-lg font-medium ml-5 mb-2" style={{color:"#6b87cf"}}>40,000.00</div> | |||
| </Card> | |||
| <Card> | |||
| <CardHeader | |||
| className="text-slate-500" | |||
| title="Accounts Receivable (HKD)" | |||
| /> | |||
| <ReactApexChart | |||
| options={accountsReceivableOptions} | |||
| series={accountsReceivableOptions.series} | |||
| type="radialBar" | |||
| /> | |||
| <Card className="ml-2 mr-2 mb-4 rounded-none border-solid border-slate-100"> | |||
| <div | |||
| className="text-sm font-medium ml-5 mt-2" | |||
| style={{ color: "#898d8d" }} | |||
| > | |||
| Total A. Receivable | |||
| </div> | |||
| <div | |||
| className="text-lg font-medium ml-5" | |||
| style={{ color: "#6b87cf" }} | |||
| > | |||
| 1,000,000.00 | |||
| </div> | |||
| <hr /> | |||
| <div | |||
| className="text-sm font-medium ml-5" | |||
| style={{ color: "#898d8d" }} | |||
| > | |||
| Amount Received | |||
| </div> | |||
| <div | |||
| className="text-lg font-medium ml-5" | |||
| style={{ color: "#6b87cf" }} | |||
| > | |||
| 800,000.00 | |||
| </div> | |||
| <hr /> | |||
| <div | |||
| className="text-sm font-medium ml-5" | |||
| style={{ color: "#898d8d" }} | |||
| > | |||
| Remaining Balance | |||
| </div> | |||
| <div | |||
| className="text-lg font-medium ml-5 mb-2" | |||
| style={{ color: "#6b87cf" }} | |||
| > | |||
| 200,000.00 | |||
| </div> | |||
| </Card> | |||
| </Card> | |||
| </Grid> | |||
| </div> | |||
| <div className="mt-5" style={{display:"inline-block",width:"100%", verticalAlign:"top"}}> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card> | |||
| <CardHeader className="text-slate-500" title="Cash Flow Ledger by Month"/> | |||
| <div className="ml-4 mr-4"> | |||
| <CustomDatagrid rows={ledgerData} columns={ledgerColumns} columnWidth={200} dataGridHeight={300}/> | |||
| </div> | |||
| <div | |||
| style={{ | |||
| display: "inline-block", | |||
| width: "24%", | |||
| verticalAlign: "top", | |||
| marginLeft: 10, | |||
| }} | |||
| > | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card> | |||
| <CardHeader | |||
| className="text-slate-500" | |||
| title="Expenditure (HKD)" | |||
| /> | |||
| <ReactApexChart | |||
| options={expenditureOptions} | |||
| series={expenditureOptions.series} | |||
| type="radialBar" | |||
| /> | |||
| <Card className="ml-2 mr-2 mb-4 rounded-none border-solid border-slate-100"> | |||
| <div | |||
| className="text-sm font-medium ml-5 mt-2" | |||
| style={{ color: "#898d8d" }} | |||
| > | |||
| Budgeted Expenditure | |||
| </div> | |||
| <div | |||
| className="text-lg font-medium ml-5" | |||
| style={{ color: "#6b87cf" }} | |||
| > | |||
| 800,000.00 | |||
| </div> | |||
| <hr /> | |||
| <div | |||
| className="text-sm font-medium ml-5" | |||
| style={{ color: "#898d8d" }} | |||
| > | |||
| Actual Expenditure | |||
| </div> | |||
| <div | |||
| className="text-lg font-medium ml-5" | |||
| style={{ color: "#6b87cf" }} | |||
| > | |||
| 760,000.00 | |||
| </div> | |||
| <hr /> | |||
| <div | |||
| className="text-sm font-medium ml-5" | |||
| style={{ color: "#898d8d" }} | |||
| > | |||
| Remaining Balance | |||
| </div> | |||
| <div | |||
| className="text-lg font-medium ml-5 mb-2" | |||
| style={{ color: "#6b87cf" }} | |||
| > | |||
| 40,000.00 | |||
| </div> | |||
| </Card> | |||
| </Grid> | |||
| </div> | |||
| </Grid> | |||
| </Card> | |||
| </Grid> | |||
| </div> | |||
| <div | |||
| className="mt-5" | |||
| style={{ | |||
| display: "inline-block", | |||
| width: "100%", | |||
| verticalAlign: "top", | |||
| }} | |||
| > | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Card> | |||
| <CardHeader | |||
| className="text-slate-500" | |||
| title="Cash Flow Ledger by Month" | |||
| /> | |||
| <div className="ml-4 mr-4"> | |||
| <CustomDatagrid | |||
| rows={ledgerData} | |||
| columns={ledgerColumns} | |||
| columnWidth={200} | |||
| dataGridHeight={300} | |||
| /> | |||
| </div> | |||
| </Card> | |||
| </Grid> | |||
| </div> | |||
| </Grid> | |||
| </> | |||
| ); | |||
| }; | |||
| @@ -1,75 +1,173 @@ | |||
| import * as React from "react"; | |||
| import Grid from "@mui/material/Grid"; | |||
| import { useState,useEffect, useMemo } from 'react' | |||
| import { useState, useEffect, useMemo } from "react"; | |||
| import Paper from "@mui/material/Paper"; | |||
| import { TFunction } from "i18next"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import {Card,CardHeader} from '@mui/material'; | |||
| import { Card, CardHeader } from "@mui/material"; | |||
| import CustomSearchForm from "../CustomSearchForm/CustomSearchForm"; | |||
| import CustomDatagrid from '../CustomDatagrid/CustomDatagrid'; | |||
| import ReactApexChart from 'react-apexcharts'; | |||
| import { ApexOptions } from 'apexcharts'; | |||
| import { GridColDef, GridRowSelectionModel} from '@mui/x-data-grid'; | |||
| import ReportProblemIcon from '@mui/icons-material/ReportProblem'; | |||
| import dynamic from 'next/dynamic'; | |||
| import '../../app/global.css'; | |||
| import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; | |||
| import ReactApexChart from "react-apexcharts"; | |||
| import { ApexOptions } from "apexcharts"; | |||
| import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid"; | |||
| import ReportProblemIcon from "@mui/icons-material/ReportProblem"; | |||
| import dynamic from "next/dynamic"; | |||
| import "../../app/global.css"; | |||
| import { AnyARecord, AnyCnameRecord } from "dns"; | |||
| import SearchBox, { Criterion } from "../SearchBox"; | |||
| import ProgressByClientSearch from "@/components/ProgressByClientSearch"; | |||
| import { Suspense } from "react"; | |||
| interface Props { | |||
| Title: string; | |||
| TotalActiveProjectNumber: string; | |||
| TotalFees: string; | |||
| TotalBudget: string; | |||
| TotalCumulative: string; | |||
| TotalInvoicedAmount: string; | |||
| TotalReceivedAmount: string; | |||
| CashFlowStatus: string; | |||
| CostPerformanceIndex: string; | |||
| ClickedIndex: number; | |||
| Index: number; | |||
| } | |||
| Title: string; | |||
| TotalActiveProjectNumber: string; | |||
| TotalFees: string; | |||
| TotalBudget: string; | |||
| TotalCumulative: string; | |||
| TotalInvoicedAmount: string; | |||
| TotalReceivedAmount: string; | |||
| CashFlowStatus: string; | |||
| CostPerformanceIndex: string; | |||
| ClickedIndex: number; | |||
| Index: number; | |||
| } | |||
| const ProjectFinancialCard: React.FC<Props> = ({Title,TotalActiveProjectNumber,TotalFees,TotalBudget,TotalCumulative,TotalInvoicedAmount,TotalReceivedAmount,CashFlowStatus,CostPerformanceIndex,ClickedIndex,Index}) => { | |||
| const [SearchCriteria, setSearchCriteria] = React.useState({}) | |||
| const { t } = useTranslation("dashboard"); | |||
| const borderColor = CashFlowStatus === "Negative" ? "border-red-300 border-solid" : "border-green-200 border-solid" | |||
| const selectedBackgroundColor = ClickedIndex === Index ? "rgb(235 235 235)" : "rgb(255 255 255)" | |||
| console.log(ClickedIndex) | |||
| console.log(Index) | |||
| return ( | |||
| <Card style={{maxWidth:"25%",minWidth:"280px",boxShadow:"0 0px 10px 0 rgba(0, 0, 0, 0.08), 0 0px 10px 0 rgba(0, 0, 0, 0.08)", backgroundColor:selectedBackgroundColor}} className={`${borderColor}`}> | |||
| <div className="text-xl mt-2 font-medium" style={{width:"100%",textAlign:"center",color:"#898d8d"}}>{Title}</div><hr/> | |||
| <div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Total Active Project</div> | |||
| <div className="text-lg font-medium ml-5" style={{color:"#6b87cf"}}>{TotalActiveProjectNumber}</div><hr/> | |||
| <div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Total Fees</div> | |||
| <div className="text-lg font-medium ml-5" style={{color:"#6b87cf"}}>{TotalFees}</div><hr/> | |||
| <div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Total Budget</div> | |||
| <div className="text-lg font-medium ml-5" style={{color:"#6b87cf"}}>{TotalBudget}</div><hr/> | |||
| <div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Total Cumulative Expenditure</div> | |||
| <div className="text-lg font-medium ml-5" style={{color:"#6b87cf"}}>{TotalCumulative}</div><hr/> | |||
| <div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Total Invoiced Amount</div> | |||
| <div className="text-lg font-medium ml-5" style={{color:"#6b87cf"}}>{TotalInvoicedAmount}</div><hr/> | |||
| <div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Total Received Amount</div> | |||
| <div className="text-lg font-medium ml-5" style={{color:"#6b87cf"}}>{TotalReceivedAmount}</div><hr/> | |||
| <div className="text-sm font-medium ml-5" style={{color:"#898d8d"}}>Cash Flow Status</div> | |||
| {CashFlowStatus === "Negative" && ( | |||
| <><div className="text-lg font-medium ml-5" style={{color:"#f896aa"}}>{CashFlowStatus}</div><hr/></> | |||
| )} | |||
| {CashFlowStatus === "Positive" && ( | |||
| <><div className="text-lg font-medium ml-5" style={{color:"#71d19e"}}>{CashFlowStatus}</div><hr/></> | |||
| )} | |||
| <div className="text-sm mt-2 font-medium ml-5" style={{color:"#898d8d"}}>Cost Performance Index (CPI)</div> | |||
| {Number(CostPerformanceIndex) < 1 && ( | |||
| <><div className="text-lg font-medium ml-5 mb-2" style={{color:"#f896aa"}}>{CostPerformanceIndex}</div></> | |||
| )} | |||
| {Number(CostPerformanceIndex) >= 1 && ( | |||
| <><div className="text-lg font-medium ml-5 mb-2" style={{color:"#71d19e"}}>{CostPerformanceIndex}</div></> | |||
| )} | |||
| </Card> | |||
| ); | |||
| }; | |||
| export default ProjectFinancialCard; | |||
| const ProjectFinancialCard: React.FC<Props> = ({ | |||
| Title, | |||
| TotalActiveProjectNumber, | |||
| TotalFees, | |||
| TotalBudget, | |||
| TotalCumulative, | |||
| TotalInvoicedAmount, | |||
| TotalReceivedAmount, | |||
| CashFlowStatus, | |||
| CostPerformanceIndex, | |||
| ClickedIndex, | |||
| Index, | |||
| }) => { | |||
| const [SearchCriteria, setSearchCriteria] = React.useState({}); | |||
| const { t } = useTranslation("dashboard"); | |||
| const borderColor = | |||
| CashFlowStatus === "Negative" | |||
| ? "border-red-300 border-solid" | |||
| : "border-green-200 border-solid"; | |||
| const selectedBackgroundColor = | |||
| ClickedIndex === Index ? "rgb(235 235 235)" : "rgb(255 255 255)"; | |||
| console.log(ClickedIndex); | |||
| console.log(Index); | |||
| return ( | |||
| <Card | |||
| style={{ | |||
| maxWidth: "25%", | |||
| minWidth: "280px", | |||
| boxShadow: | |||
| "0 0px 10px 0 rgba(0, 0, 0, 0.08), 0 0px 10px 0 rgba(0, 0, 0, 0.08)", | |||
| backgroundColor: selectedBackgroundColor, | |||
| }} | |||
| className={`${borderColor}`} | |||
| > | |||
| <div | |||
| className="text-xl mt-2 font-medium" | |||
| style={{ width: "100%", textAlign: "center", color: "#898d8d" }} | |||
| > | |||
| {Title} | |||
| </div> | |||
| <hr /> | |||
| <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | |||
| Total Active Project | |||
| </div> | |||
| <div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | |||
| {TotalActiveProjectNumber} | |||
| </div> | |||
| <hr /> | |||
| <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | |||
| Total Fees | |||
| </div> | |||
| <div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | |||
| {TotalFees} | |||
| </div> | |||
| <hr /> | |||
| <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | |||
| Total Budget | |||
| </div> | |||
| <div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | |||
| {TotalBudget} | |||
| </div> | |||
| <hr /> | |||
| <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | |||
| Total Cumulative Expenditure | |||
| </div> | |||
| <div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | |||
| {TotalCumulative} | |||
| </div> | |||
| <hr /> | |||
| <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | |||
| Total Invoiced Amount | |||
| </div> | |||
| <div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | |||
| {TotalInvoicedAmount} | |||
| </div> | |||
| <hr /> | |||
| <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | |||
| Total Received Amount | |||
| </div> | |||
| <div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | |||
| {TotalReceivedAmount} | |||
| </div> | |||
| <hr /> | |||
| <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | |||
| Cash Flow Status | |||
| </div> | |||
| {CashFlowStatus === "Negative" && ( | |||
| <> | |||
| <div | |||
| className="text-lg font-medium ml-5" | |||
| style={{ color: "#f896aa" }} | |||
| > | |||
| {CashFlowStatus} | |||
| </div> | |||
| <hr /> | |||
| </> | |||
| )} | |||
| {CashFlowStatus === "Positive" && ( | |||
| <> | |||
| <div | |||
| className="text-lg font-medium ml-5" | |||
| style={{ color: "#71d19e" }} | |||
| > | |||
| {CashFlowStatus} | |||
| </div> | |||
| <hr /> | |||
| </> | |||
| )} | |||
| <div | |||
| className="text-sm mt-2 font-medium ml-5" | |||
| style={{ color: "#898d8d" }} | |||
| > | |||
| Cost Performance Index (CPI) | |||
| </div> | |||
| {Number(CostPerformanceIndex) < 1 && ( | |||
| <> | |||
| <div | |||
| className="text-lg font-medium ml-5 mb-2" | |||
| style={{ color: "#f896aa" }} | |||
| > | |||
| {CostPerformanceIndex} | |||
| </div> | |||
| </> | |||
| )} | |||
| {Number(CostPerformanceIndex) >= 1 && ( | |||
| <> | |||
| <div | |||
| className="text-lg font-medium ml-5 mb-2" | |||
| style={{ color: "#71d19e" }} | |||
| > | |||
| {CostPerformanceIndex} | |||
| </div> | |||
| </> | |||
| )} | |||
| </Card> | |||
| ); | |||
| }; | |||
| export default ProjectFinancialCard; | |||
| @@ -1,19 +1,19 @@ | |||
| "use client"; | |||
| import * as React from "react"; | |||
| import Grid from "@mui/material/Grid"; | |||
| import { useState,useEffect, useMemo } from 'react' | |||
| import { useState, useEffect, useMemo } from "react"; | |||
| import Paper from "@mui/material/Paper"; | |||
| import { TFunction } from "i18next"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import {Card,CardHeader} from '@mui/material'; | |||
| import { Card, CardHeader } from "@mui/material"; | |||
| import CustomSearchForm from "../CustomSearchForm/CustomSearchForm"; | |||
| import CustomDatagrid from '../CustomDatagrid/CustomDatagrid'; | |||
| import ReactApexChart from 'react-apexcharts'; | |||
| import { ApexOptions } from 'apexcharts'; | |||
| import { GridColDef, GridRowSelectionModel} from '@mui/x-data-grid'; | |||
| import ReportProblemIcon from '@mui/icons-material/ReportProblem'; | |||
| import dynamic from 'next/dynamic'; | |||
| import '../../app/global.css'; | |||
| import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; | |||
| import ReactApexChart from "react-apexcharts"; | |||
| import { ApexOptions } from "apexcharts"; | |||
| import { GridColDef, GridRowSelectionModel } from "@mui/x-data-grid"; | |||
| import ReportProblemIcon from "@mui/icons-material/ReportProblem"; | |||
| import dynamic from "next/dynamic"; | |||
| import "../../app/global.css"; | |||
| import { AnyARecord, AnyCnameRecord } from "dns"; | |||
| import SearchBox, { Criterion } from "../SearchBox"; | |||
| import ProgressByClientSearch from "@/components/ProgressByClientSearch"; | |||
| @@ -21,251 +21,453 @@ import { Suspense } from "react"; | |||
| import ProjectFinancialCard from "./ProjectFinancialCard"; | |||
| const ProjectFinancialSummary: React.FC = () => { | |||
| const [SearchCriteria, setSearchCriteria] = React.useState({}) | |||
| const [SearchCriteria, setSearchCriteria] = React.useState({}); | |||
| const { t } = useTranslation("dashboard"); | |||
| const [selectionModel, setSelectionModel] : any[] = React.useState([]); | |||
| const [selectionModel, setSelectionModel]: any[] = React.useState([]); | |||
| const projectFinancialData = [ | |||
| {id:1,title:"All Teams",activeProject:"147",fees:"22,800,000.00",budget:"18,240,000.00",cumulativeExpenditure:"17,950,000.00",invoicedAmount:"18,240,000.00",receivedAmount:"10,900,000.00",cashFlowStatus:"Negative",CPI:"0.69"}, | |||
| {id:2,title:"XXX Team",activeProject:"25",fees:"1,500,000.00",budget:"1,200,000.00",cumulativeExpenditure:"1,250,000.00",invoicedAmount:"900,000.00",receivedAmount:"650,000.00",cashFlowStatus:"Negative",CPI:"0.72"}, | |||
| {id:3,title:"YYY Team",activeProject:"35",fees:"5,000,000.00",budget:"4,000,000.00",cumulativeExpenditure:"3,200,000.00",invoicedAmount:"3,500,000.00",receivedAmount:"3,500,000.00",cashFlowStatus:"Positive",CPI:"1.09"}, | |||
| {id:4,title:"ZZZ Team",activeProject:"50",fees:"3,500,000.00",budget:"2,800,000.00",cumulativeExpenditure:"5,600,000.00",invoicedAmount:"2,500,000.00",receivedAmount:"2,200,000.00",cashFlowStatus:"Negative",CPI:"0.45"}, | |||
| {id:5,title:"AAA Team",activeProject:"15",fees:"4,800,000.00",budget:"3,840,000.00",cumulativeExpenditure:"2,500,000.00",invoicedAmount:"1,500,000.00",receivedAmount:"750,000.00",cashFlowStatus:"Negative",CPI:"0.60"}, | |||
| {id:6,title:"BBB Team",activeProject:"22",fees:"8,000,000.00",budget:"6,400,000.00",cumulativeExpenditure:"5,400,000.00",invoicedAmount:"4,000,000.00",receivedAmount:"3,800,000.00",cashFlowStatus:"Negative",CPI:"0.74"} | |||
| ] | |||
| { | |||
| id: 1, | |||
| title: "All Teams", | |||
| activeProject: "147", | |||
| fees: "22,800,000.00", | |||
| budget: "18,240,000.00", | |||
| cumulativeExpenditure: "17,950,000.00", | |||
| invoicedAmount: "18,240,000.00", | |||
| receivedAmount: "10,900,000.00", | |||
| cashFlowStatus: "Negative", | |||
| CPI: "0.69", | |||
| }, | |||
| { | |||
| id: 2, | |||
| title: "XXX Team", | |||
| activeProject: "25", | |||
| fees: "1,500,000.00", | |||
| budget: "1,200,000.00", | |||
| cumulativeExpenditure: "1,250,000.00", | |||
| invoicedAmount: "900,000.00", | |||
| receivedAmount: "650,000.00", | |||
| cashFlowStatus: "Negative", | |||
| CPI: "0.72", | |||
| }, | |||
| { | |||
| id: 3, | |||
| title: "YYY Team", | |||
| activeProject: "35", | |||
| fees: "5,000,000.00", | |||
| budget: "4,000,000.00", | |||
| cumulativeExpenditure: "3,200,000.00", | |||
| invoicedAmount: "3,500,000.00", | |||
| receivedAmount: "3,500,000.00", | |||
| cashFlowStatus: "Positive", | |||
| CPI: "1.09", | |||
| }, | |||
| { | |||
| id: 4, | |||
| title: "ZZZ Team", | |||
| activeProject: "50", | |||
| fees: "3,500,000.00", | |||
| budget: "2,800,000.00", | |||
| cumulativeExpenditure: "5,600,000.00", | |||
| invoicedAmount: "2,500,000.00", | |||
| receivedAmount: "2,200,000.00", | |||
| cashFlowStatus: "Negative", | |||
| CPI: "0.45", | |||
| }, | |||
| { | |||
| id: 5, | |||
| title: "AAA Team", | |||
| activeProject: "15", | |||
| fees: "4,800,000.00", | |||
| budget: "3,840,000.00", | |||
| cumulativeExpenditure: "2,500,000.00", | |||
| invoicedAmount: "1,500,000.00", | |||
| receivedAmount: "750,000.00", | |||
| cashFlowStatus: "Negative", | |||
| CPI: "0.60", | |||
| }, | |||
| { | |||
| id: 6, | |||
| title: "BBB Team", | |||
| activeProject: "22", | |||
| fees: "8,000,000.00", | |||
| budget: "6,400,000.00", | |||
| cumulativeExpenditure: "5,400,000.00", | |||
| invoicedAmount: "4,000,000.00", | |||
| receivedAmount: "3,800,000.00", | |||
| cashFlowStatus: "Negative", | |||
| CPI: "0.74", | |||
| }, | |||
| ]; | |||
| const rows0 = [{id: 1,projectCode:"M1201",projectName:"Consultancy Project C", team:"XXX", teamLeader:"XXX", startDate:"01/08/2022", targetEndDate: "01/05/2024", client:"Client A", subsidiary:"N/A"}, | |||
| {id: 2,projectCode:"M1321",projectName:"Consultancy Project CCC", team:"XXX", teamLeader:"XXX", startDate:"01/08/2022", targetEndDate: "20/01/2024", client:"Client E", subsidiary:"Subsidiary B"}, | |||
| {id: 3,projectCode:"M1001",projectName:"Consultancy Project A", team:"YYY", teamLeader:"YYY", startDate:"01/07/2022", targetEndDate: "01/04/2024", client:"Client B", subsidiary:"N/A"}, | |||
| {id: 4,projectCode:"M1301",projectName:"Consultancy Project AAAA", team:"YYY", teamLeader:"YYY", startDate:"01/09/2022", targetEndDate: "20/02/2024", client:"Client C", subsidiary:"Subsidiary A"}, | |||
| {id: 5,projectCode:"M1354",projectName:"Consultancy Project BBB", team:"YYY", teamLeader:"YYY", startDate:"01/02/2023", targetEndDate: "31/01/2024", client:"Client D", subsidiary:"Subsidiary C"} | |||
| ] | |||
| const rows0 = [ | |||
| { | |||
| id: 1, | |||
| projectCode: "M1201", | |||
| projectName: "Consultancy Project C", | |||
| team: "XXX", | |||
| teamLeader: "XXX", | |||
| startDate: "01/08/2022", | |||
| targetEndDate: "01/05/2024", | |||
| client: "Client A", | |||
| subsidiary: "N/A", | |||
| }, | |||
| { | |||
| id: 2, | |||
| projectCode: "M1321", | |||
| projectName: "Consultancy Project CCC", | |||
| team: "XXX", | |||
| teamLeader: "XXX", | |||
| startDate: "01/08/2022", | |||
| targetEndDate: "20/01/2024", | |||
| client: "Client E", | |||
| subsidiary: "Subsidiary B", | |||
| }, | |||
| { | |||
| id: 3, | |||
| projectCode: "M1001", | |||
| projectName: "Consultancy Project A", | |||
| team: "YYY", | |||
| teamLeader: "YYY", | |||
| startDate: "01/07/2022", | |||
| targetEndDate: "01/04/2024", | |||
| client: "Client B", | |||
| subsidiary: "N/A", | |||
| }, | |||
| { | |||
| id: 4, | |||
| projectCode: "M1301", | |||
| projectName: "Consultancy Project AAAA", | |||
| team: "YYY", | |||
| teamLeader: "YYY", | |||
| startDate: "01/09/2022", | |||
| targetEndDate: "20/02/2024", | |||
| client: "Client C", | |||
| subsidiary: "Subsidiary A", | |||
| }, | |||
| { | |||
| id: 5, | |||
| projectCode: "M1354", | |||
| projectName: "Consultancy Project BBB", | |||
| team: "YYY", | |||
| teamLeader: "YYY", | |||
| startDate: "01/02/2023", | |||
| targetEndDate: "31/01/2024", | |||
| client: "Client D", | |||
| subsidiary: "Subsidiary C", | |||
| }, | |||
| ]; | |||
| const rows1 = [{id: 1,projectCode:"M1201",projectName:"Consultancy Project C", team:"XXX", teamLeader:"XXX", startDate:"01/08/2022", targetEndDate: "01/05/2024", client:"Client A", subsidiary:"N/A"}, | |||
| {id: 2,projectCode:"M1321",projectName:"Consultancy Project CCC", team:"XXX", teamLeader:"XXX", startDate:"01/08/2022", targetEndDate: "20/01/2024", client:"Client E", subsidiary:"Subsidiary B"}, | |||
| ] | |||
| const rows1 = [ | |||
| { | |||
| id: 1, | |||
| projectCode: "M1201", | |||
| projectName: "Consultancy Project C", | |||
| team: "XXX", | |||
| teamLeader: "XXX", | |||
| startDate: "01/08/2022", | |||
| targetEndDate: "01/05/2024", | |||
| client: "Client A", | |||
| subsidiary: "N/A", | |||
| }, | |||
| { | |||
| id: 2, | |||
| projectCode: "M1321", | |||
| projectName: "Consultancy Project CCC", | |||
| team: "XXX", | |||
| teamLeader: "XXX", | |||
| startDate: "01/08/2022", | |||
| targetEndDate: "20/01/2024", | |||
| client: "Client E", | |||
| subsidiary: "Subsidiary B", | |||
| }, | |||
| ]; | |||
| const rows2 = [{id: 3,projectCode:"M1001",projectName:"Consultancy Project A", team:"YYY", teamLeader:"YYY", startDate:"01/07/2022", targetEndDate: "01/04/2024", client:"Client B", subsidiary:"N/A"}, | |||
| {id: 4,projectCode:"M1301",projectName:"Consultancy Project AAAA", team:"YYY", teamLeader:"YYY", startDate:"01/09/2022", targetEndDate: "20/02/2024", client:"Client C", subsidiary:"Subsidiary A"}, | |||
| {id: 5,projectCode:"M1354",projectName:"Consultancy Project BBB", team:"YYY", teamLeader:"YYY", startDate:"01/02/2023", targetEndDate: "31/01/2024", client:"Client D", subsidiary:"Subsidiary C"} | |||
| ] | |||
| const rows2 = [ | |||
| { | |||
| id: 3, | |||
| projectCode: "M1001", | |||
| projectName: "Consultancy Project A", | |||
| team: "YYY", | |||
| teamLeader: "YYY", | |||
| startDate: "01/07/2022", | |||
| targetEndDate: "01/04/2024", | |||
| client: "Client B", | |||
| subsidiary: "N/A", | |||
| }, | |||
| { | |||
| id: 4, | |||
| projectCode: "M1301", | |||
| projectName: "Consultancy Project AAAA", | |||
| team: "YYY", | |||
| teamLeader: "YYY", | |||
| startDate: "01/09/2022", | |||
| targetEndDate: "20/02/2024", | |||
| client: "Client C", | |||
| subsidiary: "Subsidiary A", | |||
| }, | |||
| { | |||
| id: 5, | |||
| projectCode: "M1354", | |||
| projectName: "Consultancy Project BBB", | |||
| team: "YYY", | |||
| teamLeader: "YYY", | |||
| startDate: "01/02/2023", | |||
| targetEndDate: "31/01/2024", | |||
| client: "Client D", | |||
| subsidiary: "Subsidiary C", | |||
| }, | |||
| ]; | |||
| const projectFinancialRows = [{id: 1,cashFlowStatus:"Positive",cpi:"1.25", totalFees:"500,000.00", totalBudget:"400,000.00", totalCumulativeExpenditure:"280,000.00", totalInvoicedAmount: "350,000.00", totalUnInvoicedAmount:"150,000.00", totalReceivedAmount:"350,000.00", totalUnReceivedAmount:"0.00"} | |||
| ] | |||
| const projectFinancialRows = [ | |||
| { | |||
| id: 1, | |||
| cashFlowStatus: "Positive", | |||
| cpi: "1.25", | |||
| totalFees: "500,000.00", | |||
| totalBudget: "400,000.00", | |||
| totalCumulativeExpenditure: "280,000.00", | |||
| totalInvoicedAmount: "350,000.00", | |||
| totalUnInvoicedAmount: "150,000.00", | |||
| totalReceivedAmount: "350,000.00", | |||
| totalUnReceivedAmount: "0.00", | |||
| }, | |||
| ]; | |||
| const [isCardClickedIndex, setIsCardClickedIndex] = React.useState(0); | |||
| const [selectedTeamData, setSelectedTeamData] : any[] = React.useState(rows0); | |||
| const [selectedTeamData, setSelectedTeamData]: any[] = React.useState(rows0); | |||
| const handleCardClick = (r:any) => { | |||
| setIsCardClickedIndex(r) | |||
| if (r === 0) { | |||
| setSelectedTeamData(rows0) | |||
| } else if (r === 1) { | |||
| setSelectedTeamData(rows1) | |||
| } else if (r === 2) { | |||
| setSelectedTeamData(rows2) | |||
| } | |||
| const handleCardClick = (r: any) => { | |||
| setIsCardClickedIndex(r); | |||
| if (r === 0) { | |||
| setSelectedTeamData(rows0); | |||
| } else if (r === 1) { | |||
| setSelectedTeamData(rows1); | |||
| } else if (r === 2) { | |||
| setSelectedTeamData(rows2); | |||
| } | |||
| }; | |||
| const columns = [ | |||
| { | |||
| id: 'projectCode', | |||
| field: 'projectCode', | |||
| id: "projectCode", | |||
| field: "projectCode", | |||
| headerName: "Project Code", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'projectName', | |||
| field: 'projectName', | |||
| }, | |||
| { | |||
| id: "projectName", | |||
| field: "projectName", | |||
| headerName: "Project Name", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'team', | |||
| field: 'team', | |||
| headerName: "Team", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'teamLeader', | |||
| field: 'teamLeader', | |||
| headerName: "Team Leader", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'startDate', | |||
| field: 'startDate', | |||
| headerName: "Start Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'targetEndDate', | |||
| field: 'targetEndDate', | |||
| headerName: "Target End Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'client', | |||
| field: 'client', | |||
| headerName: "Client", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: 'subsidiary', | |||
| field: 'subsidiary', | |||
| headerName: "Subsidiary", | |||
| flex: 1, | |||
| }, | |||
| ]; | |||
| }, | |||
| { | |||
| id: "team", | |||
| field: "team", | |||
| headerName: "Team", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "teamLeader", | |||
| field: "teamLeader", | |||
| headerName: "Team Leader", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "startDate", | |||
| field: "startDate", | |||
| headerName: "Start Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "targetEndDate", | |||
| field: "targetEndDate", | |||
| headerName: "Target End Date", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "client", | |||
| field: "client", | |||
| headerName: "Client", | |||
| flex: 1, | |||
| }, | |||
| { | |||
| id: "subsidiary", | |||
| field: "subsidiary", | |||
| headerName: "Subsidiary", | |||
| flex: 1, | |||
| }, | |||
| ]; | |||
| const columns2 = [ | |||
| { | |||
| id: 'cashFlowStatus', | |||
| field: 'cashFlowStatus', | |||
| headerName: "Cash Flow Status", | |||
| flex: 1, | |||
| renderCell: (params:any) => { | |||
| if (params.row.cashFlowStatus === "Positive") { | |||
| return ( | |||
| <span className="text-lime-500">{params.row.cashFlowStatus}</span> | |||
| ) | |||
| } else if (params.row.cashFlowStatus === "Negative") { | |||
| return ( | |||
| <span className="text-red-500">{params.row.cashFlowStatus}</span> | |||
| ) | |||
| } | |||
| }, | |||
| }, | |||
| { | |||
| id: 'cpi', | |||
| field: 'cpi', | |||
| headerName: "CPI", | |||
| flex: 0.7, | |||
| renderCell: (params:any) => { | |||
| if (params.row.cpi >= 1) { | |||
| return ( | |||
| <span className="text-lime-500">{params.row.cpi}</span> | |||
| ) | |||
| } else if (params.row.cpi < 1) { | |||
| return ( | |||
| <span className="text-red-500">{params.row.cpi}</span> | |||
| ) | |||
| } | |||
| }, | |||
| }, | |||
| { | |||
| id: 'totalFees', | |||
| field: 'totalFees', | |||
| headerName: "Total Fees (HKD)", | |||
| flex: 1, | |||
| renderCell: (params:any) => { | |||
| return ( | |||
| <span>${params.row.totalFees}</span> | |||
| ) | |||
| }, | |||
| }, | |||
| { | |||
| id: 'totalBudget', | |||
| field: 'totalBudget', | |||
| headerName: "Total Budget (HKD)", | |||
| flex: 1, | |||
| renderCell: (params:any) => { | |||
| return ( | |||
| <span>${params.row.totalBudget}</span> | |||
| ) | |||
| }, | |||
| }, | |||
| { | |||
| id: 'totalCumulativeExpenditure', | |||
| field: 'totalCumulativeExpenditure', | |||
| headerName: "Total Cumulative Expenditure (HKD)", | |||
| flex: 1, | |||
| renderCell: (params:any) => { | |||
| return ( | |||
| <span>${params.row.totalCumulativeExpenditure}</span> | |||
| ) | |||
| }, | |||
| }, | |||
| { | |||
| id: 'totalInvoicedAmount', | |||
| field: 'totalInvoicedAmount', | |||
| headerName: "Total Invoiced Amount (HKD)", | |||
| flex: 1, | |||
| renderCell: (params:any) => { | |||
| return ( | |||
| <span>${params.row.totalInvoicedAmount}</span> | |||
| ) | |||
| }, | |||
| }, | |||
| { | |||
| id: 'totalUnInvoicedAmount', | |||
| field: 'totalUnInvoicedAmount', | |||
| headerName: "Total Un-invoiced Amount (HKD)", | |||
| flex: 1, | |||
| renderCell: (params:any) => { | |||
| return ( | |||
| <span>${params.row.totalUnInvoicedAmount}</span> | |||
| ) | |||
| }, | |||
| }, | |||
| { | |||
| id: 'totalReceivedAmount', | |||
| field: 'totalReceivedAmount', | |||
| headerName: "Total Received Amount (HKD)", | |||
| flex: 1, | |||
| renderCell: (params:any) => { | |||
| return ( | |||
| <span>${params.row.totalReceivedAmount}</span> | |||
| ) | |||
| }, | |||
| }, | |||
| { | |||
| id: 'totalUnReceivedAmount', | |||
| field: 'totalUnReceivedAmount', | |||
| headerName: "Total Un-received Amount (HKD)", | |||
| flex: 1, | |||
| renderCell: (params:any) => { | |||
| return ( | |||
| <span>${params.row.totalUnReceivedAmount}</span> | |||
| ) | |||
| }, | |||
| }, | |||
| ]; | |||
| const columns2 = [ | |||
| { | |||
| id: "cashFlowStatus", | |||
| field: "cashFlowStatus", | |||
| headerName: "Cash Flow Status", | |||
| flex: 1, | |||
| renderCell: (params: any) => { | |||
| if (params.row.cashFlowStatus === "Positive") { | |||
| return ( | |||
| <span className="text-lime-500">{params.row.cashFlowStatus}</span> | |||
| ); | |||
| } else if (params.row.cashFlowStatus === "Negative") { | |||
| return ( | |||
| <span className="text-red-500">{params.row.cashFlowStatus}</span> | |||
| ); | |||
| } | |||
| }, | |||
| }, | |||
| { | |||
| id: "cpi", | |||
| field: "cpi", | |||
| headerName: "CPI", | |||
| flex: 0.7, | |||
| renderCell: (params: any) => { | |||
| if (params.row.cpi >= 1) { | |||
| return <span className="text-lime-500">{params.row.cpi}</span>; | |||
| } else if (params.row.cpi < 1) { | |||
| return <span className="text-red-500">{params.row.cpi}</span>; | |||
| } | |||
| }, | |||
| }, | |||
| { | |||
| id: "totalFees", | |||
| field: "totalFees", | |||
| headerName: "Total Fees (HKD)", | |||
| flex: 1, | |||
| renderCell: (params: any) => { | |||
| return <span>${params.row.totalFees}</span>; | |||
| }, | |||
| }, | |||
| { | |||
| id: "totalBudget", | |||
| field: "totalBudget", | |||
| headerName: "Total Budget (HKD)", | |||
| flex: 1, | |||
| renderCell: (params: any) => { | |||
| return <span>${params.row.totalBudget}</span>; | |||
| }, | |||
| }, | |||
| { | |||
| id: "totalCumulativeExpenditure", | |||
| field: "totalCumulativeExpenditure", | |||
| headerName: "Total Cumulative Expenditure (HKD)", | |||
| flex: 1, | |||
| renderCell: (params: any) => { | |||
| return <span>${params.row.totalCumulativeExpenditure}</span>; | |||
| }, | |||
| }, | |||
| { | |||
| id: "totalInvoicedAmount", | |||
| field: "totalInvoicedAmount", | |||
| headerName: "Total Invoiced Amount (HKD)", | |||
| flex: 1, | |||
| renderCell: (params: any) => { | |||
| return <span>${params.row.totalInvoicedAmount}</span>; | |||
| }, | |||
| }, | |||
| { | |||
| id: "totalUnInvoicedAmount", | |||
| field: "totalUnInvoicedAmount", | |||
| headerName: "Total Un-invoiced Amount (HKD)", | |||
| flex: 1, | |||
| renderCell: (params: any) => { | |||
| return <span>${params.row.totalUnInvoicedAmount}</span>; | |||
| }, | |||
| }, | |||
| { | |||
| id: "totalReceivedAmount", | |||
| field: "totalReceivedAmount", | |||
| headerName: "Total Received Amount (HKD)", | |||
| flex: 1, | |||
| renderCell: (params: any) => { | |||
| return <span>${params.row.totalReceivedAmount}</span>; | |||
| }, | |||
| }, | |||
| { | |||
| id: "totalUnReceivedAmount", | |||
| field: "totalUnReceivedAmount", | |||
| headerName: "Total Un-received Amount (HKD)", | |||
| flex: 1, | |||
| renderCell: (params: any) => { | |||
| return <span>${params.row.totalUnReceivedAmount}</span>; | |||
| }, | |||
| }, | |||
| ]; | |||
| const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => { | |||
| const selectedRowsData = selectedTeamData.filter((row:any) => | |||
| newSelectionModel.includes(row.id) | |||
| const selectedRowsData = selectedTeamData.filter((row: any) => | |||
| newSelectionModel.includes(row.id), | |||
| ); | |||
| console.log(selectedRowsData) | |||
| } | |||
| console.log(selectedRowsData); | |||
| }; | |||
| return ( | |||
| <Grid item sm> | |||
| <Card> | |||
| <CardHeader className="text-slate-500" title="Active Project Financial Status"/> | |||
| <div className="ml-10 mr-10" style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'start'}}> | |||
| {projectFinancialData.map((record, index) => ( | |||
| <div className="hover:cursor-pointer ml-4 mt-5 mb-4 inline-block" key={index} onClick={(r) => handleCardClick(index)}> | |||
| <ProjectFinancialCard Title={record.title} TotalActiveProjectNumber={record.activeProject} TotalFees={record.fees} TotalBudget={record.budget} TotalCumulative={record.cumulativeExpenditure} TotalInvoicedAmount={record.invoicedAmount} TotalReceivedAmount={record.receivedAmount} CashFlowStatus={record.cashFlowStatus} CostPerformanceIndex={record.CPI} ClickedIndex={isCardClickedIndex} Index={index}/> | |||
| </div> | |||
| ))} | |||
| </div> | |||
| </Card> | |||
| <Card className="mt-5"> | |||
| <CardHeader className="text-slate-500" title="Selected Team's Project"/> | |||
| <div style={{display:"inline-block",width:"99%",marginLeft:10}}> | |||
| <CustomDatagrid rows={selectedTeamData} columns={columns} columnWidth={200} dataGridHeight={300} checkboxSelection={true} onRowSelectionModelChange={handleSelectionChange} selectionModel={selectionModel}/> | |||
| </div> | |||
| </Card> | |||
| <Card className="mt-5"> | |||
| <CardHeader className="text-slate-500" title="Individual Project Financial Status"/> | |||
| <div style={{display:"inline-block",width:"99%",marginLeft:10}}> | |||
| <CustomDatagrid rows={projectFinancialRows} columns={columns2} columnWidth={200} dataGridHeight={300}/> | |||
| </div> | |||
| </Card> | |||
| </Grid> | |||
| <Grid item sm> | |||
| <Card> | |||
| <CardHeader | |||
| className="text-slate-500" | |||
| title="Active Project Financial Status" | |||
| /> | |||
| <div | |||
| className="ml-10 mr-10" | |||
| style={{ display: "flex", flexWrap: "wrap", justifyContent: "start" }} | |||
| > | |||
| {projectFinancialData.map((record, index) => ( | |||
| <div | |||
| className="hover:cursor-pointer ml-4 mt-5 mb-4 inline-block" | |||
| key={index} | |||
| onClick={(r) => handleCardClick(index)} | |||
| > | |||
| <ProjectFinancialCard | |||
| Title={record.title} | |||
| TotalActiveProjectNumber={record.activeProject} | |||
| TotalFees={record.fees} | |||
| TotalBudget={record.budget} | |||
| TotalCumulative={record.cumulativeExpenditure} | |||
| TotalInvoicedAmount={record.invoicedAmount} | |||
| TotalReceivedAmount={record.receivedAmount} | |||
| CashFlowStatus={record.cashFlowStatus} | |||
| CostPerformanceIndex={record.CPI} | |||
| ClickedIndex={isCardClickedIndex} | |||
| Index={index} | |||
| /> | |||
| </div> | |||
| ))} | |||
| </div> | |||
| </Card> | |||
| <Card className="mt-5"> | |||
| <CardHeader | |||
| className="text-slate-500" | |||
| title="Selected Team's Project" | |||
| /> | |||
| <div style={{ display: "inline-block", width: "99%", marginLeft: 10 }}> | |||
| <CustomDatagrid | |||
| rows={selectedTeamData} | |||
| columns={columns} | |||
| columnWidth={200} | |||
| dataGridHeight={300} | |||
| checkboxSelection={true} | |||
| onRowSelectionModelChange={handleSelectionChange} | |||
| selectionModel={selectionModel} | |||
| /> | |||
| </div> | |||
| </Card> | |||
| <Card className="mt-5"> | |||
| <CardHeader | |||
| className="text-slate-500" | |||
| title="Individual Project Financial Status" | |||
| /> | |||
| <div style={{ display: "inline-block", width: "99%", marginLeft: 10 }}> | |||
| <CustomDatagrid | |||
| rows={projectFinancialRows} | |||
| columns={columns2} | |||
| columnWidth={200} | |||
| dataGridHeight={300} | |||
| /> | |||
| </div> | |||
| </Card> | |||
| </Grid> | |||
| ); | |||
| }; | |||
| @@ -1,23 +1,22 @@ | |||
| import Swal from "sweetalert2"; | |||
| export const msg = (text) => { | |||
| Swal.mixin({ | |||
| toast: true, | |||
| position: "bottom-end", | |||
| showConfirmButton: false, | |||
| timer: 3000, | |||
| timerProgressBar: true, | |||
| didOpen: (toast) => { | |||
| toast.onmouseenter = Swal.stopTimer; | |||
| toast.onmouseleave = Swal.resumeTimer; | |||
| } | |||
| }).fire({ | |||
| icon: "Success", | |||
| title: text | |||
| }); | |||
| } | |||
| Swal.mixin({ | |||
| toast: true, | |||
| position: "bottom-end", | |||
| showConfirmButton: false, | |||
| timer: 3000, | |||
| timerProgressBar: true, | |||
| didOpen: (toast) => { | |||
| toast.onmouseenter = Swal.stopTimer; | |||
| toast.onmouseleave = Swal.resumeTimer; | |||
| }, | |||
| }).fire({ | |||
| icon: "Success", | |||
| title: text, | |||
| }); | |||
| }; | |||
| export const popup = (text) => { | |||
| Swal.fire(text); | |||
| } | |||
| Swal.fire(text); | |||
| }; | |||
| @@ -1,44 +1,78 @@ | |||
| "use client"; | |||
| import * as React from "react"; | |||
| import Grid from "@mui/material/Grid"; | |||
| import { useEffect, useState } from 'react' | |||
| import { TFunction } from "i18next"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import {Card,CardContent,CardHeader} from '@mui/material'; | |||
| import CustomCardGrid from '../CustomCardGrid/CustomCardGrid'; | |||
| import '../../app/global.css'; | |||
| import { useEffect } from "react"; | |||
| import { Card, CardContent, CardHeader } from "@mui/material"; | |||
| import CustomCardGrid from "../CustomCardGrid/CustomCardGrid"; | |||
| import "../../app/global.css"; | |||
| import { PROJECT_CARD_STYLE } from "@/theme/colorConst"; | |||
| interface ProjectGridProps { | |||
| tab: number; | |||
| } | |||
| const cards = [ | |||
| { | |||
| code: "M1001 (C)", | |||
| name: "Consultancy Project A", | |||
| hr_spent: 12.75, | |||
| hr_spent_normal: 0.0, | |||
| hr_alloc: 150.0, | |||
| hr_alloc_normal: 30.0, | |||
| }, | |||
| { | |||
| code: "M1301 (C)", | |||
| name: "Consultancy Project AAA", | |||
| hr_spent: 4.25, | |||
| hr_spent_normal: 0.25, | |||
| hr_alloc: 30.0, | |||
| hr_alloc_normal: 0.0, | |||
| }, | |||
| { | |||
| code: "M1354 (C)", | |||
| name: "Consultancy Project BBB", | |||
| hr_spent: 57.0, | |||
| hr_spent_normal: 6.5, | |||
| hr_alloc: 100.0, | |||
| hr_alloc_normal: 20.0, | |||
| }, | |||
| { | |||
| code: "M1973 (C)", | |||
| name: "Construction Project CCC", | |||
| hr_spent: 12.75, | |||
| hr_spent_normal: 0.0, | |||
| hr_alloc: 150.0, | |||
| hr_alloc_normal: 30.0, | |||
| }, | |||
| { | |||
| code: "M2014 (T)", | |||
| name: "Consultancy Project DDD", | |||
| hr_spent: 1.0, | |||
| hr_spent_normal: 0.0, | |||
| hr_alloc: 10.0, | |||
| hr_alloc_normal: 0.0, | |||
| }, | |||
| ]; | |||
| const ProjectGrid: React.FC<ProjectGridProps> = (props) => { | |||
| const [items, setItems] = React.useState<Object[]>([]) | |||
| const [items, setItems] = React.useState<typeof cards>([]); | |||
| useEffect(() => { | |||
| if (props.tab == 0) { | |||
| setItems(cards) | |||
| } | |||
| else { | |||
| const filteredItems = cards;//cards.filter(item => (item.track == props.tab)); | |||
| setItems(cards); | |||
| } else { | |||
| const filteredItems = cards; //cards.filter(item => (item.track == props.tab)); | |||
| setItems(filteredItems); | |||
| } | |||
| }, [props.tab]); | |||
| const cards = [ | |||
| {code: 'M1001 (C)', name: 'Consultancy Project A', hr_spent: 12.75, hr_spent_normal: 0.00, hr_alloc: 150.00, hr_alloc_normal: 30.00}, | |||
| {code: 'M1301 (C)', name: 'Consultancy Project AAA', hr_spent: 4.25, hr_spent_normal: 0.25, hr_alloc: 30.00, hr_alloc_normal: 0.00}, | |||
| {code: 'M1354 (C)', name: 'Consultancy Project BBB', hr_spent: 57.00, hr_spent_normal: 6.50, hr_alloc: 100.00, hr_alloc_normal: 20.00}, | |||
| {code: 'M1973 (C)', name: 'Construction Project CCC', hr_spent: 12.75, hr_spent_normal: 0.00, hr_alloc: 150.00, hr_alloc_normal: 30.00}, | |||
| {code: 'M2014 (T)', name: 'Consultancy Project DDD', hr_spent: 1.00, hr_spent_normal: 0.00, hr_alloc: 10.00, hr_alloc_normal: 0.00}, | |||
| ]; | |||
| const cardLayout = (item: Record<string, string>) => { | |||
| return ( | |||
| <Card style={PROJECT_CARD_STYLE}> | |||
| <CardHeader style={{backgroundColor:'pink'}} title={item.code + '\u000A' + item.name}/> | |||
| <CardHeader | |||
| style={{ backgroundColor: "pink" }} | |||
| title={item.code + "\u000A" + item.name} | |||
| /> | |||
| <CardContent> | |||
| <p>Hours Spent: {item.hr_spent}</p> | |||
| <p>Normal (Others): {item.hr_spent_normal}</p> | |||
| @@ -47,15 +81,19 @@ const ProjectGrid: React.FC<ProjectGridProps> = (props) => { | |||
| </CardContent> | |||
| </Card> | |||
| ); | |||
| } | |||
| }; | |||
| // Apply the preset style to the cards in child, if not specified // | |||
| return ( | |||
| <Grid container md={12}> | |||
| {/* <CustomSearchForm applySearch={applySearch} fields={InputFields}/> */} | |||
| {/* item count = {items?.length??"idk"} , track/tab = {props.tab} */} | |||
| <CustomCardGrid Title={props.tab.toString()} items={items} cardStyle={cardLayout}/> | |||
| {/* <CustomCardGrid Title={props.tab.toString()} rows={rows} columns={columns} columnWidth={200} items={items}/> */} | |||
| </Grid> | |||
| {/* <CustomSearchForm applySearch={applySearch} fields={InputFields}/> */} | |||
| {/* item count = {items?.length??"idk"} , track/tab = {props.tab} */} | |||
| <CustomCardGrid | |||
| Title={props.tab.toString()} | |||
| items={items} | |||
| cardStyle={cardLayout} | |||
| /> | |||
| {/* <CustomCardGrid Title={props.tab.toString()} rows={rows} columns={columns} columnWidth={200} items={items}/> */} | |||
| </Grid> | |||
| ); | |||
| }; | |||
| @@ -8,9 +8,9 @@ import PageTitle from "../PageTitle/PageTitle"; | |||
| import { Suspense } from "react"; | |||
| import Button from "@mui/material/Button"; | |||
| import Stack from "@mui/material/Stack"; | |||
| import { Add } from '@mui/icons-material'; | |||
| import { Add } from "@mui/icons-material"; | |||
| import Link from "next/link"; | |||
| import { t } from 'i18next'; | |||
| import { t } from "i18next"; | |||
| import { Modal } from "@mui/material"; | |||
| import CustomModal from "../CustomModal/CustomModal"; | |||
| import EnterTimesheetModal from "../EnterTimesheet/EnterTimesheetModal"; | |||
| @@ -18,7 +18,6 @@ import EnterTimesheetModal from "../EnterTimesheet/EnterTimesheetModal"; | |||
| const UserWorkspacePage: React.FC = () => { | |||
| const [isModalVisible, setModalVisible] = useState(false); | |||
| const { t } = useTranslation("home"); | |||
| const handleButtonClick = () => { | |||
| setModalVisible(true); | |||
| @@ -29,38 +28,36 @@ const UserWorkspacePage: React.FC = () => { | |||
| }; | |||
| return ( | |||
| <Grid container height="100vh" > | |||
| <Grid container height="100vh"> | |||
| <Grid item sm> | |||
| <PageTitle BigTitle={"User Workspace"}/> | |||
| <div><Stack | |||
| direction="row" | |||
| justifyContent="right" | |||
| flexWrap="wrap" | |||
| > | |||
| <Button | |||
| variant="contained" | |||
| startIcon={<Add />} | |||
| onClick={handleButtonClick} | |||
| sx={{marginRight:"2rem"}} | |||
| > | |||
| Enter Timesheet | |||
| </Button> | |||
| <Button | |||
| variant="contained" | |||
| startIcon={<Add />} | |||
| sx={{marginRight:"2rem"}} | |||
| LinkComponent={Link} | |||
| href="/projects/create" | |||
| > | |||
| Record Leave | |||
| </Button> | |||
| </Stack> | |||
| <Suspense> {/*fallback={<ProjectSearch.Loading />}>*/} | |||
| </Suspense> | |||
| </div> | |||
| <EnterTimesheetModal isOpen={isModalVisible} onClose={handleCloseModal}/> | |||
| <AssignedProjectGrid Title="Assigned Project"/> | |||
| <PageTitle BigTitle={"User Workspace"} /> | |||
| <div> | |||
| <Stack direction="row" justifyContent="right" flexWrap="wrap"> | |||
| <Button | |||
| variant="contained" | |||
| startIcon={<Add />} | |||
| onClick={handleButtonClick} | |||
| sx={{ marginRight: "2rem" }} | |||
| > | |||
| Enter Timesheet | |||
| </Button> | |||
| <Button | |||
| variant="contained" | |||
| startIcon={<Add />} | |||
| sx={{ marginRight: "2rem" }} | |||
| LinkComponent={Link} | |||
| href="/projects/create" | |||
| > | |||
| Record Leave | |||
| </Button> | |||
| </Stack> | |||
| <Suspense> {/*fallback={<ProjectSearch.Loading />}>*/}</Suspense> | |||
| </div> | |||
| <EnterTimesheetModal | |||
| isOpen={isModalVisible} | |||
| onClose={handleCloseModal} | |||
| /> | |||
| <AssignedProjectGrid Title="Assigned Project" /> | |||
| </Grid> | |||
| </Grid> | |||
| ); | |||
| @@ -1,12 +1,11 @@ | |||
| import { createTheme } from '@mui/material/styles'; | |||
| import { createTheme } from "@mui/material/styles"; | |||
| const theme = createTheme({ | |||
| palette: { | |||
| background: { | |||
| default: '#fcfcfc' | |||
| } | |||
| } | |||
| default: "#fcfcfc", | |||
| }, | |||
| }, | |||
| }); | |||
| export default theme; | |||
| export default theme; | |||
| @@ -4,51 +4,85 @@ import { aborted } from "util"; | |||
| // - - - - - - WORK IN PROGRESS - - - - - - // | |||
| export const chartColor = [ | |||
| '#CB4047', '#ED3A41', '#F47B50', '#FBA647', | |||
| '#FDB64C', '#CCBB32', '#9ACC59', '#57B962', | |||
| '#1E83C5', '#7C4A9D' | |||
| "#CB4047", | |||
| "#ED3A41", | |||
| "#F47B50", | |||
| "#FBA647", | |||
| "#FDB64C", | |||
| "#CCBB32", | |||
| "#9ACC59", | |||
| "#57B962", | |||
| "#1E83C5", | |||
| "#7C4A9D", | |||
| ]; | |||
| export const chartSingleColor = [ | |||
| '#f2969a', '#fc9599', '#faa789', '#f7ae94', | |||
| '#ffd491', '#ede5a1', '#d1f5a2', '#9de0a4', | |||
| '#a2d4f5', '#b685d6' | |||
| "#f2969a", | |||
| "#fc9599", | |||
| "#faa789", | |||
| "#f7ae94", | |||
| "#ffd491", | |||
| "#ede5a1", | |||
| "#d1f5a2", | |||
| "#9de0a4", | |||
| "#a2d4f5", | |||
| "#b685d6", | |||
| ]; | |||
| export const rankColor = [ | |||
| '#FFD700', '#C0C0C0', '#CD853F', '#57B962', '#57B962', | |||
| '#57B962', '#57B962', '#57B962', '#57B962', '#57B962' | |||
| "#FFD700", | |||
| "#C0C0C0", | |||
| "#CD853F", | |||
| "#57B962", | |||
| "#57B962", | |||
| "#57B962", | |||
| "#57B962", | |||
| "#57B962", | |||
| "#57B962", | |||
| "#57B962", | |||
| ]; | |||
| export const piechartColor1 = [ | |||
| '#E84A3E', '#F2883C', '#FDCD4D', '#CE478A', '#B63D2A', | |||
| '#6A8B9E', '#60667E', '#58865F', '#2F763E', '#7D80B5', | |||
| "#E84A3E", | |||
| "#F2883C", | |||
| "#FDCD4D", | |||
| "#CE478A", | |||
| "#B63D2A", | |||
| "#6A8B9E", | |||
| "#60667E", | |||
| "#58865F", | |||
| "#2F763E", | |||
| "#7D80B5", | |||
| ]; | |||
| export const piechartColor2 = [ | |||
| '#6A8B9E', '#60667E', '#58865F', '#2F763E', '#7D80B5', | |||
| '#E84A3E', '#F2883C', '#FDCD4D', '#CE478A', '#B63D2A', | |||
| "#6A8B9E", | |||
| "#60667E", | |||
| "#58865F", | |||
| "#2F763E", | |||
| "#7D80B5", | |||
| "#E84A3E", | |||
| "#F2883C", | |||
| "#FDCD4D", | |||
| "#CE478A", | |||
| "#B63D2A", | |||
| ]; | |||
| export const cardBorderColor = [ | |||
| '#efb142', '#4bb641', '#448df2', '#e03c04' | |||
| ]; | |||
| export const cardBorderColor = ["#efb142", "#4bb641", "#448df2", "#e03c04"]; | |||
| export const chartLineColor = [ | |||
| '#FFFFFF', '#D9D9D9' | |||
| ]; | |||
| export const chartLineColor = ["#FFFFFF", "#D9D9D9"]; | |||
| export const GENERAL_RED_COLOR = '#e03c04'; | |||
| export const GENERAL_RED_COLOR = "#e03c04"; | |||
| export const TABLE_HEADER_TEXT_COLOR = "#3367D1"; | |||
| export const GENERAL_INFO_COLOR = '#448df2'; | |||
| export const GENERAL_INFO_COLOR = "#448df2"; | |||
| export const GENERAL_SETTING_COLOR = '#666666'; | |||
| export const GENERAL_SETTING_COLOR = "#666666"; | |||
| export const GENERAL_BORDER_COLOR = '#e6ebf1'; | |||
| export const GENERAL_BORDER_COLOR = "#e6ebf1"; | |||
| export const GENERAL_TEXT_COLOR = '#262626'; | |||
| export const GENERAL_TEXT_COLOR = "#262626"; | |||
| export const FONT_SIZE_L = "1.875rem"; | |||
| @@ -57,327 +91,327 @@ export const FONT_SIZE_M = "1.5rem"; | |||
| export const FONT_SIZE_S = "1.25rem"; | |||
| export const PROJECT_CARD_STYLE = { | |||
| borderRadius: '10px', | |||
| //border: '10px dotted #ccc', | |||
| width: '20rem', | |||
| margin: '20px', | |||
| //backgroundColor:"pink" | |||
| borderRadius: "10px", | |||
| //border: '10px dotted #ccc', | |||
| width: "20rem", | |||
| margin: "20px", | |||
| //backgroundColor:"pink" | |||
| }; | |||
| export const PROJECT_MODAL_STYLE = { | |||
| position: 'absolute', | |||
| width: '85%', | |||
| borderRadius: '10px', | |||
| height: '75%', | |||
| // top: '50%', | |||
| // left: '50%', | |||
| transform: 'translate(10%, 15%)', | |||
| backgroundColor: 'white', | |||
| padding: '20px', | |||
| display: 'flex', | |||
| flexDirection: 'column', | |||
| }; | |||
| position: "absolute", | |||
| width: "85%", | |||
| borderRadius: "10px", | |||
| height: "75%", | |||
| // top: '50%', | |||
| // left: '50%', | |||
| transform: "translate(10%, 15%)", | |||
| backgroundColor: "white", | |||
| padding: "20px", | |||
| display: "flex", | |||
| flexDirection: "column", | |||
| }; | |||
| export const DATAGRID_STYLE = { | |||
| boxShadow: 2, | |||
| border: 2, | |||
| borderColor: 'primary.light', | |||
| '& .MuiDataGrid-cell:hover': { | |||
| color: 'primary.main' | |||
| }, | |||
| '& .MuiDataGrid-root': { | |||
| overflow: 'auto', | |||
| } | |||
| boxShadow: 2, | |||
| border: 2, | |||
| borderColor: "primary.light", | |||
| "& .MuiDataGrid-cell:hover": { | |||
| color: "primary.main", | |||
| }, | |||
| "& .MuiDataGrid-root": { | |||
| overflow: "auto", | |||
| }, | |||
| }; | |||
| export const TAB_THEME = { | |||
| components: { | |||
| MuiTab: { | |||
| styleOverrides: { | |||
| root: { | |||
| // fontSize: '1.0rem', | |||
| fontSize: '1.25rem'//'20px', | |||
| // height: '40px', | |||
| // width: '40vw', // Default width for xs screen sizes | |||
| // '@media (min-width: 600px)': { // sm breakpoint | |||
| // width: '20vw', | |||
| // }, | |||
| // '@media (min-width: 960px)': { // md breakpoint | |||
| // width: '15vw', | |||
| // }, | |||
| // '@media (min-width: 1280px)': { // lg breakpoint | |||
| // width: '7vw', | |||
| // }, | |||
| // textTransform: "none", | |||
| // alignItems: 'center' | |||
| }, | |||
| }, | |||
| }, | |||
| } | |||
| }; | |||
| components: { | |||
| MuiTab: { | |||
| styleOverrides: { | |||
| root: { | |||
| // fontSize: '1.0rem', | |||
| fontSize: "1.25rem", //'20px', | |||
| // height: '40px', | |||
| // width: '40vw', // Default width for xs screen sizes | |||
| // '@media (min-width: 600px)': { // sm breakpoint | |||
| // width: '20vw', | |||
| // }, | |||
| // '@media (min-width: 960px)': { // md breakpoint | |||
| // width: '15vw', | |||
| // }, | |||
| // '@media (min-width: 1280px)': { // lg breakpoint | |||
| // width: '7vw', | |||
| // }, | |||
| // textTransform: "none", | |||
| // alignItems: 'center' | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| }; | |||
| // copy from MTMS | |||
| export const TSMS_BUTTON_THEME = createTheme({ | |||
| palette: { | |||
| primary: { | |||
| main: '#92C1E9', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| secondary: { | |||
| main: '#898D8D', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| success: { | |||
| main: '#ADCAB8', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| danger: { | |||
| main: '#F890A5', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| warning: { | |||
| main: '#EFBE7D', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| disable: { | |||
| main: '#B2B4B2', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| create: { | |||
| // main: '#57B962', | |||
| main: '#ADCAB8', | |||
| // light: will be calculated from palette.primary.main, | |||
| // dark: will be calculated from palette.primary.main, | |||
| // contrastText: will be calculated to contrast with palette.primary.main | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| delete: { | |||
| // main: '#E03C04', | |||
| main: '#F890A5', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| cancel: { | |||
| // main: '#999999', | |||
| main: '#F890A5', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| back: { | |||
| // main: '#999999', | |||
| main: '#898D8D', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| reset: { | |||
| main: '#EFBE7D', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| save: { | |||
| // main: '#448DF2', | |||
| main: '#92C1E9', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| export: { | |||
| main: '#8C52FF', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| import: { | |||
| main: '#92C1E9', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| saveAs: { | |||
| main: '#FFBD59', | |||
| contrastText: '#FFFFFF', | |||
| } | |||
| }, | |||
| components: { | |||
| MuiButton: { | |||
| styleOverrides: { | |||
| root: { | |||
| '& .MuiButtonBase-root-MuiButton-root': { | |||
| fontSize: FONT_SIZE_S | |||
| }, | |||
| } | |||
| } | |||
| }, | |||
| MuiButtonBase: { | |||
| styleOverrides: { | |||
| root: { | |||
| '&.MuiChip-root.Mui-disabled': { | |||
| opacity: 0.75, | |||
| }, | |||
| '&.MuiButton-root': { | |||
| fontSize: FONT_SIZE_S | |||
| }, | |||
| } | |||
| } | |||
| }, | |||
| } | |||
| palette: { | |||
| primary: { | |||
| main: "#92C1E9", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| secondary: { | |||
| main: "#898D8D", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| success: { | |||
| main: "#ADCAB8", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| danger: { | |||
| main: "#F890A5", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| warning: { | |||
| main: "#EFBE7D", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| disable: { | |||
| main: "#B2B4B2", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| create: { | |||
| // main: '#57B962', | |||
| main: "#ADCAB8", | |||
| // light: will be calculated from palette.primary.main, | |||
| // dark: will be calculated from palette.primary.main, | |||
| // contrastText: will be calculated to contrast with palette.primary.main | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| delete: { | |||
| // main: '#E03C04', | |||
| main: "#F890A5", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| cancel: { | |||
| // main: '#999999', | |||
| main: "#F890A5", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| back: { | |||
| // main: '#999999', | |||
| main: "#898D8D", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| reset: { | |||
| main: "#EFBE7D", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| save: { | |||
| // main: '#448DF2', | |||
| main: "#92C1E9", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| export: { | |||
| main: "#8C52FF", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| import: { | |||
| main: "#92C1E9", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| saveAs: { | |||
| main: "#FFBD59", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| }, | |||
| components: { | |||
| MuiButton: { | |||
| styleOverrides: { | |||
| root: { | |||
| "& .MuiButtonBase-root-MuiButton-root": { | |||
| fontSize: FONT_SIZE_S, | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| MuiButtonBase: { | |||
| styleOverrides: { | |||
| root: { | |||
| "&.MuiChip-root.Mui-disabled": { | |||
| opacity: 0.75, | |||
| }, | |||
| "&.MuiButton-root": { | |||
| fontSize: FONT_SIZE_S, | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| }); | |||
| export const formTheme = createTheme({ | |||
| components: { | |||
| MuiFormLabel: { | |||
| root: { // Name of the rule | |||
| color: "rgba(0, 0, 0, 1)", | |||
| }, | |||
| styleOverrides: { | |||
| asterisk: { | |||
| color: "#db3131", | |||
| "&$error": { | |||
| color: "#db3131", | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| components: { | |||
| MuiFormLabel: { | |||
| root: { | |||
| // Name of the rule | |||
| color: "rgba(0, 0, 0, 1)", | |||
| }, | |||
| styleOverrides: { | |||
| asterisk: { | |||
| color: "#db3131", | |||
| "&$error": { | |||
| color: "#db3131", | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| }); | |||
| export const ARS_BUTTON_THEME = createTheme({ | |||
| palette: { | |||
| create: { | |||
| main: '#57B962', | |||
| // light: will be calculated from palette.primary.main, | |||
| // dark: will be calculated from palette.primary.main, | |||
| // contrastText: will be calculated to contrast with palette.primary.main | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| delete: { | |||
| main: '#E03C04', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| cancel: { | |||
| main: '#999999', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| save: { | |||
| main: '#448DF2', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| export: { | |||
| main: '#8C52FF', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| saveAs: { | |||
| main: '#FFBD59', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| edit: { | |||
| main: '#F3AF2B', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| exportExcel: { | |||
| main: '#6A8B9E', | |||
| contrastText: '#FFFFFF', | |||
| } | |||
| }, | |||
| components: { | |||
| MuiDataGrid: { | |||
| styleOverrides: { | |||
| actionsCell: { | |||
| '& .MuiDataGrid-actionsContainer .MuiIconButton-root': { | |||
| fontSize: '80px', // Set the desired icon size here | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| MuiButton: { | |||
| styleOverrides: { | |||
| root: { | |||
| // fontSize: '1.0rem', | |||
| fontSize: '1.25rem', | |||
| height: '40px', | |||
| width: '40vw', // Default width for xs screen sizes | |||
| '@media (min-width: 600px)': { // sm breakpoint | |||
| width: '20vw', | |||
| }, | |||
| '@media (min-width: 960px)': { // md breakpoint | |||
| width: '15vw', | |||
| }, | |||
| '@media (min-width: 1280px)': { // lg breakpoint | |||
| width: '7vw', | |||
| }, | |||
| textTransform: "none", | |||
| alignItems: 'center' | |||
| }, | |||
| }, | |||
| }, | |||
| } | |||
| palette: { | |||
| create: { | |||
| main: "#57B962", | |||
| // light: will be calculated from palette.primary.main, | |||
| // dark: will be calculated from palette.primary.main, | |||
| // contrastText: will be calculated to contrast with palette.primary.main | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| delete: { | |||
| main: "#E03C04", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| cancel: { | |||
| main: "#999999", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| save: { | |||
| main: "#448DF2", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| export: { | |||
| main: "#8C52FF", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| saveAs: { | |||
| main: "#FFBD59", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| edit: { | |||
| main: "#F3AF2B", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| exportExcel: { | |||
| main: "#6A8B9E", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| }, | |||
| components: { | |||
| MuiDataGrid: { | |||
| styleOverrides: { | |||
| actionsCell: { | |||
| "& .MuiDataGrid-actionsContainer .MuiIconButton-root": { | |||
| fontSize: "80px", // Set the desired icon size here | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| MuiButton: { | |||
| styleOverrides: { | |||
| root: { | |||
| // fontSize: '1.0rem', | |||
| fontSize: "1.25rem", | |||
| height: "40px", | |||
| width: "40vw", // Default width for xs screen sizes | |||
| "@media (min-width: 600px)": { | |||
| // sm breakpoint | |||
| width: "20vw", | |||
| }, | |||
| "@media (min-width: 960px)": { | |||
| // md breakpoint | |||
| width: "15vw", | |||
| }, | |||
| "@media (min-width: 1280px)": { | |||
| // lg breakpoint | |||
| width: "7vw", | |||
| }, | |||
| textTransform: "none", | |||
| alignItems: "center", | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| }); | |||
| //from ARS | |||
| export const TSMS_LONG_BUTTON_THEME = createTheme({ | |||
| palette: { | |||
| create: { | |||
| main: '#57B962', | |||
| // light: will be calculated from palette.primary.main, | |||
| // dark: will be calculated from palette.primary.main, | |||
| // contrastText: will be calculated to contrast with palette.primary.main | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| delete: { | |||
| main: '#E03C04', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| cancel: { | |||
| main: '#999999', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| save: { | |||
| main: '#448DF2', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| export: { | |||
| main: '#8C52FF', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| saveAs: { | |||
| main: '#FFBD59', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| edit: { | |||
| main: '#F3AF2B', | |||
| contrastText: '#FFFFFF', | |||
| }, | |||
| exportExcel: { | |||
| main: '#60667E', | |||
| contrastText: '#FFFFFF', | |||
| } | |||
| }, | |||
| components: { | |||
| MuiDataGrid: { | |||
| styleOverrides: { | |||
| actionsCell: { | |||
| '& .MuiDataGrid-actionsContainer .MuiIconButton-root': { | |||
| fontSize: '80px', // Set the desired icon size here | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| MuiButton: { | |||
| styleOverrides: { | |||
| root: { | |||
| fontSize: '1.25rem', | |||
| height: '40px', | |||
| width: '40vw', // Default width for xs screen sizes | |||
| '@media (min-width: 600px)': { // sm breakpoint | |||
| width: '30vw', | |||
| }, | |||
| '@media (min-width: 960px)': { // md breakpoint | |||
| width: '25vw', | |||
| }, | |||
| '@media (min-width: 1280px)': { // lg breakpoint | |||
| width: '14vw', | |||
| }, | |||
| textTransform: "none", | |||
| alignItems: 'center' | |||
| }, | |||
| }, | |||
| }, | |||
| } | |||
| }); | |||
| palette: { | |||
| create: { | |||
| main: "#57B962", | |||
| // light: will be calculated from palette.primary.main, | |||
| // dark: will be calculated from palette.primary.main, | |||
| // contrastText: will be calculated to contrast with palette.primary.main | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| delete: { | |||
| main: "#E03C04", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| cancel: { | |||
| main: "#999999", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| save: { | |||
| main: "#448DF2", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| export: { | |||
| main: "#8C52FF", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| saveAs: { | |||
| main: "#FFBD59", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| edit: { | |||
| main: "#F3AF2B", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| exportExcel: { | |||
| main: "#60667E", | |||
| contrastText: "#FFFFFF", | |||
| }, | |||
| }, | |||
| components: { | |||
| MuiDataGrid: { | |||
| styleOverrides: { | |||
| actionsCell: { | |||
| "& .MuiDataGrid-actionsContainer .MuiIconButton-root": { | |||
| fontSize: "80px", // Set the desired icon size here | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| MuiButton: { | |||
| styleOverrides: { | |||
| root: { | |||
| fontSize: "1.25rem", | |||
| height: "40px", | |||
| width: "40vw", // Default width for xs screen sizes | |||
| "@media (min-width: 600px)": { | |||
| // sm breakpoint | |||
| width: "30vw", | |||
| }, | |||
| "@media (min-width: 960px)": { | |||
| // md breakpoint | |||
| width: "25vw", | |||
| }, | |||
| "@media (min-width: 1280px)": { | |||
| // lg breakpoint | |||
| width: "14vw", | |||
| }, | |||
| textTransform: "none", | |||
| alignItems: "center", | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| }); | |||