@@ -18,9 +18,6 @@ const CompanyTeamCashFlow: React.FC = () => { | |||||
preloadClientProjects(); | preloadClientProjects(); | ||||
return ( | return ( | ||||
<I18nProvider namespaces={["dashboard"]}> | <I18nProvider namespaces={["dashboard"]}> | ||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
Company / Team Cash Flow | |||||
</Typography> | |||||
<CompanyTeamCashFlowComponent /> | <CompanyTeamCashFlowComponent /> | ||||
</I18nProvider> | </I18nProvider> | ||||
); | ); | ||||
@@ -17,10 +17,7 @@ export const metadata: Metadata = { | |||||
const ProjectCashFlow: React.FC = () => { | const ProjectCashFlow: React.FC = () => { | ||||
preloadClientProjects(); | preloadClientProjects(); | ||||
return ( | return ( | ||||
<I18nProvider namespaces={["dashboard"]}> | |||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
Project Cash Flow | |||||
</Typography> | |||||
<I18nProvider namespaces={["dashboard",'common']}> | |||||
{/* <Suspense fallback={<ProgressCashFlowSearch.Loading />}> | {/* <Suspense fallback={<ProgressCashFlowSearch.Loading />}> | ||||
<ProgressCashFlowSearch/> | <ProgressCashFlowSearch/> | ||||
</Suspense> */} | </Suspense> */} | ||||
@@ -9,6 +9,7 @@ import Tab from "@mui/material/Tab"; | |||||
import Typography from "@mui/material/Typography"; | import Typography from "@mui/material/Typography"; | ||||
import ProjectFinancialSummaryComponents from "@/components/ProjectFinancialSummary"; | import ProjectFinancialSummaryComponents from "@/components/ProjectFinancialSummary"; | ||||
import { preloadClientProjects } from "@/app/api/clientprojects"; | import { preloadClientProjects } from "@/app/api/clientprojects"; | ||||
import { useTranslation } from "react-i18next"; | |||||
export const metadata: Metadata = { | export const metadata: Metadata = { | ||||
title: "Project Status by Client", | title: "Project Status by Client", | ||||
@@ -17,10 +18,7 @@ export const metadata: Metadata = { | |||||
const ProjectFinancialSummary: React.FC = () => { | const ProjectFinancialSummary: React.FC = () => { | ||||
preloadClientProjects(); | preloadClientProjects(); | ||||
return ( | return ( | ||||
<I18nProvider namespaces={["dashboard"]}> | |||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
Financial Summary | |||||
</Typography> | |||||
<I18nProvider namespaces={["dashboard", "common"]}> | |||||
<ProjectFinancialSummaryComponents /> | <ProjectFinancialSummaryComponents /> | ||||
</I18nProvider> | </I18nProvider> | ||||
); | ); | ||||
@@ -17,10 +17,7 @@ export const metadata: Metadata = { | |||||
const ProjectResourceConsumptionRanking: React.FC = () => { | const ProjectResourceConsumptionRanking: React.FC = () => { | ||||
preloadClientProjects(); | preloadClientProjects(); | ||||
return ( | return ( | ||||
<I18nProvider namespaces={["dashboard"]}> | |||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
Project Resource Consumption Ranking | |||||
</Typography> | |||||
<I18nProvider namespaces={["dashboard","common"]}> | |||||
<ProjectResourceConsumptionRankingDisplay/> | <ProjectResourceConsumptionRankingDisplay/> | ||||
</I18nProvider> | </I18nProvider> | ||||
); | ); | ||||
@@ -5,11 +5,11 @@ import DashboardPageButton from "@/components/DashboardPage/DashboardTabButton"; | |||||
import { Suspense } from "react"; | import { Suspense } from "react"; | ||||
import Tabs, { TabsProps } from "@mui/material/Tabs"; | import Tabs, { TabsProps } from "@mui/material/Tabs"; | ||||
import Tab from "@mui/material/Tab"; | import Tab from "@mui/material/Tab"; | ||||
import Typography from "@mui/material/Typography"; | |||||
import StaffUtilizationComponent from "@/components/StaffUtilization"; | import StaffUtilizationComponent from "@/components/StaffUtilization"; | ||||
import ProjectResourceSummarySearch from "@/components/ProjectResourceSummarySearch"; | import ProjectResourceSummarySearch from "@/components/ProjectResourceSummarySearch"; | ||||
import { ResourceSummaryResult } from "@/app/api/resourcesummary"; | import { ResourceSummaryResult } from "@/app/api/resourcesummary"; | ||||
import { preloadClientProjects } from "@/app/api/clientprojects"; | import { preloadClientProjects } from "@/app/api/clientprojects"; | ||||
import ProjectResourceSummaryComponent from "@/components/ProjectResourceSummary"; | |||||
export const metadata: Metadata = { | export const metadata: Metadata = { | ||||
title: "Project Resource Summary", | title: "Project Resource Summary", | ||||
@@ -18,13 +18,11 @@ export const metadata: Metadata = { | |||||
const ProjectResourceSummary: React.FC = () => { | const ProjectResourceSummary: React.FC = () => { | ||||
preloadClientProjects(); | preloadClientProjects(); | ||||
return ( | return ( | ||||
<I18nProvider namespaces={["dashboard"]}> | |||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
Project Resource Summary | |||||
</Typography> | |||||
<I18nProvider namespaces={["dashboard","common"]}> | |||||
<Suspense fallback={<ProjectResourceSummarySearch.Loading />}> | <Suspense fallback={<ProjectResourceSummarySearch.Loading />}> | ||||
<ProjectResourceSummarySearch/> | <ProjectResourceSummarySearch/> | ||||
</Suspense> | </Suspense> | ||||
{/* <ProjectResourceSummaryComponent/> */} | |||||
</I18nProvider> | </I18nProvider> | ||||
); | ); | ||||
}; | }; | ||||
@@ -20,10 +20,7 @@ export const metadata: Metadata = { | |||||
const ProjectStatusByClient: React.FC = () => { | const ProjectStatusByClient: React.FC = () => { | ||||
preloadClientProjects(); | preloadClientProjects(); | ||||
return ( | return ( | ||||
<I18nProvider namespaces={["dashboard"]}> | |||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
Project Status by Client | |||||
</Typography> | |||||
<I18nProvider namespaces={["dashboard","common"]}> | |||||
<Suspense fallback={<ProgressByClientSearch.Loading />}> | <Suspense fallback={<ProgressByClientSearch.Loading />}> | ||||
<ProgressByClientSearch /> | <ProgressByClientSearch /> | ||||
</Suspense> | </Suspense> | ||||
@@ -17,10 +17,7 @@ export const metadata: Metadata = { | |||||
const ProjectStatusByTeam: React.FC = () => { | const ProjectStatusByTeam: React.FC = () => { | ||||
preloadClientProjects(); | preloadClientProjects(); | ||||
return ( | return ( | ||||
<I18nProvider namespaces={["dashboard"]}> | |||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
Project Status by Team | |||||
</Typography> | |||||
<I18nProvider namespaces={["dashboard","common"]}> | |||||
<Suspense fallback={<ProgressByTeamSearch.Loading />}> | <Suspense fallback={<ProgressByTeamSearch.Loading />}> | ||||
<ProgressByTeamSearch /> | <ProgressByTeamSearch /> | ||||
</Suspense> | </Suspense> | ||||
@@ -18,9 +18,6 @@ const StaffUtilization: React.FC = () => { | |||||
preloadClientProjects(); | preloadClientProjects(); | ||||
return ( | return ( | ||||
<I18nProvider namespaces={["dashboard"]}> | <I18nProvider namespaces={["dashboard"]}> | ||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
Staff Utilization | |||||
</Typography> | |||||
<StaffUtilizationComponent /> | <StaffUtilizationComponent /> | ||||
</I18nProvider> | </I18nProvider> | ||||
); | ); | ||||
@@ -15,9 +15,9 @@ const pathToLabelMap: { [path: string]: string } = { | |||||
"/home": "User Workspace", | "/home": "User Workspace", | ||||
"/changepassword": "Change Password", | "/changepassword": "Change Password", | ||||
"/dashboard": "Dashboard", | "/dashboard": "Dashboard", | ||||
"/dashboard/CompanyTeamCashFlow": "Company Team Cash Flow", | |||||
"/dashboard/CompanyTeamCashFlow": "Company / Team Cash Flow", | |||||
"/dashboard/ProjectCashFlow": "Project Cash Flow", | "/dashboard/ProjectCashFlow": "Project Cash Flow", | ||||
"/dashboard/ProjectFinancialSummary": "Project Finanical Summary", | |||||
"/dashboard/ProjectFinancialSummary": "Financial Summary", | |||||
"/dashboard/ProjectResourceSummary": "Project Resource Summary", | "/dashboard/ProjectResourceSummary": "Project Resource Summary", | ||||
"/dashboard/ProjectStatusByClient": "Project Status by Client", | "/dashboard/ProjectStatusByClient": "Project Status by Client", | ||||
"/dashboard/ProjectStatusByTeam": "Project Status by Team", | "/dashboard/ProjectStatusByTeam": "Project Status by Team", | ||||
@@ -82,7 +82,8 @@ const Breadcrumb = () => { | |||||
const pathname = usePathname(); | const pathname = usePathname(); | ||||
const segments = pathname.split("/"); | const segments = pathname.split("/"); | ||||
// const { t } = useTranslation("customer"); | |||||
//const { t } = useTranslation("customer"); | |||||
const { t } = useTranslation("common"); | |||||
return ( | return ( | ||||
<Box | <Box | ||||
@@ -93,7 +94,9 @@ const Breadcrumb = () => { | |||||
<Breadcrumbs> | <Breadcrumbs> | ||||
{segments.map((segment, index) => { | {segments.map((segment, index) => { | ||||
const href = segments.slice(0, index + 1).join("/"); | const href = segments.slice(0, index + 1).join("/"); | ||||
const label = pathToLabelMap[href] || segment; | |||||
// const label = pathToLabelMap[href] || segment; | |||||
const originalLabel = pathToLabelMap[href] || segment; | |||||
const label = t(originalLabel, originalLabel); | |||||
if (index === segments.length - 1) { | if (index === segments.length - 1) { | ||||
return ( | return ( | ||||
@@ -24,6 +24,7 @@ import Select, { components } from "react-select"; | |||||
import { fetchTeamCombo, fetchTeamCashFlowChartData } from "@/app/api/teamCashflow"; | import { fetchTeamCombo, fetchTeamCashFlowChartData } from "@/app/api/teamCashflow"; | ||||
import { VIEW_DASHBOARD_ALL } from "@/middleware"; | import { VIEW_DASHBOARD_ALL } from "@/middleware"; | ||||
import { SessionStaff } from "@/config/authConfig"; | import { SessionStaff } from "@/config/authConfig"; | ||||
import Typography from "@mui/material/Typography"; | |||||
interface Props { | interface Props { | ||||
abilities: string[], | abilities: string[], | ||||
@@ -31,6 +32,7 @@ interface Props { | |||||
} | } | ||||
const CompanyTeamCashFlow: React.FC<Props> = ({ abilities, staff }) => { | const CompanyTeamCashFlow: React.FC<Props> = ({ abilities, staff }) => { | ||||
const { t } = useTranslation("dashboard"); | |||||
const todayDate = new Date(); | const todayDate = new Date(); | ||||
const [selectionModel, setSelectionModel]: any[] = React.useState([]); | const [selectionModel, setSelectionModel]: any[] = React.useState([]); | ||||
const [teamOptions, setTeamOptions]: any[] = React.useState([]); | const [teamOptions, setTeamOptions]: any[] = React.useState([]); | ||||
@@ -220,24 +222,27 @@ const CompanyTeamCashFlow: React.FC<Props> = ({ abilities, staff }) => { | |||||
}, | }, | ||||
xaxis: { | xaxis: { | ||||
categories: [ | categories: [ | ||||
"JAN", | |||||
"FEB", | |||||
"MAR", | |||||
"APR", | |||||
"MAY", | |||||
"JUN", | |||||
"JUL", | |||||
"AUG", | |||||
"SEP", | |||||
"OCT", | |||||
"NOV", | |||||
"DEC", | |||||
t("JAN"), | |||||
t("FEB"), | |||||
t("MAR"), | |||||
t("APR"), | |||||
t("MAY"), | |||||
t("JUN"), | |||||
t("JUL"), | |||||
t("AUG"), | |||||
t("SEP"), | |||||
t("OCT"), | |||||
t("NOV"), | |||||
t("DEC"), | |||||
], | ], | ||||
}, | }, | ||||
yaxis: [ | yaxis: [ | ||||
{ | { | ||||
title: { | title: { | ||||
text: "Monthly Income and Expenditure(HKD)", | |||||
text:t("Monthly Income and Expenditure (HKD)"), | |||||
style: { | |||||
fontSize: '15px' | |||||
} | |||||
}, | }, | ||||
min: 0, | min: 0, | ||||
max: monthlyChartLeftMax, | max: monthlyChartLeftMax, | ||||
@@ -252,7 +257,7 @@ const CompanyTeamCashFlow: React.FC<Props> = ({ abilities, staff }) => { | |||||
show: false, | show: false, | ||||
seriesName: "Monthly Expenditure", | seriesName: "Monthly Expenditure", | ||||
title: { | title: { | ||||
text: "Monthly Expenditure (HKD)", | |||||
text: t("Monthly Expenditure (HKD)"), | |||||
}, | }, | ||||
min: 0, | min: 0, | ||||
max: monthlyChartLeftMax, | max: monthlyChartLeftMax, | ||||
@@ -262,7 +267,10 @@ const CompanyTeamCashFlow: React.FC<Props> = ({ abilities, staff }) => { | |||||
seriesName: "Cumulative Income", | seriesName: "Cumulative Income", | ||||
opposite: true, | opposite: true, | ||||
title: { | title: { | ||||
text: "Cumulative Income and Expenditure(HKD)", | |||||
text: t("Cumulative Income and Expenditure (HKD)"), | |||||
style: { | |||||
fontSize: '15px' | |||||
} | |||||
}, | }, | ||||
min: 0, | min: 0, | ||||
max: monthlyChartRightMax, | max: monthlyChartRightMax, | ||||
@@ -278,7 +286,7 @@ const CompanyTeamCashFlow: React.FC<Props> = ({ abilities, staff }) => { | |||||
seriesName: "Cumulative Expenditure", | seriesName: "Cumulative Expenditure", | ||||
opposite: true, | opposite: true, | ||||
title: { | title: { | ||||
text: "Cumulative Expenditure (HKD)", | |||||
text: t("Cumulative Expenditure (HKD)"), | |||||
}, | }, | ||||
min: 0, | min: 0, | ||||
max: monthlyChartRightMax, | max: monthlyChartRightMax, | ||||
@@ -291,25 +299,25 @@ const CompanyTeamCashFlow: React.FC<Props> = ({ abilities, staff }) => { | |||||
annotations: {}, | annotations: {}, | ||||
series: [ | series: [ | ||||
{ | { | ||||
name: "Monthly Income", | |||||
name: t("Monthly Income"), | |||||
type: "column", | type: "column", | ||||
color: "#ffde91", | color: "#ffde91", | ||||
data: monthlyIncomeList, | data: monthlyIncomeList, | ||||
}, | }, | ||||
{ | { | ||||
name: "Monthly Expenditure", | |||||
name: t("Monthly Expenditure"), | |||||
type: "column", | type: "column", | ||||
color: "#82b59a", | color: "#82b59a", | ||||
data: monthlyExpenditureList, | data: monthlyExpenditureList, | ||||
}, | }, | ||||
{ | { | ||||
name: "Cumulative Income", | |||||
name: t("Cumulative Income"), | |||||
type: "line", | type: "line", | ||||
color: "#EE6D7A", | color: "#EE6D7A", | ||||
data: monthlyCumulativeIncomeList, | data: monthlyCumulativeIncomeList, | ||||
}, | }, | ||||
{ | { | ||||
name: "Cumulative Expenditure", | |||||
name: t("Cumulative Expenditure"), | |||||
type: "line", | type: "line", | ||||
color: "#7cd3f2", | color: "#7cd3f2", | ||||
data: monthlyCumulativeExpenditureList, | data: monthlyCumulativeExpenditureList, | ||||
@@ -320,17 +328,20 @@ const CompanyTeamCashFlow: React.FC<Props> = ({ abilities, staff }) => { | |||||
return ( | return ( | ||||
<> | <> | ||||
<Grid item sm> | <Grid item sm> | ||||
<div style={{ display: "inline-block", width: "100%" }}> | |||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
{t("Company / Team Cash Flow")} | |||||
</Typography> | |||||
<div style={{ display: "inline-block", width: "100%" }} className={"mt-5"}> | |||||
<Grid item xs={12} md={12} lg={12}> | <Grid item xs={12} md={12} lg={12}> | ||||
<Card> | <Card> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Company and Team Cash Flow by Month" | |||||
title={t("Company and Team Cash Flow By Month")} | |||||
/> | /> | ||||
<div style={{ display: "inline-block", width: "99%" }}> | <div style={{ display: "inline-block", width: "99%" }}> | ||||
<div className="inline-block"> | <div className="inline-block"> | ||||
<Label className="text-slate-500 font-medium ml-6"> | <Label className="text-slate-500 font-medium ml-6"> | ||||
Period: | |||||
{t("Year")}: | |||||
</Label> | </Label> | ||||
<Input | <Input | ||||
id={"cashFlowYear"} | id={"cashFlowYear"} | ||||
@@ -359,12 +370,12 @@ const CompanyTeamCashFlow: React.FC<Props> = ({ abilities, staff }) => { | |||||
{abilities.includes(VIEW_DASHBOARD_ALL) && <div className="inline-block"> | {abilities.includes(VIEW_DASHBOARD_ALL) && <div className="inline-block"> | ||||
<div className="inline-block ml-2"> | <div className="inline-block ml-2"> | ||||
<Label className="text-slate-500 font-medium"> | <Label className="text-slate-500 font-medium"> | ||||
Team: | |||||
{t("Team")}: | |||||
</Label> | </Label> | ||||
</div> | </div> | ||||
<div className="inline-block ml-1 w-60"> | <div className="inline-block ml-1 w-60"> | ||||
<Select | <Select | ||||
placeholder="All Team" | |||||
placeholder={t("All Team")} | |||||
options={teamOptions} | options={teamOptions} | ||||
isClearable={true} | isClearable={true} | ||||
onChange={(selectedOption: any) => { | onChange={(selectedOption: any) => { | ||||
@@ -101,6 +101,7 @@ interface Props { | |||||
} | } | ||||
const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | ||||
const { t } = useTranslation("common"); | |||||
const navigationItems: NavigationItem[] = [ | const navigationItems: NavigationItem[] = [ | ||||
{ | { | ||||
icon: <WorkHistory />, | icon: <WorkHistory />, | ||||
@@ -110,7 +111,7 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | |||||
}, | }, | ||||
{ | { | ||||
icon: <Dashboard />, | icon: <Dashboard />, | ||||
label: "Dashboard", | |||||
label: t("Dashboard"), | |||||
path: "", | path: "", | ||||
isHidden: ![VIEW_DASHBOARD_ALL, VIEW_DASHBOARD_SELF].some((ability) => | isHidden: ![VIEW_DASHBOARD_ALL, VIEW_DASHBOARD_SELF].some((ability) => | ||||
abilities!.includes(ability), | abilities!.includes(ability), | ||||
@@ -411,7 +412,7 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | |||||
const isMobile = useIsMobile(); | const isMobile = useIsMobile(); | ||||
const { t } = useTranslation("common"); | |||||
// const { t } = useTranslation("common"); | |||||
const pathname = usePathname(); | const pathname = usePathname(); | ||||
const [openItems, setOpenItems] = React.useState<string[]>([]); | const [openItems, setOpenItems] = React.useState<string[]>([]); | ||||
const toggleItem = (label: string) => { | const toggleItem = (label: string) => { | ||||
@@ -235,31 +235,31 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
{ | { | ||||
id: "projectCode", | id: "projectCode", | ||||
field: "projectCode", | field: "projectCode", | ||||
headerName: "Project No", | |||||
headerName: t("Project Code"), | |||||
minWidth:100 | minWidth:100 | ||||
}, | }, | ||||
{ | { | ||||
id: "projectName", | id: "projectName", | ||||
field: "projectName", | field: "projectName", | ||||
headerName: "Project", | |||||
headerName: t("Project Name"), | |||||
minWidth:300 | minWidth:300 | ||||
}, | }, | ||||
{ | { | ||||
id: "team", | id: "team", | ||||
field: "team", | field: "team", | ||||
headerName: "Team", | |||||
headerName: t("Team"), | |||||
minWidth: 50 | minWidth: 50 | ||||
}, | }, | ||||
{ | { | ||||
id: "teamLead", | id: "teamLead", | ||||
field: "teamLead", | field: "teamLead", | ||||
headerName: "Team Leader", | |||||
headerName: t("Team Leader"), | |||||
minWidth: 70 | minWidth: 70 | ||||
}, | }, | ||||
{ | { | ||||
id: "expectedStage", | id: "expectedStage", | ||||
field: "expectedStage", | field: "expectedStage", | ||||
headerName: "Expected Stage", | |||||
headerName: t("Expected Stage"), | |||||
minWidth: 300, | minWidth: 300, | ||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.expectedStage != null){ | if (params.row.expectedStage != null){ | ||||
@@ -280,7 +280,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
{ | { | ||||
id: "budgetedManhour", | id: "budgetedManhour", | ||||
field: "budgetedManhour", | field: "budgetedManhour", | ||||
headerName: "Budgeted Manhour", | |||||
headerName: t("Budgeted Manhours"), | |||||
minWidth: 70, | minWidth: 70, | ||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
return <span>{params.row.budgetedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>; | return <span>{params.row.budgetedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>; | ||||
@@ -289,7 +289,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
{ | { | ||||
id: "spentManhour", | id: "spentManhour", | ||||
field: "spentManhour", | field: "spentManhour", | ||||
headerName: "Spent Manhour", | |||||
headerName: t("Spent Manhours"), | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | ||||
return ( | return ( | ||||
@@ -305,7 +305,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
{ | { | ||||
id: "remainedManhour", | id: "remainedManhour", | ||||
field: "remainedManhour", | field: "remainedManhour", | ||||
headerName: "Remained Manhour", | |||||
headerName: t("Remained Manhours"), | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | ||||
return ( | return ( | ||||
@@ -320,13 +320,13 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
{ | { | ||||
id: "comingPaymentMilestone", | id: "comingPaymentMilestone", | ||||
field: "comingPaymentMilestone", | field: "comingPaymentMilestone", | ||||
headerName: "Coming Payment Milestone", | |||||
headerName: t("Coming Payment Milestones"), | |||||
minWidth: 100 | minWidth: 100 | ||||
}, | }, | ||||
{ | { | ||||
id: "alert", | id: "alert", | ||||
field: "alert", | field: "alert", | ||||
headerName: "Alert", | |||||
headerName: t("Alert"), | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.alert === true) { | if (params.row.alert === true) { | ||||
return ( | return ( | ||||
@@ -364,7 +364,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
total: { | total: { | ||||
show: true, | show: true, | ||||
showAlways: true, | showAlways: true, | ||||
label: "Spent", | |||||
label: t("Spent"), | |||||
fontFamily: "sans-serif", | fontFamily: "sans-serif", | ||||
formatter: function (val) { | formatter: function (val) { | ||||
return totalSpentPercentage + "%"; | return totalSpentPercentage + "%"; | ||||
@@ -412,9 +412,9 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
<div style="width: auto;"> | <div style="width: auto;"> | ||||
<span style="font-weight: bold;">${projectCode} - ${projectName}</span> | <span style="font-weight: bold;">${projectCode} - ${projectName}</span> | ||||
<br> | <br> | ||||
Budget Manhours: ${budgetManhours} hours | |||||
${t("Budget Manhours")}: ${budgetManhours} hours | |||||
<br> | <br> | ||||
Spent Manhours: ${spentManhours} hours | |||||
${t("Spent Manhours")}: ${spentManhours} hours | |||||
<br> | <br> | ||||
Percentage: ${value}% | Percentage: ${value}% | ||||
</div> | </div> | ||||
@@ -424,7 +424,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
}, | }, | ||||
}, | }, | ||||
series: [{ | series: [{ | ||||
name: "Project Resource Consumption Percentage", | |||||
name: t("Project Resource Consumption Percentage (%)"), | |||||
data: chartManhourConsumptionPercentage, | data: chartManhourConsumptionPercentage, | ||||
},], | },], | ||||
colors: ["#f57f90", "#94f7d6", "#87c5f5", "#ab95f5", "#fcd68b", | colors: ["#f57f90", "#94f7d6", "#87c5f5", "#ab95f5", "#fcd68b", | ||||
@@ -471,7 +471,11 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
}, | }, | ||||
yaxis: { | yaxis: { | ||||
title: { | title: { | ||||
text: "Projects", | |||||
text: t("Projects"), | |||||
style: { | |||||
fontSize: "14px", | |||||
fontWeight: "bold", | |||||
}, | |||||
}, | }, | ||||
labels: { | labels: { | ||||
maxWidth: 200, | maxWidth: 200, | ||||
@@ -481,7 +485,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
}, | }, | ||||
}, | }, | ||||
title: { | title: { | ||||
text: "Project Resource Consumption Percentage", | |||||
text: t("Project Resource Consumption Percentage"), | |||||
align: "center", | align: "center", | ||||
}, | }, | ||||
grid: { | grid: { | ||||
@@ -507,7 +511,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
const percentageArray = []; | const percentageArray = []; | ||||
for (let i = 0; i <= selectedRowsData.length; i++) { | for (let i = 0; i <= selectedRowsData.length; i++) { | ||||
if (i === selectedRowsData.length && i > 0) { | if (i === selectedRowsData.length && i > 0) { | ||||
projectArray.push("Remained"); | |||||
projectArray.push(t("Remained")); | |||||
} else if (selectedRowsData.length > 0) { | } else if (selectedRowsData.length > 0) { | ||||
projectArray.push(selectedRowsData[i].projectName); | projectArray.push(selectedRowsData[i].projectName); | ||||
totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour); | totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour); | ||||
@@ -541,7 +545,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
setTotalSpentPercentage( | setTotalSpentPercentage( | ||||
((totalSpent / totalBudgetManhour) * 100).toFixed(1), | ((totalSpent / totalBudgetManhour) * 100).toFixed(1), | ||||
); | ); | ||||
if (projectArray.length > 0 && projectArray.includes("Remained")) { | |||||
if (projectArray.length > 0 && projectArray.includes(t("Remained"))) { | |||||
const nonLastRecordColors = pieChartColorArray; | const nonLastRecordColors = pieChartColorArray; | ||||
setColorArray([ | setColorArray([ | ||||
...nonLastRecordColors.slice(0, projectArray.length - 1), | ...nonLastRecordColors.slice(0, projectArray.length - 1), | ||||
@@ -563,30 +567,30 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
<div style={{ display: "inline-block", width: "70%" }}> | <div style={{ display: "inline-block", width: "70%" }}> | ||||
<Grid item xs={12} md={12} lg={12}> | <Grid item xs={12} md={12} lg={12}> | ||||
<Card> | <Card> | ||||
<CardHeader className="text-slate-500" title="Project Resource Consumption" /> | |||||
<CardHeader className="text-slate-500" title= {t("Project Resource Consumption")} /> | |||||
<div style={{ display: "inline-block", width: "99%" }}> | <div style={{ display: "inline-block", width: "99%" }}> | ||||
<div className="ml-6 text-sm"> | <div className="ml-6 text-sm"> | ||||
<b> | <b> | ||||
Sorting: | |||||
{t("Sorting")}: | |||||
</b> | </b> | ||||
</div> | </div> | ||||
<div className="ml-6 mb-2"> | <div className="ml-6 mb-2"> | ||||
<button onClick={() => {setTableSorting('PercentageASC')}} | <button onClick={() => {setTableSorting('PercentageASC')}} | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | ||||
> | > | ||||
{`Percentage (Ascending Order)`} | |||||
{t(`Percentage (Ascending Order)`)} | |||||
</button> | </button> | ||||
<button | <button | ||||
onClick={() => {setTableSorting('PercentageDESC')}} | onClick={() => {setTableSorting('PercentageDESC')}} | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | ||||
> | > | ||||
{`Percentage (Descending Order)`} | |||||
{t(`Percentage (Descending Order)`)} | |||||
</button> | </button> | ||||
<button | <button | ||||
onClick={() => {setTableSorting('ProjectName')}} | onClick={() => {setTableSorting('ProjectName')}} | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | ||||
> | > | ||||
Project Name | |||||
{t("Project Name")} | |||||
</button> | </button> | ||||
</div> | </div> | ||||
<ReactApexChart | <ReactApexChart | ||||
@@ -609,7 +613,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
<Card className="mt-2"> | <Card className="mt-2"> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Resource Consumption and Coming Milestone" | |||||
title= {t("Resource Consumption and Coming Milestones")} | |||||
/> | /> | ||||
<div | <div | ||||
style={{ display: "inline-block", width: "99%", marginLeft: 10 }} | style={{ display: "inline-block", width: "99%", marginLeft: 10 }} | ||||
@@ -639,14 +643,14 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
<Card style={{ marginLeft: 15, marginRight: 20, height:"100%"}}> | <Card style={{ marginLeft: 15, marginRight: 20, height:"100%"}}> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Overall Progress per Project" | |||||
title= {t("Overall Progress per Project")} | |||||
/> | /> | ||||
{percentageArray.length === 0 && ( | {percentageArray.length === 0 && ( | ||||
<div | <div | ||||
className="mt-40 mb-10 ml-5 mr-5 text-lg font-medium text-center" | className="mt-40 mb-10 ml-5 mr-5 text-lg font-medium text-center" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
Please select the project you want to check. | |||||
{t("Please select the project you want to check.")} | |||||
</div> | </div> | ||||
)} | )} | ||||
{percentageArray.length > 0 && ( | {percentageArray.length > 0 && ( | ||||
@@ -666,7 +670,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
className="mt-5 text-lg font-medium" | className="mt-5 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>Project Budget Manhour</span> | |||||
<span style={{ marginLeft: "5%" }}>{t("Project Budget Manhours")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
@@ -681,7 +685,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>Actual Manhour Spent</span> | |||||
<span style={{ marginLeft: "5%" }}>{t("Actual Manhours Spent")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
@@ -696,7 +700,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>Remained Manhour</span> | |||||
<span style={{ marginLeft: "5%" }}>{t("Remained Manhours")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
@@ -711,7 +715,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>Last Update</span> | |||||
<span style={{ marginLeft: "5%" }}>{t("Last Update")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 mb-5 text-2xl font-extrabold" | className="mt-2 mb-5 text-2xl font-extrabold" | ||||
@@ -10,6 +10,7 @@ import { fetchAllClientSubsidiaryProjects} from "@/app/api/clientprojects/action | |||||
import VisibilityIcon from '@mui/icons-material/Visibility'; | import VisibilityIcon from '@mui/icons-material/Visibility'; | ||||
import { useRouter, useSearchParams } from "next/navigation"; | import { useRouter, useSearchParams } from "next/navigation"; | ||||
import ProgressByClient from "@/components/ProgressByClient"; | import ProgressByClient from "@/components/ProgressByClient"; | ||||
import Typography from "@mui/material/Typography"; | |||||
interface Props { | interface Props { | ||||
clientProjects: ClientProjectResult[]; | clientProjects: ClientProjectResult[]; | ||||
@@ -19,7 +20,7 @@ type SearchParamNames = keyof SearchQuery; | |||||
const ProgressByClientSearch: React.FC<Props> = ({ clientProjects }) => { | const ProgressByClientSearch: React.FC<Props> = ({ clientProjects }) => { | ||||
const router = useRouter(); | const router = useRouter(); | ||||
const { t } = useTranslation("projects"); | |||||
const { t } = useTranslation("dashboard"); | |||||
const searchParams = useSearchParams() | const searchParams = useSearchParams() | ||||
// If project searching is done on the server-side, then no need for this. | // If project searching is done on the server-side, then no need for this. | ||||
const [filteredProjects, setFilteredProjects] = useState(clientProjects); | const [filteredProjects, setFilteredProjects] = useState(clientProjects); | ||||
@@ -27,8 +28,8 @@ const ProgressByClientSearch: React.FC<Props> = ({ clientProjects }) => { | |||||
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | ||||
() => [ | () => [ | ||||
{ label: "Client Code", paramName: "customerCode", type: "text" }, | |||||
{ label: "Client Name", paramName: "customerName", type: "text" }, | |||||
{ label: t("Client Code"), paramName: "customerCode", type: "text" }, | |||||
{ label: t("Client Name"), paramName: "customerName", type: "text" }, | |||||
], | ], | ||||
[t], | [t], | ||||
); | ); | ||||
@@ -62,7 +63,7 @@ const ProgressByClientSearch: React.FC<Props> = ({ clientProjects }) => { | |||||
{ name: "customerCode", label: t("Client Code") }, | { name: "customerCode", label: t("Client Code") }, | ||||
{ name: "customerName", label: t("Client Name") }, | { name: "customerName", label: t("Client Name") }, | ||||
{ name: "subsidiaryCode", label: t("Subsidiary Code") }, | { name: "subsidiaryCode", label: t("Subsidiary Code") }, | ||||
{ name: "subsidiaryName", label: t("Subisdiary") }, | |||||
{ name: "subsidiaryName", label: t("Subsidiary") }, | |||||
{ name: "projectNo", label: t("No. of Projects") }, | { name: "projectNo", label: t("No. of Projects") }, | ||||
], | ], | ||||
[onTaskClick, t], | [onTaskClick, t], | ||||
@@ -71,6 +72,9 @@ const ProgressByClientSearch: React.FC<Props> = ({ clientProjects }) => { | |||||
return ( | return ( | ||||
<> | <> | ||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
{t("Project Status by Client")} | |||||
</Typography> | |||||
<SearchBox | <SearchBox | ||||
criteria={searchCriteria} | criteria={searchCriteria} | ||||
onSearch={(query) => { | onSearch={(query) => { | ||||
@@ -275,31 +275,31 @@ const ProgressByTeam: React.FC = () => { | |||||
{ | { | ||||
id: "projectCode", | id: "projectCode", | ||||
field: "projectCode", | field: "projectCode", | ||||
headerName: "Project No", | |||||
headerName: t("Project Code"), | |||||
minWidth:100 | minWidth:100 | ||||
}, | }, | ||||
{ | { | ||||
id: "projectName", | id: "projectName", | ||||
field: "projectName", | field: "projectName", | ||||
headerName: "Project", | |||||
headerName: t("Project Name"), | |||||
minWidth:300 | minWidth:300 | ||||
}, | }, | ||||
{ | { | ||||
id: "team", | id: "team", | ||||
field: "team", | field: "team", | ||||
headerName: "Team", | |||||
headerName: t("Team"), | |||||
minWidth:50 | minWidth:50 | ||||
}, | }, | ||||
{ | { | ||||
id: "teamLead", | id: "teamLead", | ||||
field: "teamLead", | field: "teamLead", | ||||
headerName: "Team Leader", | |||||
headerName: t("Team Leader"), | |||||
minWidth: 70 | minWidth: 70 | ||||
}, | }, | ||||
{ | { | ||||
id: "expectedStage", | id: "expectedStage", | ||||
field: "expectedStage", | field: "expectedStage", | ||||
headerName: "Expected Stage", | |||||
headerName: t("Expected Stage"), | |||||
minWidth: 300, | minWidth: 300, | ||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.expectedStage != null){ | if (params.row.expectedStage != null){ | ||||
@@ -320,7 +320,7 @@ const ProgressByTeam: React.FC = () => { | |||||
{ | { | ||||
id: "budgetedManhour", | id: "budgetedManhour", | ||||
field: "budgetedManhour", | field: "budgetedManhour", | ||||
headerName: "Budgeted Manhour", | |||||
headerName: t("Budgeted Manhours"), | |||||
minWidth: 70, | minWidth: 70, | ||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
return <span>{params.row.budgetedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>; | return <span>{params.row.budgetedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>; | ||||
@@ -329,7 +329,7 @@ const ProgressByTeam: React.FC = () => { | |||||
{ | { | ||||
id: "spentManhour", | id: "spentManhour", | ||||
field: "spentManhour", | field: "spentManhour", | ||||
headerName: "Spent Manhour", | |||||
headerName: t("Spent Manhours"), | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | ||||
return ( | return ( | ||||
@@ -344,7 +344,7 @@ const ProgressByTeam: React.FC = () => { | |||||
{ | { | ||||
id: "remainedManhour", | id: "remainedManhour", | ||||
field: "remainedManhour", | field: "remainedManhour", | ||||
headerName: "Remained Manhour", | |||||
headerName: t("Remained Manhours"), | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | ||||
return ( | return ( | ||||
@@ -359,13 +359,13 @@ const ProgressByTeam: React.FC = () => { | |||||
{ | { | ||||
id: "comingPaymentMilestone", | id: "comingPaymentMilestone", | ||||
field: "comingPaymentMilestone", | field: "comingPaymentMilestone", | ||||
headerName: "Coming Payment Milestone", | |||||
headerName: t("Coming Payment Milestones"), | |||||
minWidth: 100 | minWidth: 100 | ||||
}, | }, | ||||
{ | { | ||||
id: "alert", | id: "alert", | ||||
field: "alert", | field: "alert", | ||||
headerName: "Alert", | |||||
headerName: t("Alert"), | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.alert === 1) { | if (params.row.alert === 1) { | ||||
return ( | return ( | ||||
@@ -447,7 +447,7 @@ const ProgressByTeam: React.FC = () => { | |||||
total: { | total: { | ||||
show: true, | show: true, | ||||
showAlways: true, | showAlways: true, | ||||
label: "Spent", | |||||
label: t("Spent"), | |||||
fontFamily: "sans-serif", | fontFamily: "sans-serif", | ||||
formatter: function (val) { | formatter: function (val) { | ||||
return totalSpentPercentage + "%"; | return totalSpentPercentage + "%"; | ||||
@@ -495,9 +495,9 @@ const ProgressByTeam: React.FC = () => { | |||||
<div style="width: auto;"> | <div style="width: auto;"> | ||||
<span style="font-weight: bold;">${projectCode} - ${projectName}</span> | <span style="font-weight: bold;">${projectCode} - ${projectName}</span> | ||||
<br> | <br> | ||||
Budget Manhours: ${budgetManhours} hours | |||||
${t("Budget Manhours")}: ${budgetManhours} hours | |||||
<br> | <br> | ||||
Spent Manhours: ${spentManhours} hours | |||||
${t("Spent Manhours")}: ${spentManhours} hours | |||||
<br> | <br> | ||||
Percentage: ${value}% | Percentage: ${value}% | ||||
</div> | </div> | ||||
@@ -507,7 +507,7 @@ const ProgressByTeam: React.FC = () => { | |||||
}, | }, | ||||
}, | }, | ||||
series: [{ | series: [{ | ||||
name: "Project Resource Consumption Percentage", | |||||
name: t("Project Resource Consumption Percentage"), | |||||
data: currentPagePercentage, | data: currentPagePercentage, | ||||
},], | },], | ||||
colors: currentPageColor, | colors: currentPageColor, | ||||
@@ -530,7 +530,7 @@ const ProgressByTeam: React.FC = () => { | |||||
}, | }, | ||||
yaxis: { | yaxis: { | ||||
title: { | title: { | ||||
text: "Projects", | |||||
text: t("Projects"), | |||||
}, | }, | ||||
labels: { | labels: { | ||||
maxWidth: 200, | maxWidth: 200, | ||||
@@ -540,7 +540,7 @@ const ProgressByTeam: React.FC = () => { | |||||
}, | }, | ||||
}, | }, | ||||
title: { | title: { | ||||
text: "Project Resource Consumption Percentage", | |||||
text: t("Project Resource Consumption Percentage"), | |||||
align: "center", | align: "center", | ||||
}, | }, | ||||
grid: { | grid: { | ||||
@@ -566,7 +566,7 @@ const ProgressByTeam: React.FC = () => { | |||||
const percentageArray = []; | const percentageArray = []; | ||||
for (let i = 0; i <= selectedRowsData.length; i++) { | for (let i = 0; i <= selectedRowsData.length; i++) { | ||||
if (i === selectedRowsData.length && i > 0) { | if (i === selectedRowsData.length && i > 0) { | ||||
projectArray.push("Remained"); | |||||
projectArray.push(t("Remained")); | |||||
} else if (selectedRowsData.length > 0) { | } else if (selectedRowsData.length > 0) { | ||||
projectArray.push(selectedRowsData[i].projectName); | projectArray.push(selectedRowsData[i].projectName); | ||||
totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour); | totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour); | ||||
@@ -600,7 +600,7 @@ const ProgressByTeam: React.FC = () => { | |||||
setTotalSpentPercentage( | setTotalSpentPercentage( | ||||
((totalSpent / totalBudgetManhour) * 100).toFixed(1), | ((totalSpent / totalBudgetManhour) * 100).toFixed(1), | ||||
); | ); | ||||
if (projectArray.length > 0 && projectArray.includes("Remained")) { | |||||
if (projectArray.length > 0 && projectArray.includes(t("Remained"))) { | |||||
const nonLastRecordColors = pieChartColorArray; | const nonLastRecordColors = pieChartColorArray; | ||||
setColorArray([ | setColorArray([ | ||||
...nonLastRecordColors.slice(0, projectArray.length - 1), | ...nonLastRecordColors.slice(0, projectArray.length - 1), | ||||
@@ -654,30 +654,30 @@ const ProgressByTeam: React.FC = () => { | |||||
<div style={{ display: "inline-block", width: "70%" }}> | <div style={{ display: "inline-block", width: "70%" }}> | ||||
<Grid item xs={12} md={12} lg={12}> | <Grid item xs={12} md={12} lg={12}> | ||||
<Card> | <Card> | ||||
<CardHeader className="text-slate-500" title="Project Resource Consumption" /> | |||||
<CardHeader className="text-slate-500" title= {t("Project Resource Consumption")} /> | |||||
<div style={{ display: "inline-block", width: "99%" }}> | <div style={{ display: "inline-block", width: "99%" }}> | ||||
<div className="ml-6 text-sm"> | <div className="ml-6 text-sm"> | ||||
<b> | <b> | ||||
Sorting: | |||||
{t("Sorting")}: | |||||
</b> | </b> | ||||
</div> | </div> | ||||
<div className="ml-6 mb-2"> | <div className="ml-6 mb-2"> | ||||
<button onClick={() => {setTableSorting('PercentageASC')}} | <button onClick={() => {setTableSorting('PercentageASC')}} | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | ||||
> | > | ||||
{`Percentage (Ascending Order)`} | |||||
{t("Percentage (Ascending Order)")} | |||||
</button> | </button> | ||||
<button | <button | ||||
onClick={() => {setTableSorting('PercentageDESC')}} | onClick={() => {setTableSorting('PercentageDESC')}} | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | ||||
> | > | ||||
{`Percentage (Descending Order)`} | |||||
{t("Percentage (Descending Order)")} | |||||
</button> | </button> | ||||
<button | <button | ||||
onClick={() => {setTableSorting('ProjectName')}} | onClick={() => {setTableSorting('ProjectName')}} | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | ||||
> | > | ||||
Project Name | |||||
{t("Project Name")} | |||||
</button> | </button> | ||||
</div> | </div> | ||||
<ReactApexChart | <ReactApexChart | ||||
@@ -689,25 +689,25 @@ const ProgressByTeam: React.FC = () => { | |||||
<div className="float-right mr-4 mb-10"> | <div className="float-right mr-4 mb-10"> | ||||
{currentPage === 1 && ( | {currentPage === 1 && ( | ||||
<button className="bg-lime-600 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-l"> | <button className="bg-lime-600 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-l"> | ||||
Pervious | |||||
{t("Previous")} | |||||
</button> | </button> | ||||
)} | )} | ||||
{currentPage !== 1 && ( | {currentPage !== 1 && ( | ||||
<button onClick={handlePrevPage} className="bg-lime-600 hover:bg-lime-700 text-white font-bold py-2 px-4 outline-none rounded-l"> | <button onClick={handlePrevPage} className="bg-lime-600 hover:bg-lime-700 text-white font-bold py-2 px-4 outline-none rounded-l"> | ||||
Previous | |||||
{t("Previous")} | |||||
</button> | </button> | ||||
)} | )} | ||||
{endIndex >= chartManhourConsumptionPercentage.length && ( | {endIndex >= chartManhourConsumptionPercentage.length && ( | ||||
<button className="bg-lime-600 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-r mr-2"> | <button className="bg-lime-600 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-r mr-2"> | ||||
Next | |||||
{t("Next")} | |||||
</button> | </button> | ||||
)} | )} | ||||
{endIndex < chartManhourConsumptionPercentage.length && ( | {endIndex < chartManhourConsumptionPercentage.length && ( | ||||
<button onClick={handleNextPage} className="bg-lime-600 hover:bg-lime-700 text-white font-bold py-2 px-4 outline-none rounded-r mr-2"> | <button onClick={handleNextPage} className="bg-lime-600 hover:bg-lime-700 text-white font-bold py-2 px-4 outline-none rounded-r mr-2"> | ||||
Next | |||||
{t("Next")} | |||||
</button> | </button> | ||||
)} | )} | ||||
Page | |||||
{t("Page")} | |||||
{chartManhourConsumptionPercentage.length === 0 && ( | {chartManhourConsumptionPercentage.length === 0 && ( | ||||
0 | 0 | ||||
)} | )} | ||||
@@ -732,7 +732,7 @@ const ProgressByTeam: React.FC = () => { | |||||
<Card className="mt-2"> | <Card className="mt-2"> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Resource Consumption and Coming Milestone" | |||||
title= {t("Resource Consumption and Coming Milestones")} | |||||
/> | /> | ||||
<div | <div | ||||
style={{ display: "inline-block", width: "99%", marginLeft: 10 }} | style={{ display: "inline-block", width: "99%", marginLeft: 10 }} | ||||
@@ -762,14 +762,14 @@ const ProgressByTeam: React.FC = () => { | |||||
<Card style={{ marginLeft: 15, marginRight: 20, height:"100%"}}> | <Card style={{ marginLeft: 15, marginRight: 20, height:"100%"}}> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Overall Progress per Project" | |||||
title= {t("Overall Progress per Project")} | |||||
/> | /> | ||||
{percentageArray.length === 0 && ( | {percentageArray.length === 0 && ( | ||||
<div | <div | ||||
className="mt-40 mb-10 ml-5 mr-5 text-lg font-medium text-center" | className="mt-40 mb-10 ml-5 mr-5 text-lg font-medium text-center" | ||||
style={{ color: "#898d8d"}} | style={{ color: "#898d8d"}} | ||||
> | > | ||||
Please select the project you want to check. | |||||
{t("Please select the project you want to check.")} | |||||
</div> | </div> | ||||
)} | )} | ||||
{percentageArray.length > 0 && ( | {percentageArray.length > 0 && ( | ||||
@@ -789,7 +789,7 @@ const ProgressByTeam: React.FC = () => { | |||||
className="mt-5 text-lg font-medium" | className="mt-5 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>Project Budget Manhour</span> | |||||
<span style={{ marginLeft: "5%" }}>{t("Project Budget Manhours")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
@@ -804,7 +804,7 @@ const ProgressByTeam: React.FC = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>Actual Manhour Spent</span> | |||||
<span style={{ marginLeft: "5%" }}>{t("Actual Manhours Spent")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
@@ -819,7 +819,7 @@ const ProgressByTeam: React.FC = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>Remained Manhour</span> | |||||
<span style={{ marginLeft: "5%" }}>{t("Remained Manhours")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
@@ -834,7 +834,7 @@ const ProgressByTeam: React.FC = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>Last Update</span> | |||||
<span style={{ marginLeft: "5%" }}>{t("Last Update")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 mb-5 text-2xl font-extrabold" | className="mt-2 mb-5 text-2xl font-extrabold" | ||||
@@ -8,6 +8,7 @@ import SearchResults, { Column } from "../SearchResults"; | |||||
import { TeamProjectResult } from "@/app/api/teamprojects"; | import { TeamProjectResult } from "@/app/api/teamprojects"; | ||||
import VisibilityIcon from '@mui/icons-material/Visibility'; | import VisibilityIcon from '@mui/icons-material/Visibility'; | ||||
import { useRouter, useSearchParams } from "next/navigation"; | import { useRouter, useSearchParams } from "next/navigation"; | ||||
import Typography from "@mui/material/Typography"; | |||||
interface Props { | interface Props { | ||||
projects: TeamProjectResult[]; | projects: TeamProjectResult[]; | ||||
@@ -16,15 +17,15 @@ type SearchQuery = Partial<Omit<TeamProjectResult, "id">>; | |||||
type SearchParamNames = keyof SearchQuery; | type SearchParamNames = keyof SearchQuery; | ||||
const ProgressByClientSearch: React.FC<Props> = ({ projects }) => { | const ProgressByClientSearch: React.FC<Props> = ({ projects }) => { | ||||
const { t } = useTranslation("projects"); | |||||
const { t } = useTranslation("dashboard"); | |||||
const router = useRouter(); | const router = useRouter(); | ||||
// If project searching is done on the server-side, then no need for this. | // If project searching is done on the server-side, then no need for this. | ||||
const [filteredProjects, setFilteredProjects] = useState(projects); | const [filteredProjects, setFilteredProjects] = useState(projects); | ||||
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | ||||
() => [ | () => [ | ||||
{ label: "Team Code", paramName: "teamCode", type: "text" }, | |||||
{ label: "Team Name", paramName: "teamName", type: "text" }, | |||||
{ label: t("Team Code"), paramName: "teamCode", type: "text" }, | |||||
{ label: t("Team Name"), paramName: "teamName", type: "text" }, | |||||
], | ], | ||||
[t], | [t], | ||||
); | ); | ||||
@@ -58,6 +59,9 @@ const ProgressByClientSearch: React.FC<Props> = ({ projects }) => { | |||||
return ( | return ( | ||||
<> | <> | ||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
{t("Project Status by Team")} | |||||
</Typography> | |||||
<SearchBox | <SearchBox | ||||
criteria={searchCriteria} | criteria={searchCriteria} | ||||
onSearch={(query) => { | onSearch={(query) => { | ||||
@@ -24,6 +24,7 @@ import { Input, Label } from "reactstrap"; | |||||
import { CashFlow } from "@/app/api/cashflow"; | import { CashFlow } from "@/app/api/cashflow"; | ||||
import dayjs from 'dayjs'; | import dayjs from 'dayjs'; | ||||
import ProjectTotalFee from "../CreateInvoice_forGen/ProjectTotalFee"; | import ProjectTotalFee from "../CreateInvoice_forGen/ProjectTotalFee"; | ||||
import Typography from "@mui/material/Typography"; | |||||
interface Props { | interface Props { | ||||
projects: CashFlow[]; | projects: CashFlow[]; | ||||
@@ -32,7 +33,7 @@ type SearchQuery = Partial<Omit<CashFlow, "id">>; | |||||
type SearchParamNames = keyof SearchQuery; | type SearchParamNames = keyof SearchQuery; | ||||
const ProjectCashFlow: React.FC = () => { | const ProjectCashFlow: React.FC = () => { | ||||
const { t } = useTranslation("projects"); | |||||
const { t } = useTranslation("dashboard"); | |||||
const todayDate = new Date(); | const todayDate = new Date(); | ||||
const [selectionModel, setSelectionModel]: any[] = React.useState([]); | const [selectionModel, setSelectionModel]: any[] = React.useState([]); | ||||
const [projectData, setProjectData]: any[] = React.useState([]); | const [projectData, setProjectData]: any[] = React.useState([]); | ||||
@@ -226,49 +227,49 @@ const ProjectCashFlow: React.FC = () => { | |||||
{ | { | ||||
id: "projectCode", | id: "projectCode", | ||||
field: "projectCode", | field: "projectCode", | ||||
headerName: "Project Code", | |||||
headerName: t("Project Code"), | |||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
{ | { | ||||
id: "projectName", | id: "projectName", | ||||
field: "projectName", | field: "projectName", | ||||
headerName: "Project Name", | |||||
headerName: t("Project Name"), | |||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
{ | { | ||||
id: "team", | id: "team", | ||||
field: "team", | field: "team", | ||||
headerName: "Team", | |||||
headerName: t("Team"), | |||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
{ | { | ||||
id: "teamLead", | id: "teamLead", | ||||
field: "teamLead", | field: "teamLead", | ||||
headerName: "Team Leader", | |||||
headerName: t("Team Leader"), | |||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
{ | { | ||||
id: "startDate", | id: "startDate", | ||||
field: "startDate", | field: "startDate", | ||||
headerName: "Start Date", | |||||
headerName: t("Start Date"), | |||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
{ | { | ||||
id: "targetEndDate", | id: "targetEndDate", | ||||
field: "targetEndDate", | field: "targetEndDate", | ||||
headerName: "Target End Date", | |||||
headerName: t("Target End Date"), | |||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
{ | { | ||||
id: "client", | id: "client", | ||||
field: "client", | field: "client", | ||||
headerName: "Client", | |||||
headerName: t("Client"), | |||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
{ | { | ||||
id: "subsidiary", | id: "subsidiary", | ||||
field: "subsidiary", | field: "subsidiary", | ||||
headerName: "Subsidiary", | |||||
headerName: t("Subsidiary"), | |||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
]; | ]; | ||||
@@ -277,13 +278,13 @@ const ProjectCashFlow: React.FC = () => { | |||||
{ | { | ||||
id: "date", | id: "date", | ||||
field: "date", | field: "date", | ||||
headerName: "Date", | |||||
headerName: t("Date"), | |||||
flex: 0.5, | flex: 0.5, | ||||
}, | }, | ||||
{ | { | ||||
id: "expenditure", | id: "expenditure", | ||||
field: "expenditure", | field: "expenditure", | ||||
headerName: "Expenditure (HKD)", | |||||
headerName: t("Expenditure (HKD)"), | |||||
flex: 0.6, | flex: 0.6, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -294,7 +295,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
{ | { | ||||
id: "income", | id: "income", | ||||
field: "income", | field: "income", | ||||
headerName: "Income (HKD)", | |||||
headerName: t("Income (HKD)"), | |||||
flex: 0.6, | flex: 0.6, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -305,7 +306,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
{ | { | ||||
id: "balance", | id: "balance", | ||||
field: "balance", | field: "balance", | ||||
headerName: "Cash Flow Balance (HKD)", | |||||
headerName: t("Cash Flow Balance (HKD)"), | |||||
flex: 0.6, | flex: 0.6, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
if (params.row.balance < 0) { | if (params.row.balance < 0) { | ||||
@@ -322,7 +323,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
{ | { | ||||
id: "remarks", | id: "remarks", | ||||
field: "remarks", | field: "remarks", | ||||
headerName: "Remarks", | |||||
headerName: t("Remarks"), | |||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
]; | ]; | ||||
@@ -353,24 +354,27 @@ const ProjectCashFlow: React.FC = () => { | |||||
}, | }, | ||||
xaxis: { | xaxis: { | ||||
categories: [ | categories: [ | ||||
"JAN", | |||||
"FEB", | |||||
"MAR", | |||||
"APR", | |||||
"MAY", | |||||
"JUN", | |||||
"JUL", | |||||
"AUG", | |||||
"SEP", | |||||
"OCT", | |||||
"NOV", | |||||
"DEC", | |||||
t("JAN"), | |||||
t("FEB"), | |||||
t("MAR"), | |||||
t("APR"), | |||||
t("MAY"), | |||||
t("JUN"), | |||||
t("JUL"), | |||||
t("AUG"), | |||||
t("SEP"), | |||||
t("OCT"), | |||||
t("NOV"), | |||||
t("DEC"), | |||||
], | ], | ||||
}, | }, | ||||
yaxis: [ | yaxis: [ | ||||
{ | { | ||||
title: { | title: { | ||||
text: "Monthly Income and Expenditure(HKD)", | |||||
text: t("Monthly Income and Expenditure (HKD)"), | |||||
style: { | |||||
fontSize: "13px", | |||||
} | |||||
}, | }, | ||||
min: 0, | min: 0, | ||||
max: monthlyChartLeftMax, | max: monthlyChartLeftMax, | ||||
@@ -395,7 +399,10 @@ const ProjectCashFlow: React.FC = () => { | |||||
seriesName: "Cumulative Income", | seriesName: "Cumulative Income", | ||||
opposite: true, | opposite: true, | ||||
title: { | title: { | ||||
text: "Cumulative Income and Expenditure(HKD)", | |||||
text: t("Cumulative Income and Expenditure (HKD)"), | |||||
style: { | |||||
fontSize: "13px", | |||||
} | |||||
}, | }, | ||||
min: 0, | min: 0, | ||||
max: monthlyChartRightMax, | max: monthlyChartRightMax, | ||||
@@ -425,25 +432,25 @@ const ProjectCashFlow: React.FC = () => { | |||||
annotations: {}, | annotations: {}, | ||||
series: [ | series: [ | ||||
{ | { | ||||
name: "Monthly Income", | |||||
name: t("Monthly Income"), | |||||
type: "column", | type: "column", | ||||
color: "#ffde91", | color: "#ffde91", | ||||
data: monthlyIncomeList, | data: monthlyIncomeList, | ||||
}, | }, | ||||
{ | { | ||||
name: "Monthly Expenditure", | |||||
name: t("Monthly Expenditure"), | |||||
type: "column", | type: "column", | ||||
color: "#82b59a", | color: "#82b59a", | ||||
data: monthlyExpenditureList, | data: monthlyExpenditureList, | ||||
}, | }, | ||||
{ | { | ||||
name: "Cumulative Income", | |||||
name: t("Cumulative Income"), | |||||
type: "line", | type: "line", | ||||
color: "#EE6D7A", | color: "#EE6D7A", | ||||
data: monthlyCumulativeIncomeList, | data: monthlyCumulativeIncomeList, | ||||
}, | }, | ||||
{ | { | ||||
name: "Cumulative Expenditure", | |||||
name: t("Cumulative Expenditure"), | |||||
type: "line", | type: "line", | ||||
color: "#7cd3f2", | color: "#7cd3f2", | ||||
data: monthlyCumulativeExpenditureList, | data: monthlyCumulativeExpenditureList, | ||||
@@ -477,24 +484,27 @@ const ProjectCashFlow: React.FC = () => { | |||||
}, | }, | ||||
xaxis: { | xaxis: { | ||||
categories: [ | categories: [ | ||||
"JAN", | |||||
"FEB", | |||||
"MAR", | |||||
"APR", | |||||
"MAY", | |||||
"JUN", | |||||
"JUL", | |||||
"AUG", | |||||
"SEP", | |||||
"OCT", | |||||
"NOV", | |||||
"DEC", | |||||
t("JAN"), | |||||
t("FEB"), | |||||
t("MAR"), | |||||
t("APR"), | |||||
t("MAY"), | |||||
t("JUN"), | |||||
t("JUL"), | |||||
t("AUG"), | |||||
t("SEP"), | |||||
t("OCT"), | |||||
t("NOV"), | |||||
t("DEC"), | |||||
], | ], | ||||
}, | }, | ||||
yaxis: [ | yaxis: [ | ||||
{ | { | ||||
title: { | title: { | ||||
text: "Anticipate Monthly Income and Expenditure(HKD)", | |||||
text: t("Anticipate Monthly Income and Expenditure") + t("HKD"), | |||||
style: { | |||||
fontSize: "13px", | |||||
} | |||||
}, | }, | ||||
min: 0, | min: 0, | ||||
max: monthlyAnticipateLeftMax, | max: monthlyAnticipateLeftMax, | ||||
@@ -513,13 +523,13 @@ const ProjectCashFlow: React.FC = () => { | |||||
annotations: {}, | annotations: {}, | ||||
series: [ | series: [ | ||||
{ | { | ||||
name: "Monthly Income", | |||||
name: t("Monthly Income"), | |||||
type: "column", | type: "column", | ||||
color: "#f1c48a", | color: "#f1c48a", | ||||
data: monthlyAnticipateIncomeList, | data: monthlyAnticipateIncomeList, | ||||
}, | }, | ||||
{ | { | ||||
name: "Monthly Expenditure", | |||||
name: t("Monthly Expenditure"), | |||||
type: "column", | type: "column", | ||||
color: "#89d7f3", | color: "#89d7f3", | ||||
data: monthlyAnticipateExpenditureList, | data: monthlyAnticipateExpenditureList, | ||||
@@ -563,7 +573,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
show: true, | show: true, | ||||
color: "#20E647", | color: "#20E647", | ||||
fontSize: "0.9em", | fontSize: "0.9em", | ||||
label: 'Receivable / Invoiced', | |||||
label: t('Receivable') + " / " + t('Invoiced'), | |||||
formatter: function (w:any) { | formatter: function (w:any) { | ||||
return receivedPercentage + "% / " + invoicedPercentage + "%" | return receivedPercentage + "% / " + invoicedPercentage + "%" | ||||
}, | }, | ||||
@@ -633,7 +643,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
stroke: { | stroke: { | ||||
lineCap: "round", | lineCap: "round", | ||||
}, | }, | ||||
labels: ["Expenditure"], | |||||
labels: [t("Expenditure")], | |||||
}; | }; | ||||
const rows = [ | const rows = [ | ||||
@@ -725,11 +735,11 @@ const ProjectCashFlow: React.FC = () => { | |||||
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | ||||
() => [ | () => [ | ||||
{ label: "Project Code", paramName: "projectCode", type: "text" }, | |||||
{ label: "Project Name", paramName: "projectName", type: "text" }, | |||||
{ label: t("Project Code"), paramName: "projectCode", type: "text" }, | |||||
{ label: t("Project Name"), paramName: "projectName", type: "text" }, | |||||
{ | { | ||||
label: "Start Date From", | |||||
label2: "Start Date To", | |||||
label: t("Start Date From"), | |||||
label2: t("Start Date To"), | |||||
paramName: "startDateFrom", | paramName: "startDateFrom", | ||||
type: "dateRange", | type: "dateRange", | ||||
}, | }, | ||||
@@ -755,6 +765,9 @@ const ProjectCashFlow: React.FC = () => { | |||||
{/* <Suspense fallback={<ProgressCashFlowSearch.Loading />}> | {/* <Suspense fallback={<ProgressCashFlowSearch.Loading />}> | ||||
<ProgressCashFlowSearch /> | <ProgressCashFlowSearch /> | ||||
</Suspense> */} | </Suspense> */} | ||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
{t('Project Cash Flow')} | |||||
</Typography> | |||||
<SearchBox | <SearchBox | ||||
criteria={searchCriteria} | criteria={searchCriteria} | ||||
onSearch={(query) => { | onSearch={(query) => { | ||||
@@ -786,12 +799,12 @@ const ProjectCashFlow: React.FC = () => { | |||||
<Card> | <Card> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Project Cash Flow by Month" | |||||
title= {t("Project Cash Flow by Month")} | |||||
/> | /> | ||||
<div style={{ display: "inline-block", width: "99%" }}> | <div style={{ display: "inline-block", width: "99%" }}> | ||||
<div className="inline-block"> | <div className="inline-block"> | ||||
<Label className="text-slate-500 font-medium ml-6"> | <Label className="text-slate-500 font-medium ml-6"> | ||||
Period: | |||||
{t("Year")}: | |||||
</Label> | </Label> | ||||
<Input | <Input | ||||
id={"cashFlowYear"} | id={"cashFlowYear"} | ||||
@@ -839,7 +852,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
<Card> | <Card> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Accounts Receivable (HKD)" | |||||
title= {t("Accounts Receivable (HKD)")} | |||||
/> | /> | ||||
<div style={{ display: "inline-block", width: "99%" }}> | <div style={{ display: "inline-block", width: "99%" }}> | ||||
<ReactApexChart | <ReactApexChart | ||||
@@ -853,7 +866,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
className="text-sm font-medium ml-5 mt-2" | className="text-sm font-medium ml-5 mt-2" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
Total Project Fee | |||||
{t("Total Project Fee")} | |||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5" | className="text-lg font-medium ml-5" | ||||
@@ -866,7 +879,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
className="text-sm font-medium ml-5 mt-2" | className="text-sm font-medium ml-5 mt-2" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
Total Invoiced Amount | |||||
{t("Total Invoiced Amount")} | |||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5" | className="text-lg font-medium ml-5" | ||||
@@ -879,7 +892,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
className="text-sm font-medium ml-5" | className="text-sm font-medium ml-5" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
Total Received Amount | |||||
{t("Total Received Amount")} | |||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5" | className="text-lg font-medium ml-5" | ||||
@@ -892,7 +905,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
className="text-sm font-medium ml-5" | className="text-sm font-medium ml-5" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
Accounts Receivable | |||||
{t("Accounts Receivable")} | |||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5 mb-2" | className="text-lg font-medium ml-5 mb-2" | ||||
@@ -916,7 +929,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
<Card> | <Card> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Expenditure (HKD)" | |||||
title={t("Expenditure (HKD)")} | |||||
/> | /> | ||||
<ReactApexChart | <ReactApexChart | ||||
options={expenditureOptions} | options={expenditureOptions} | ||||
@@ -928,7 +941,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
className="text-sm font-medium ml-5 mt-2" | className="text-sm font-medium ml-5 mt-2" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
Total Budget | |||||
{t("Total Budget")} | |||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5" | className="text-lg font-medium ml-5" | ||||
@@ -941,7 +954,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
className="text-sm font-medium ml-5" | className="text-sm font-medium ml-5" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
Total Cumulative Expenditure | |||||
{t("Total Cumulative Expenditure")} | |||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5" | className="text-lg font-medium ml-5" | ||||
@@ -954,7 +967,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
className="text-sm font-medium ml-5" | className="text-sm font-medium ml-5" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
Remaining Budget | |||||
{t("Remaining Budget")} | |||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5 mb-2" | className="text-lg font-medium ml-5 mb-2" | ||||
@@ -978,12 +991,12 @@ const ProjectCashFlow: React.FC = () => { | |||||
<Card> | <Card> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Anticipate Cash Flow by Month" | |||||
title= {t("Anticipate Cash Flow by Month")} | |||||
/> | /> | ||||
<div style={{ display: "inline-block", width: "99%" }}> | <div style={{ display: "inline-block", width: "99%" }}> | ||||
<div className="inline-block"> | <div className="inline-block"> | ||||
<Label className="text-slate-500 font-medium ml-6"> | <Label className="text-slate-500 font-medium ml-6"> | ||||
Period: | |||||
{t("Year")}: | |||||
</Label> | </Label> | ||||
<Input | <Input | ||||
id={"cashFlowYear"} | id={"cashFlowYear"} | ||||
@@ -1020,7 +1033,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
<Card> | <Card> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Cash Flow Ledger by Month" | |||||
title= {t("Cash Flow Ledger by Month")} | |||||
/> | /> | ||||
<div className="ml-4 mr-4"> | <div className="ml-4 mr-4"> | ||||
<CustomDatagrid | <CustomDatagrid | ||||
@@ -78,56 +78,56 @@ const ProjectFinancialCard: React.FC<Props> = ({ | |||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | ||||
Total Active Project | |||||
{t("Total Active Project")} | |||||
</div> | </div> | ||||
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | <div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | ||||
{TotalActiveProjectNumber.toLocaleString()} | {TotalActiveProjectNumber.toLocaleString()} | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | ||||
Total Fees | |||||
{t("Total Fees")} | |||||
</div> | </div> | ||||
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | <div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | ||||
{TotalFees.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | {TotalFees.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | ||||
Total Budget | |||||
{t("Total Budget")} | |||||
</div> | </div> | ||||
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | <div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | ||||
{TotalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | {TotalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | ||||
Total Cumulative Expenditure | |||||
{t("Total Cumulative Expenditure")} | |||||
</div> | </div> | ||||
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | <div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | ||||
{TotalCumulative.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | {TotalCumulative.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | ||||
Total Invoiced Amount | |||||
{t("Total Invoiced Amount")} | |||||
</div> | </div> | ||||
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | <div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | ||||
{TotalInvoicedAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | {TotalInvoicedAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | ||||
Total Un-Invoiced Amount | |||||
{t("Total Un-Invoiced Amount")} | |||||
</div> | </div> | ||||
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | <div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | ||||
{TotalUnInvoicedAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | {TotalUnInvoicedAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | ||||
Total Received Amount | |||||
{t("Total Received Amount")} | |||||
</div> | </div> | ||||
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | <div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}> | ||||
{TotalReceivedAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | {TotalReceivedAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | ||||
Cash Flow Status | |||||
{t("Cash Flow Status")} | |||||
</div> | </div> | ||||
{CashFlowStatus === "Negative" && ( | {CashFlowStatus === "Negative" && ( | ||||
<> | <> | ||||
@@ -135,7 +135,7 @@ const ProjectFinancialCard: React.FC<Props> = ({ | |||||
className="text-lg font-medium ml-5" | className="text-lg font-medium ml-5" | ||||
style={{ color: "#f896aa" }} | style={{ color: "#f896aa" }} | ||||
> | > | ||||
{CashFlowStatus} | |||||
{t(CashFlowStatus)} | |||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
</> | </> | ||||
@@ -146,7 +146,7 @@ const ProjectFinancialCard: React.FC<Props> = ({ | |||||
className="text-lg font-medium ml-5" | className="text-lg font-medium ml-5" | ||||
style={{ color: "#71d19e" }} | style={{ color: "#71d19e" }} | ||||
> | > | ||||
{CashFlowStatus} | |||||
{t(CashFlowStatus)} | |||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
</> | </> | ||||
@@ -155,7 +155,7 @@ const ProjectFinancialCard: React.FC<Props> = ({ | |||||
className="text-sm mt-2 font-medium ml-5" | className="text-sm mt-2 font-medium ml-5" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
Cost Performance Index (CPI) | |||||
{t("Cost Performance Index") + " (CPI)"} | |||||
</div> | </div> | ||||
{Number(CostPerformanceIndex) < 1 && ( | {Number(CostPerformanceIndex) < 1 && ( | ||||
<> | <> | ||||
@@ -180,7 +180,7 @@ const ProjectFinancialCard: React.FC<Props> = ({ | |||||
</> | </> | ||||
)} | )} | ||||
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | <div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}> | ||||
Projected Cash Flow Status | |||||
{t("Projected Cash Flow Status")} | |||||
</div> | </div> | ||||
{ProjectedCashFlowStatus === "Negative" && ( | {ProjectedCashFlowStatus === "Negative" && ( | ||||
<> | <> | ||||
@@ -188,7 +188,7 @@ const ProjectFinancialCard: React.FC<Props> = ({ | |||||
className="text-lg font-medium ml-5" | className="text-lg font-medium ml-5" | ||||
style={{ color: "#f896aa" }} | style={{ color: "#f896aa" }} | ||||
> | > | ||||
{ProjectedCashFlowStatus} | |||||
{t(ProjectedCashFlowStatus)} | |||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
</> | </> | ||||
@@ -199,7 +199,7 @@ const ProjectFinancialCard: React.FC<Props> = ({ | |||||
className="text-lg font-medium ml-5" | className="text-lg font-medium ml-5" | ||||
style={{ color: "#71d19e" }} | style={{ color: "#71d19e" }} | ||||
> | > | ||||
{ProjectedCashFlowStatus} | |||||
{t(ProjectedCashFlowStatus)} | |||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
</> | </> | ||||
@@ -208,7 +208,7 @@ const ProjectFinancialCard: React.FC<Props> = ({ | |||||
className="text-sm mt-2 font-medium ml-5" | className="text-sm mt-2 font-medium ml-5" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
Projected Cost Performance Index (CPI) | |||||
{t("Projected Cost Performance Index") + " (CPI)"} | |||||
</div> | </div> | ||||
{Number(ProjectedCPI) < 1 && ( | {Number(ProjectedCPI) < 1 && ( | ||||
<> | <> | ||||
@@ -23,6 +23,7 @@ import { exportFinancialSummaryByClientExcel, exportFinancialSummaryByProjectExc | |||||
import ProjectFinancialCard from "./ProjectFinancialCard"; | import ProjectFinancialCard from "./ProjectFinancialCard"; | ||||
import VisibilityIcon from '@mui/icons-material/Visibility'; | import VisibilityIcon from '@mui/icons-material/Visibility'; | ||||
import { downloadFile } from "@/app/utils/commonUtil"; | import { downloadFile } from "@/app/utils/commonUtil"; | ||||
import Typography from "@mui/material/Typography"; | |||||
type SearchProjectQuery = Partial<Omit<FinancialSummaryByProjectResult, "id">>; | type SearchProjectQuery = Partial<Omit<FinancialSummaryByProjectResult, "id">>; | ||||
type SearchClientQuery = Partial<Omit<FinancialSummaryByClientResult, "id">>; | type SearchClientQuery = Partial<Omit<FinancialSummaryByClientResult, "id">>; | ||||
@@ -41,15 +42,15 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
const projectSearchCriteria: Criterion<SearchProjectParamNames>[] = useMemo( | const projectSearchCriteria: Criterion<SearchProjectParamNames>[] = useMemo( | ||||
() => [ | () => [ | ||||
{ label: "Project Code", paramName: "projectCode", type: "text" }, | |||||
{ label: "Project Name", paramName: "projectName", type: "text" }, | |||||
{ label: t("Project Code"), paramName: "projectCode", type: "text" }, | |||||
{ label: t("Project Name"), paramName: "projectName", type: "text" }, | |||||
], | ], | ||||
[t], | [t], | ||||
); | ); | ||||
const clientSearchCriteria: Criterion<SearchClientParamNames>[] = useMemo( | const clientSearchCriteria: Criterion<SearchClientParamNames>[] = useMemo( | ||||
() => [ | () => [ | ||||
{ label: "Client Code", paramName: "customerCode", type: "text" }, | |||||
{ label: "Client Name", paramName: "customerName", type: "text" }, | |||||
{ label: t("Client Code"), paramName: "customerCode", type: "text" }, | |||||
{ label: t("Client Name"), paramName: "customerName", type: "text" }, | |||||
], | ], | ||||
[t], | [t], | ||||
); | ); | ||||
@@ -109,35 +110,35 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
{ | { | ||||
id: 'customerCode', | id: 'customerCode', | ||||
field: 'customerCode', | field: 'customerCode', | ||||
headerName: "Client Code", | |||||
headerName: t("Client Code"), | |||||
minWidth:50 | minWidth:50 | ||||
}, | }, | ||||
{ | { | ||||
id: 'customerName', | id: 'customerName', | ||||
field: 'customerName', | field: 'customerName', | ||||
headerName: "Client Name", | |||||
headerName: t("Client Name"), | |||||
minWidth:80 | minWidth:80 | ||||
}, | }, | ||||
{ | { | ||||
id: 'projectNo', | id: 'projectNo', | ||||
field: 'projectNo', | field: 'projectNo', | ||||
headerName: "Total Project Involved", | |||||
headerName: t("Total Project Involved"), | |||||
minWidth:80 | minWidth:80 | ||||
}, | }, | ||||
{ | { | ||||
id: 'cashFlowStatus', | id: 'cashFlowStatus', | ||||
field: 'cashFlowStatus', | field: 'cashFlowStatus', | ||||
headerName: "Cash Flow Status", | |||||
headerName: t("Cash Flow Status"), | |||||
minWidth:100, | minWidth:100, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
console.log(params.row) | console.log(params.row) | ||||
if (params.row.cashFlowStatus === "Positive") { | if (params.row.cashFlowStatus === "Positive") { | ||||
return ( | return ( | ||||
<span className="text-lime-500">{params.row.cashFlowStatus}</span> | |||||
<span className="text-lime-500">{t(params.row.cashFlowStatus)}</span> | |||||
) | ) | ||||
} else if (params.row.cashFlowStatus === "Negative") { | } else if (params.row.cashFlowStatus === "Negative") { | ||||
return ( | return ( | ||||
<span className="text-red-500">{params.row.cashFlowStatus}</span> | |||||
<span className="text-red-500">{t(params.row.cashFlowStatus)}</span> | |||||
) | ) | ||||
} | } | ||||
}, | }, | ||||
@@ -145,7 +146,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
{ | { | ||||
id: 'cpi', | id: 'cpi', | ||||
field: 'cpi', | field: 'cpi', | ||||
headerName: "CPI", | |||||
headerName: t("CPI"), | |||||
minWidth:50, | minWidth:50, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
if (params.row.cpi >= 1) { | if (params.row.cpi >= 1) { | ||||
@@ -162,16 +163,16 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
{ | { | ||||
id: 'projectedCashFlowStatus', | id: 'projectedCashFlowStatus', | ||||
field: 'projectedCashFlowStatus', | field: 'projectedCashFlowStatus', | ||||
headerName: "Projected Cash Flow Status", | |||||
headerName: t("Projected Cash Flow Status"), | |||||
minWidth:100, | minWidth:100, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
if (params.row.projectedCashFlowStatus === "Positive") { | if (params.row.projectedCashFlowStatus === "Positive") { | ||||
return ( | return ( | ||||
<span className="text-lime-500">{params.row.projectedCashFlowStatus}</span> | |||||
<span className="text-lime-500">{t(params.row.projectedCashFlowStatus)}</span> | |||||
) | ) | ||||
} else if (params.row.projectedCashFlowStatus === "Negative") { | } else if (params.row.projectedCashFlowStatus === "Negative") { | ||||
return ( | return ( | ||||
<span className="text-red-500">{params.row.projectedCashFlowStatus}</span> | |||||
<span className="text-red-500">{t(params.row.projectedCashFlowStatus)}</span> | |||||
) | ) | ||||
} | } | ||||
}, | }, | ||||
@@ -179,7 +180,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
{ | { | ||||
id: 'projectedCpi', | id: 'projectedCpi', | ||||
field: 'projectedCpi', | field: 'projectedCpi', | ||||
headerName: "Projected CPI", | |||||
headerName: t("Projected CPI"), | |||||
minWidth:50, | minWidth:50, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
if (params.row.projectedCpi >= 1) { | if (params.row.projectedCpi >= 1) { | ||||
@@ -196,7 +197,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
{ | { | ||||
id: 'totalFee', | id: 'totalFee', | ||||
field: 'totalFee', | field: 'totalFee', | ||||
headerName: "Total Fees (HKD)", | |||||
headerName: t("Total Fees")+t("HKD"), | |||||
minWidth:50, | minWidth:50, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -207,7 +208,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
{ | { | ||||
id: 'totalBudget', | id: 'totalBudget', | ||||
field: 'totalBudget', | field: 'totalBudget', | ||||
headerName: "Total Budget (HKD)", | |||||
headerName: t("Total Budget")+t("HKD"), | |||||
minWidth:50, | minWidth:50, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -218,7 +219,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
{ | { | ||||
id: 'cumulativeExpenditure', | id: 'cumulativeExpenditure', | ||||
field: 'cumulativeExpenditure', | field: 'cumulativeExpenditure', | ||||
headerName: "Total Cumulative Expenditure (HKD)", | |||||
headerName: t("Total Cumulative Expenditure")+t("HKD"), | |||||
minWidth:280, | minWidth:280, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -229,7 +230,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
{ | { | ||||
id: 'totalInvoiced', | id: 'totalInvoiced', | ||||
field: 'totalInvoiced', | field: 'totalInvoiced', | ||||
headerName: "Total Invoiced Amount (HKD)", | |||||
headerName: t("Total Invoiced Amount")+t("HKD"), | |||||
minWidth:250, | minWidth:250, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -240,7 +241,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
{ | { | ||||
id: 'totalUnInvoiced', | id: 'totalUnInvoiced', | ||||
field: 'totalUnInvoiced', | field: 'totalUnInvoiced', | ||||
headerName: "Total Un-invoiced Amount (HKD)", | |||||
headerName: t("Total Un-Invoiced Amount")+t("HKD"), | |||||
minWidth:250, | minWidth:250, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -251,7 +252,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
{ | { | ||||
id: 'totalReceived', | id: 'totalReceived', | ||||
field: 'totalReceived', | field: 'totalReceived', | ||||
headerName: "Total Received Amount (HKD)", | |||||
headerName: t("Total Received Amount")+t("HKD"), | |||||
minWidth:250, | minWidth:250, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -314,40 +315,40 @@ const columns2 = [ | |||||
{ | { | ||||
id: 'projectCode', | id: 'projectCode', | ||||
field: 'projectCode', | field: 'projectCode', | ||||
headerName: "Project Code", | |||||
headerName: t("Project Code"), | |||||
minWidth:50, | minWidth:50, | ||||
}, | }, | ||||
{ | { | ||||
id: 'projectName', | id: 'projectName', | ||||
field: 'projectName', | field: 'projectName', | ||||
headerName: "Project Name", | |||||
headerName: t("Project Name"), | |||||
minWidth:50, | minWidth:50, | ||||
}, | }, | ||||
{ | { | ||||
id: 'customerName', | id: 'customerName', | ||||
field: 'customerName', | field: 'customerName', | ||||
headerName: "Client Name", | |||||
headerName: t("Client Name"), | |||||
minWidth:50, | minWidth:50, | ||||
}, | }, | ||||
{ | { | ||||
id: 'subsidiaryName', | id: 'subsidiaryName', | ||||
field: 'subsidiaryName', | field: 'subsidiaryName', | ||||
headerName: "Subsidiary", | |||||
headerName: t("Subsidiary"), | |||||
minWidth:50, | minWidth:50, | ||||
}, | }, | ||||
{ | { | ||||
id: 'cashFlowStatus', | id: 'cashFlowStatus', | ||||
field: 'cashFlowStatus', | field: 'cashFlowStatus', | ||||
headerName: "Cash Flow Status", | |||||
headerName: t("Cash Flow Status"), | |||||
minWidth:80, | minWidth:80, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
if (params.row.cashFlowStatus === "Positive") { | if (params.row.cashFlowStatus === "Positive") { | ||||
return ( | return ( | ||||
<span className="text-lime-500">{params.row.cashFlowStatus}</span> | |||||
<span className="text-lime-500">{t(params.row.cashFlowStatus)}</span> | |||||
) | ) | ||||
} else if (params.row.cashFlowStatus === "Negative") { | } else if (params.row.cashFlowStatus === "Negative") { | ||||
return ( | return ( | ||||
<span className="text-red-500">{params.row.cashFlowStatus}</span> | |||||
<span className="text-red-500">{t(params.row.cashFlowStatus)}</span> | |||||
) | ) | ||||
} | } | ||||
}, | }, | ||||
@@ -368,16 +369,16 @@ const columns2 = [ | |||||
{ | { | ||||
id: 'projectedCashFlowStatus', | id: 'projectedCashFlowStatus', | ||||
field: 'projectedCashFlowStatus', | field: 'projectedCashFlowStatus', | ||||
headerName: "Projected Cash Flow Status", | |||||
headerName: t("Projected Cash Flow Status"), | |||||
minWidth:100, | minWidth:100, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
if (params.row.projectedCashFlowStatus === "Positive") { | if (params.row.projectedCashFlowStatus === "Positive") { | ||||
return ( | return ( | ||||
<span className="text-lime-500">{params.row.projectedCashFlowStatus}</span> | |||||
<span className="text-lime-500">{t(params.row.projectedCashFlowStatus)}</span> | |||||
) | ) | ||||
} else if (params.row.projectedCashFlowStatus === "Negative") { | } else if (params.row.projectedCashFlowStatus === "Negative") { | ||||
return ( | return ( | ||||
<span className="text-red-500">{params.row.projectedCashFlowStatus}</span> | |||||
<span className="text-red-500">{t(params.row.projectedCashFlowStatus)}</span> | |||||
) | ) | ||||
} | } | ||||
}, | }, | ||||
@@ -385,7 +386,7 @@ const columns2 = [ | |||||
{ | { | ||||
id: 'projectedCpi', | id: 'projectedCpi', | ||||
field: 'projectedCpi', | field: 'projectedCpi', | ||||
headerName: "Projected CPI", | |||||
headerName: t("Projected CPI"), | |||||
minWidth:50, | minWidth:50, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
if (params.row.projectedCpi >= 1) { | if (params.row.projectedCpi >= 1) { | ||||
@@ -402,7 +403,7 @@ const columns2 = [ | |||||
{ | { | ||||
id: 'totalFees', | id: 'totalFees', | ||||
field: 'totalFees', | field: 'totalFees', | ||||
headerName: "Total Fees (HKD)", | |||||
headerName: t("Total Fees")+t("HKD"), | |||||
minWidth:50, | minWidth:50, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -413,7 +414,7 @@ const columns2 = [ | |||||
{ | { | ||||
id: 'totalBudget', | id: 'totalBudget', | ||||
field: 'totalBudget', | field: 'totalBudget', | ||||
headerName: "Total Budget (HKD)", | |||||
headerName: t("Total Budget")+t("HKD"), | |||||
minWidth:50, | minWidth:50, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -424,7 +425,7 @@ const columns2 = [ | |||||
{ | { | ||||
id: 'totalCumulativeExpenditure', | id: 'totalCumulativeExpenditure', | ||||
field: 'totalCumulativeExpenditure', | field: 'totalCumulativeExpenditure', | ||||
headerName: "Total Cumulative Expenditure (HKD)", | |||||
headerName: t("Total Cumulative Expenditure")+t("HKD"), | |||||
minWidth:250, | minWidth:250, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -435,7 +436,7 @@ const columns2 = [ | |||||
{ | { | ||||
id: 'totalInvoicedAmount', | id: 'totalInvoicedAmount', | ||||
field: 'totalInvoicedAmount', | field: 'totalInvoicedAmount', | ||||
headerName: "Total Invoiced Amount (HKD)", | |||||
headerName: t("Total Invoiced Amount")+t("HKD"), | |||||
minWidth:250, | minWidth:250, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -446,7 +447,7 @@ const columns2 = [ | |||||
{ | { | ||||
id: 'totalUnInvoicedAmount', | id: 'totalUnInvoicedAmount', | ||||
field: 'totalUnInvoicedAmount', | field: 'totalUnInvoicedAmount', | ||||
headerName: "Total Un-invoiced Amount (HKD)", | |||||
headerName: t("Total Un-Invoiced Amount")+t("HKD"), | |||||
minWidth:250, | minWidth:250, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -457,7 +458,7 @@ const columns2 = [ | |||||
{ | { | ||||
id: 'totalReceivedAmount', | id: 'totalReceivedAmount', | ||||
field: 'totalReceivedAmount', | field: 'totalReceivedAmount', | ||||
headerName: "Total Received Amount (HKD)", | |||||
headerName: t("Total Received Amount") +t("HKD"), | |||||
minWidth:250, | minWidth:250, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -503,30 +504,33 @@ const columns2 = [ | |||||
return ( | return ( | ||||
<Grid item sm> | <Grid item sm> | ||||
<Card> | |||||
<CardHeader className="text-slate-500" title="Active Project Financial Status"/> | |||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
{t("Financial Summary")} | |||||
</Typography> | |||||
<Card className="mt-5"> | |||||
<CardHeader className="text-slate-500" title= {t("Active Project Financial Status")}/> | |||||
<div className="ml-10 mr-10" style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'start'}}> | <div className="ml-10 mr-10" style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'start'}}> | ||||
{projectFinancialData.map((record:any, index:any) => ( | {projectFinancialData.map((record:any, index:any) => ( | ||||
<div className="hover:cursor-pointer ml-4 mt-5 mb-4 inline-block" key={index} onClick={(r) => handleCardClick(record,index)}> | <div className="hover:cursor-pointer ml-4 mt-5 mb-4 inline-block" key={index} onClick={(r) => handleCardClick(record,index)}> | ||||
<ProjectFinancialCard Title={record.teamName} TotalActiveProjectNumber={record.projectNo} TotalFees={record.totalFee} TotalBudget={record.totalBudget} TotalCumulative={record.cumulativeExpenditure ?? 0} TotalInvoicedAmount={record.totalInvoiced ?? 0} TotalUnInvoicedAmount={record.unInvoiced ?? 0} TotalReceivedAmount={record.totalReceived ?? 0} CashFlowStatus={record.cashFlowStatus ?? "Negative"} CostPerformanceIndex={record.cpi ?? 0} ProjectedCashFlowStatus={record.projectedCashFlowStatus ?? "Negative"} ProjectedCPI={record.projectedCpi ?? 0} ClickedIndex={isCardClickedIndex} Index={index}/> | |||||
<ProjectFinancialCard Title={record.teamName == "All Team" ? t("All Team") : record.teamName} TotalActiveProjectNumber={record.projectNo} TotalFees={record.totalFee} TotalBudget={record.totalBudget} TotalCumulative={record.cumulativeExpenditure ?? 0} TotalInvoicedAmount={record.totalInvoiced ?? 0} TotalUnInvoicedAmount={record.unInvoiced ?? 0} TotalReceivedAmount={record.totalReceived ?? 0} CashFlowStatus={record.cashFlowStatus ?? "Negative"} CostPerformanceIndex={record.cpi ?? 0} ProjectedCashFlowStatus={record.projectedCashFlowStatus ?? "Negative"} ProjectedCPI={record.projectedCpi ?? 0} ClickedIndex={isCardClickedIndex} Index={index}/> | |||||
</div> | </div> | ||||
))} | ))} | ||||
</div> | </div> | ||||
<hr></hr> | <hr></hr> | ||||
<div className="ml-10 text-base"><strong>-Formula-</strong></div> | |||||
<div className="ml-10 text-sm"><strong>CPI:</strong> Invoiced Amount / Cumulative Expenditure</div> | |||||
<div className="ml-10 text-sm"><strong>Cash Flow Status: </strong>{`Positive when CPI >= 1`}</div> | |||||
<div className="ml-10 text-sm"><strong>Projected CPI:</strong> Project Fee / Cumulative Expenditure</div> | |||||
<div className="ml-10 text-sm mb-5"><strong>Cash Flow Status: </strong>{`Positive when Projected CPI >= 1`}</div> | |||||
<div className="ml-10 text-base"><strong>-{t("Formula")}-</strong></div> | |||||
<div className="ml-10 text-sm"><strong>CPI:</strong> {t("Invoiced Amount")} / {t("Cumulative Expenditure")}</div> | |||||
<div className="ml-10 text-sm"><strong>{t("Cash Flow Status")}: </strong>{`${t("Positive when CPI")}`}</div> | |||||
<div className="ml-10 text-sm"><strong>{t("Projected CPI")}:</strong> {t("Project Fee")} / {t("Cumulative Expenditure")}</div> | |||||
<div className="ml-10 text-sm mb-5"><strong>{t("Cash Flow Status")}: </strong>{t("Positive when Projected CPI")}</div> | |||||
</Card> | </Card> | ||||
<Card className="mt-5"> | <Card className="mt-5"> | ||||
<div style={{display:"inline-block"}}> | <div style={{display:"inline-block"}}> | ||||
<CardHeader className="text-slate-500" title="Financial Status (by Project)"/> | |||||
<CardHeader className="text-slate-500" title={t("Financial Status (by Project)")}/> | |||||
</div> | </div> | ||||
<div style={{display:"inline-block"}}> | <div style={{display:"inline-block"}}> | ||||
{projectFinancialRows.length > 0 && ( | {projectFinancialRows.length > 0 && ( | ||||
<button onClick={handleExportByProject} className="hover:cursor-pointer hover:bg-lime-50 text-base bg-transparent border-lime-600 text-lime-600 border-solid rounded-md w-36"> | <button onClick={handleExportByProject} className="hover:cursor-pointer hover:bg-lime-50 text-base bg-transparent border-lime-600 text-lime-600 border-solid rounded-md w-36"> | ||||
Export Excel | |||||
{t("Export Excel")} | |||||
</button> | </button> | ||||
)} | )} | ||||
</div> | </div> | ||||
@@ -556,12 +560,12 @@ const columns2 = [ | |||||
</Card> | </Card> | ||||
<Card className="mt-5"> | <Card className="mt-5"> | ||||
<div style={{display:"inline-block"}}> | <div style={{display:"inline-block"}}> | ||||
<CardHeader className="text-slate-500" title="Financial Status (by Client)"/> | |||||
<CardHeader className="text-slate-500" title= {t("Financial Status (by Client)")}/> | |||||
</div> | </div> | ||||
<div style={{display:"inline-block"}}> | <div style={{display:"inline-block"}}> | ||||
{clientFinancialRows.length > 0 && ( | {clientFinancialRows.length > 0 && ( | ||||
<button onClick={handleExportByClient} className="hover:cursor-pointer hover:bg-lime-50 text-base bg-transparent border-lime-600 text-lime-600 border-solid rounded-md w-36"> | <button onClick={handleExportByClient} className="hover:cursor-pointer hover:bg-lime-50 text-base bg-transparent border-lime-600 text-lime-600 border-solid rounded-md w-36"> | ||||
Export Excel | |||||
{t("Export Excel")} | |||||
</button> | </button> | ||||
)} | )} | ||||
</div> | </div> | ||||
@@ -20,6 +20,7 @@ import ProgressByTeamSearch from "@/components/ProgressByTeamSearch"; | |||||
import { Suspense } from "react"; | import { Suspense } from "react"; | ||||
import { useSearchParams } from 'next/navigation'; | import { useSearchParams } from 'next/navigation'; | ||||
import { fetchAllTeamProjects, TeamProjectResult, fetchTeamProjects, fetchAllTeamConsumption, fetchAllTeamConsumptionColorOrder} from "@/app/api/teamprojects/actions"; | import { fetchAllTeamProjects, TeamProjectResult, fetchTeamProjects, fetchAllTeamConsumption, fetchAllTeamConsumptionColorOrder} from "@/app/api/teamprojects/actions"; | ||||
import Typography from "@mui/material/Typography"; | |||||
// const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false }); | // const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false }); | ||||
interface Props { | interface Props { | ||||
@@ -125,8 +126,8 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | ||||
() => [ | () => [ | ||||
{ label: "Team Code", paramName: "teamCode", type: "text" }, | |||||
{ label: "Team Name", paramName: "teamName", type: "text" }, | |||||
{ label: t("Team Code"), paramName: "teamCode", type: "text" }, | |||||
{ label: t("Team Name"), paramName: "teamName", type: "text" }, | |||||
], | ], | ||||
[t], | [t], | ||||
); | ); | ||||
@@ -292,19 +293,19 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
{ | { | ||||
id: "teamCode", | id: "teamCode", | ||||
field: "teamCode", | field: "teamCode", | ||||
headerName: "Team Code", | |||||
headerName: t("Team Code"), | |||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
{ | { | ||||
id: "teamName", | id: "teamName", | ||||
field: "teamName", | field: "teamName", | ||||
headerName: "Team Name", | |||||
headerName: t("Team Name"), | |||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
{ | { | ||||
id: "projectNo", | id: "projectNo", | ||||
field: "projectNo", | field: "projectNo", | ||||
headerName: "No. of Projects", | |||||
headerName: t("No. of Projects"), | |||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
]; | ]; | ||||
@@ -360,31 +361,31 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
{ | { | ||||
id: "projectCode", | id: "projectCode", | ||||
field: "projectCode", | field: "projectCode", | ||||
headerName: "Project No", | |||||
headerName: t("Project Code"), | |||||
minWidth:100 | minWidth:100 | ||||
}, | }, | ||||
{ | { | ||||
id: "projectName", | id: "projectName", | ||||
field: "projectName", | field: "projectName", | ||||
headerName: "Project", | |||||
headerName: t("Project Name"), | |||||
minWidth:300 | minWidth:300 | ||||
}, | }, | ||||
{ | { | ||||
id: "team", | id: "team", | ||||
field: "team", | field: "team", | ||||
headerName: "Team", | |||||
headerName: t("Team"), | |||||
minWidth:50 | minWidth:50 | ||||
}, | }, | ||||
{ | { | ||||
id: "teamLead", | id: "teamLead", | ||||
field: "teamLead", | field: "teamLead", | ||||
headerName: "Team Leader", | |||||
headerName: t("Team Leader"), | |||||
minWidth: 70 | minWidth: 70 | ||||
}, | }, | ||||
{ | { | ||||
id: "expectedStage", | id: "expectedStage", | ||||
field: "expectedStage", | field: "expectedStage", | ||||
headerName: "Expected Stage", | |||||
headerName: t("Expected Stage"), | |||||
minWidth: 300, | minWidth: 300, | ||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.expectedStage != null){ | if (params.row.expectedStage != null){ | ||||
@@ -405,7 +406,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
{ | { | ||||
id: "budgetedManhour", | id: "budgetedManhour", | ||||
field: "budgetedManhour", | field: "budgetedManhour", | ||||
headerName: "Budgeted Manhour", | |||||
headerName: t("Budgeted Manhours"), | |||||
minWidth: 70, | minWidth: 70, | ||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
return <span>{params.row.budgetedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>; | return <span>{params.row.budgetedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>; | ||||
@@ -414,7 +415,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
{ | { | ||||
id: "spentManhour", | id: "spentManhour", | ||||
field: "spentManhour", | field: "spentManhour", | ||||
headerName: "Spent Manhour", | |||||
headerName: t("Spent Manhours"), | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | ||||
return ( | return ( | ||||
@@ -429,7 +430,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
{ | { | ||||
id: "remainedManhour", | id: "remainedManhour", | ||||
field: "remainedManhour", | field: "remainedManhour", | ||||
headerName: "Remained Manhour", | |||||
headerName: t("Remained Manhours"), | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | ||||
return ( | return ( | ||||
@@ -444,13 +445,13 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
{ | { | ||||
id: "comingPaymentMilestone", | id: "comingPaymentMilestone", | ||||
field: "comingPaymentMilestone", | field: "comingPaymentMilestone", | ||||
headerName: "Coming Payment Milestone", | |||||
headerName: t("Coming Payment Milestones"), | |||||
minWidth: 100 | minWidth: 100 | ||||
}, | }, | ||||
{ | { | ||||
id: "alert", | id: "alert", | ||||
field: "alert", | field: "alert", | ||||
headerName: "Alert", | |||||
headerName: t("Alert"), | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.alert === 1) { | if (params.row.alert === 1) { | ||||
return ( | return ( | ||||
@@ -532,7 +533,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
total: { | total: { | ||||
show: true, | show: true, | ||||
showAlways: true, | showAlways: true, | ||||
label: "Spent", | |||||
label: t("Spent"), | |||||
fontFamily: "sans-serif", | fontFamily: "sans-serif", | ||||
formatter: function (val) { | formatter: function (val) { | ||||
return totalSpentPercentage + "%"; | return totalSpentPercentage + "%"; | ||||
@@ -580,9 +581,9 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
<div style="width: 250px;"> | <div style="width: 250px;"> | ||||
<span style="font-weight: bold;">${projectCode} - ${projectName}</span> | <span style="font-weight: bold;">${projectCode} - ${projectName}</span> | ||||
<br> | <br> | ||||
Budget Manhours: ${budgetManhours} hours | |||||
${t("Budget Manhours")}: ${budgetManhours} ${t("hours")} | |||||
<br> | <br> | ||||
Spent Manhours: ${spentManhours} hours | |||||
${t("Spent Manhours")}: ${spentManhours} ${t("hours")} | |||||
<br> | <br> | ||||
Percentage: ${value}% | Percentage: ${value}% | ||||
</div> | </div> | ||||
@@ -615,7 +616,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
}, | }, | ||||
yaxis: { | yaxis: { | ||||
title: { | title: { | ||||
text: "Projects", | |||||
text: t("Projects"), | |||||
}, | }, | ||||
labels: { | labels: { | ||||
maxWidth: 200, | maxWidth: 200, | ||||
@@ -625,7 +626,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
}, | }, | ||||
}, | }, | ||||
title: { | title: { | ||||
text: "Project Resource Consumption Percentage", | |||||
text: t("Project Resource Consumption Percentage"), | |||||
align: "center", | align: "center", | ||||
}, | }, | ||||
grid: { | grid: { | ||||
@@ -671,7 +672,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
const percentageArray = []; | const percentageArray = []; | ||||
for (let i = 0; i <= selectedRowsData.length; i++) { | for (let i = 0; i <= selectedRowsData.length; i++) { | ||||
if (i === selectedRowsData.length && i > 0) { | if (i === selectedRowsData.length && i > 0) { | ||||
projectArray.push("Remained"); | |||||
projectArray.push(t("Remained")); | |||||
} else if (selectedRowsData.length > 0) { | } else if (selectedRowsData.length > 0) { | ||||
projectArray.push(selectedRowsData[i].projectName); | projectArray.push(selectedRowsData[i].projectName); | ||||
totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour); | totalBudgetManhour += Number(selectedRowsData[i].budgetedManhour); | ||||
@@ -705,7 +706,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
setTotalSpentPercentage( | setTotalSpentPercentage( | ||||
((totalSpent / totalBudgetManhour) * 100).toFixed(1), | ((totalSpent / totalBudgetManhour) * 100).toFixed(1), | ||||
); | ); | ||||
if (projectArray.length > 0 && projectArray.includes("Remained")) { | |||||
if (projectArray.length > 0 && projectArray.includes(t("Remained"))) { | |||||
const nonLastRecordColors = pieChartColorArray; | const nonLastRecordColors = pieChartColorArray; | ||||
setColorArray([ | setColorArray([ | ||||
...nonLastRecordColors.slice(0, projectArray.length - 1), | ...nonLastRecordColors.slice(0, projectArray.length - 1), | ||||
@@ -754,6 +755,9 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
}; | }; | ||||
return ( | return ( | ||||
<> | <> | ||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
{t("Project Resource Consumption Ranking")} | |||||
</Typography> | |||||
<SearchBox | <SearchBox | ||||
criteria={searchCriteria} | criteria={searchCriteria} | ||||
onSearch={(query) => { | onSearch={(query) => { | ||||
@@ -779,30 +783,30 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
<div style={{ display: "inline-block", width: "70%" }}> | <div style={{ display: "inline-block", width: "70%" }}> | ||||
<Grid item xs={12} md={12} lg={12}> | <Grid item xs={12} md={12} lg={12}> | ||||
<Card> | <Card> | ||||
<CardHeader className="text-slate-500" title="Project Resource Consumption" /> | |||||
<CardHeader className="text-slate-500" title= {t("Project Resource Consumption")} /> | |||||
<div style={{ display: "inline-block", width: "99%" }}> | <div style={{ display: "inline-block", width: "99%" }}> | ||||
<div className="ml-6 text-sm"> | <div className="ml-6 text-sm"> | ||||
<b> | <b> | ||||
Sorting: | |||||
{t("Sorting")}: | |||||
</b> | </b> | ||||
</div> | </div> | ||||
<div className="ml-6 mb-2"> | <div className="ml-6 mb-2"> | ||||
<button onClick={() => {setTableSorting('PercentageASC')}} | <button onClick={() => {setTableSorting('PercentageASC')}} | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | ||||
> | > | ||||
{`Percentage (Ascending Order)`} | |||||
{t("Percentage (Ascending Order)")} | |||||
</button> | </button> | ||||
<button | <button | ||||
onClick={() => {setTableSorting('PercentageDESC')}} | onClick={() => {setTableSorting('PercentageDESC')}} | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | ||||
> | > | ||||
{`Percentage (Descending Order)`} | |||||
{t("Percentage (Descending Order)")} | |||||
</button> | </button> | ||||
<button | <button | ||||
onClick={() => {setTableSorting('ProjectName')}} | onClick={() => {setTableSorting('ProjectName')}} | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | className="hover:cursor-pointer hover:bg-lime-50 text-sm bg-transparent border-lime-600 text-lime-600 border-solid w-50" | ||||
> | > | ||||
Project Name | |||||
{t("Project Name")} | |||||
</button> | </button> | ||||
</div> | </div> | ||||
<ReactApexChart | <ReactApexChart | ||||
@@ -814,25 +818,25 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
<div className="float-right mr-4 mb-10"> | <div className="float-right mr-4 mb-10"> | ||||
{currentPage === 1 && ( | {currentPage === 1 && ( | ||||
<button className="bg-lime-600 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-l"> | <button className="bg-lime-600 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-l"> | ||||
Pervious | |||||
{t("Previous")} | |||||
</button> | </button> | ||||
)} | )} | ||||
{currentPage !== 1 && ( | {currentPage !== 1 && ( | ||||
<button onClick={handlePrevPage} className="bg-lime-600 hover:bg-lime-700 text-white font-bold py-2 px-4 outline-none rounded-l"> | |||||
Previous | |||||
<button onClick={handlePrevPage} className="bg-lime-600 hover:bg-lime-7000 text-white font-bold py-2 px-4 outline-none rounded-l"> | |||||
{t("Previous")} | |||||
</button> | </button> | ||||
)} | )} | ||||
{endIndex >= chartManhourConsumptionPercentage.length && ( | {endIndex >= chartManhourConsumptionPercentage.length && ( | ||||
<button className="bg-lime-600 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-r mr-2"> | <button className="bg-lime-600 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-r mr-2"> | ||||
Next | |||||
{t("Next")} | |||||
</button> | </button> | ||||
)} | )} | ||||
{endIndex < chartManhourConsumptionPercentage.length && ( | {endIndex < chartManhourConsumptionPercentage.length && ( | ||||
<button onClick={handleNextPage} className="bg-lime-600 hover:bg-lime-700 text-white font-bold py-2 px-4 outline-none rounded-r mr-2"> | <button onClick={handleNextPage} className="bg-lime-600 hover:bg-lime-700 text-white font-bold py-2 px-4 outline-none rounded-r mr-2"> | ||||
Next | |||||
{t("Next")} | |||||
</button> | </button> | ||||
)} | )} | ||||
Page | |||||
{t("Page")} | |||||
{chartManhourConsumptionPercentage.length === 0 && ( | {chartManhourConsumptionPercentage.length === 0 && ( | ||||
0 | 0 | ||||
)} | )} | ||||
@@ -848,7 +852,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
<Card className="mt-2"> | <Card className="mt-2"> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Resource Consumption and Coming Milestone" | |||||
title={t("Resource Consumption and Coming Milestones")} | |||||
/> | /> | ||||
<div | <div | ||||
style={{ display: "inline-block", width: "99%", marginLeft: 10 }} | style={{ display: "inline-block", width: "99%", marginLeft: 10 }} | ||||
@@ -878,14 +882,14 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
<Card style={{ marginLeft: 15, marginRight: 20, height:"100%"}}> | <Card style={{ marginLeft: 15, marginRight: 20, height:"100%"}}> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Overall Progress per Project" | |||||
title= {t("Overall Progress per Project")} | |||||
/> | /> | ||||
{percentageArray.length === 0 && ( | {percentageArray.length === 0 && ( | ||||
<div | <div | ||||
className="mt-40 mb-10 ml-5 mr-5 text-lg font-medium text-center" | className="mt-40 mb-10 ml-5 mr-5 text-lg font-medium text-center" | ||||
style={{ color: "#898d8d"}} | style={{ color: "#898d8d"}} | ||||
> | > | ||||
Please select the project you want to check. | |||||
{t("Please select the project you want to check.")} | |||||
</div> | </div> | ||||
)} | )} | ||||
{percentageArray.length > 0 && ( | {percentageArray.length > 0 && ( | ||||
@@ -905,7 +909,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
className="mt-5 text-lg font-medium" | className="mt-5 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>Project Budget Manhour</span> | |||||
<span style={{ marginLeft: "5%" }}>{t("Project Budget Manhours")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
@@ -920,7 +924,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>Actual Manhour Spent</span> | |||||
<span style={{ marginLeft: "5%" }}>{t("Actual Manhours Spent")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
@@ -935,7 +939,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>Remained Manhour</span> | |||||
<span style={{ marginLeft: "5%" }}>{t("Remained Manhours")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
@@ -950,7 +954,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>Last Update</span> | |||||
<span style={{ marginLeft: "5%" }}>{t("Last Update")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 mb-5 text-2xl font-extrabold" | className="mt-2 mb-5 text-2xl font-extrabold" | ||||
@@ -254,18 +254,18 @@ const ProjectResourceSummary: React.FC = () => { | |||||
</TableCell> | </TableCell> | ||||
<TableCell style={{fontSize:13}}>{row.stage}</TableCell> | <TableCell style={{fontSize:13}}>{row.stage}</TableCell> | ||||
<TableCell style={{fontSize:13}}>{row.taskCount}</TableCell> | <TableCell style={{fontSize:13}}>{row.taskCount}</TableCell> | ||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g1Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g1Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g2Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g2Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g3Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g3Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g4Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g4Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g5Planned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g5Actual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.totalPlanned.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.totalActual.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g1Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g1Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g2Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g2Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g3Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g3Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g4Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g4Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g5Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g5Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.totalPlanned.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.totalActual.toFixed(2)}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
{row.task.map((taskRow:any) => ( | {row.task.map((taskRow:any) => ( | ||||
<TableRow key={taskRow[0]} style={{backgroundColor:"#f0f3f7"}} className="border-t-2 border-b-0 border-l-0 border-r-0 border-solid border-slate-300"> | <TableRow key={taskRow[0]} style={{backgroundColor:"#f0f3f7"}} className="border-t-2 border-b-0 border-l-0 border-r-0 border-solid border-slate-300"> | ||||
@@ -314,7 +314,7 @@ const ProjectResourceSummary: React.FC = () => { | |||||
<Table size="small" aria-label="tasks"> | <Table size="small" aria-label="tasks"> | ||||
<TableBody> | <TableBody> | ||||
<TableRow> | <TableRow> | ||||
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{taskRow[4].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{typeof taskRow[4] === 'number' ? taskRow[4].toFixed(2) : (taskRow[4] || '-')}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableBody> | </TableBody> | ||||
</Table> | </Table> | ||||
@@ -327,7 +327,7 @@ const ProjectResourceSummary: React.FC = () => { | |||||
<Table size="small" aria-label="tasks"> | <Table size="small" aria-label="tasks"> | ||||
<TableBody> | <TableBody> | ||||
<TableRow> | <TableRow> | ||||
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{taskRow[5].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{typeof taskRow[5] === 'number' ? taskRow[5].toFixed(2) : (taskRow[5] || '-')}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableBody> | </TableBody> | ||||
</Table> | </Table> | ||||
@@ -340,7 +340,7 @@ const ProjectResourceSummary: React.FC = () => { | |||||
<Table size="small" aria-label="tasks"> | <Table size="small" aria-label="tasks"> | ||||
<TableBody> | <TableBody> | ||||
<TableRow> | <TableRow> | ||||
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{taskRow[6].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{typeof taskRow[6] === 'number' ? taskRow[6].toFixed(2) : (taskRow[6] || '-')}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableBody> | </TableBody> | ||||
</Table> | </Table> | ||||
@@ -353,7 +353,7 @@ const ProjectResourceSummary: React.FC = () => { | |||||
<Table size="small" aria-label="tasks"> | <Table size="small" aria-label="tasks"> | ||||
<TableBody> | <TableBody> | ||||
<TableRow> | <TableRow> | ||||
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{taskRow[7].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{typeof taskRow[7] === 'number' ? taskRow[7].toFixed(2) : (taskRow[7] || '-')}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableBody> | </TableBody> | ||||
</Table> | </Table> | ||||
@@ -366,7 +366,7 @@ const ProjectResourceSummary: React.FC = () => { | |||||
<Table size="small" aria-label="tasks"> | <Table size="small" aria-label="tasks"> | ||||
<TableBody> | <TableBody> | ||||
<TableRow> | <TableRow> | ||||
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{taskRow[8].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{typeof taskRow[8] === 'number' ? taskRow[8].toFixed(2) : (taskRow[8] || '-')}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableBody> | </TableBody> | ||||
</Table> | </Table> | ||||
@@ -379,7 +379,7 @@ const ProjectResourceSummary: React.FC = () => { | |||||
<Table size="small" aria-label="tasks"> | <Table size="small" aria-label="tasks"> | ||||
<TableBody> | <TableBody> | ||||
<TableRow> | <TableRow> | ||||
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{taskRow[9].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{typeof taskRow[9] === 'number' ? taskRow[9].toFixed(2) : (taskRow[9] || '-')}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableBody> | </TableBody> | ||||
</Table> | </Table> | ||||
@@ -392,7 +392,7 @@ const ProjectResourceSummary: React.FC = () => { | |||||
<Table size="small" aria-label="tasks"> | <Table size="small" aria-label="tasks"> | ||||
<TableBody> | <TableBody> | ||||
<TableRow> | <TableRow> | ||||
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{taskRow[10].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{typeof taskRow[10] === 'number' ? taskRow[10].toFixed(2) : (taskRow[10] || '-')}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableBody> | </TableBody> | ||||
</Table> | </Table> | ||||
@@ -405,7 +405,7 @@ const ProjectResourceSummary: React.FC = () => { | |||||
<Table size="small" aria-label="tasks"> | <Table size="small" aria-label="tasks"> | ||||
<TableBody> | <TableBody> | ||||
<TableRow> | <TableRow> | ||||
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{taskRow[11].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{typeof taskRow[11] === 'number' ? taskRow[11].toFixed(2) : (taskRow[11] || '-')}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableBody> | </TableBody> | ||||
</Table> | </Table> | ||||
@@ -418,7 +418,7 @@ const ProjectResourceSummary: React.FC = () => { | |||||
<Table size="small" aria-label="tasks"> | <Table size="small" aria-label="tasks"> | ||||
<TableBody> | <TableBody> | ||||
<TableRow> | <TableRow> | ||||
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{taskRow[12].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{typeof taskRow[12] === 'number' ? taskRow[12].toFixed(2) : (taskRow[12] || '-')}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableBody> | </TableBody> | ||||
</Table> | </Table> | ||||
@@ -431,7 +431,7 @@ const ProjectResourceSummary: React.FC = () => { | |||||
<Table size="small" aria-label="tasks"> | <Table size="small" aria-label="tasks"> | ||||
<TableBody> | <TableBody> | ||||
<TableRow> | <TableRow> | ||||
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{taskRow[13].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{typeof taskRow[13] === 'number' ? taskRow[13].toFixed(2) : (taskRow[13] || '-')}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableBody> | </TableBody> | ||||
</Table> | </Table> | ||||
@@ -444,7 +444,7 @@ const ProjectResourceSummary: React.FC = () => { | |||||
<Table size="small" aria-label="tasks"> | <Table size="small" aria-label="tasks"> | ||||
<TableBody> | <TableBody> | ||||
<TableRow> | <TableRow> | ||||
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{taskRow[2].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}} colSpan={1}>{typeof taskRow[2] === 'number' ? taskRow[2].toFixed(2) : (taskRow[2] || '-')}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableBody> | </TableBody> | ||||
</Table> | </Table> | ||||
@@ -457,7 +457,7 @@ const ProjectResourceSummary: React.FC = () => { | |||||
<Table size="small" aria-label="tasks"> | <Table size="small" aria-label="tasks"> | ||||
<TableBody> | <TableBody> | ||||
<TableRow> | <TableRow> | ||||
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{taskRow[3].toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}} colSpan={1}>{typeof taskRow[3] === 'number' ? taskRow[3].toFixed(2) : (taskRow[3] || '-')}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableBody> | </TableBody> | ||||
</Table> | </Table> | ||||
@@ -619,12 +619,12 @@ const columns2 = [ | |||||
}, | }, | ||||
}}> | }}> | ||||
<Card className="mt-5"> | <Card className="mt-5"> | ||||
<CardHeader className="text-slate-500" title="Project Information"/> | |||||
<CardHeader className="text-slate-500" title= {t("Project Information")}/> | |||||
<div className="ml-6 mr-6"> | <div className="ml-6 mr-6"> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{fontSize:"1em", fontWeight:"bold"}}> | <div style={{fontSize:"1em", fontWeight:"bold"}}> | ||||
<u> | <u> | ||||
Project | |||||
{t("Project")} | |||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | <div style={{fontSize:"1em"}}> | ||||
@@ -634,81 +634,81 @@ const columns2 = [ | |||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | <div style={{ fontSize:"1em", fontWeight:"bold"}}> | ||||
<u> | <u> | ||||
Project Fee | |||||
{t("Project Fee")} | |||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | <div style={{fontSize:"1em"}}> | ||||
HKD ${projectFee.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||||
HKD ${projectFee.toFixed(2)} | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | <div style={{ fontSize:"1em", fontWeight:"bold"}}> | ||||
<u> | <u> | ||||
Total Budget | |||||
{t("Total Budget")} | |||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | <div style={{fontSize:"1em"}}> | ||||
HKD ${projectBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||||
HKD ${projectBudget.toFixed(2)} | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | <div style={{ fontSize:"1em", fontWeight:"bold"}}> | ||||
<u> | <u> | ||||
Cumculative Expenditure | |||||
{t("Cumulative Expenditure")} | |||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | <div style={{fontSize:"1em"}}> | ||||
HKD ${expenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||||
HKD ${expenditure.toFixed(2)} | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | <div style={{ fontSize:"1em", fontWeight:"bold"}}> | ||||
<u> | <u> | ||||
Remaining Budget | |||||
{t("Remaining Budget")} | |||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | <div style={{fontSize:"1em"}}> | ||||
HKD ${remainingBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | |||||
HKD ${remainingBudget.toFixed(2)} | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | <div style={{ fontSize:"1em", fontWeight:"bold"}}> | ||||
<u> | <u> | ||||
Status | |||||
{t("Status")} | |||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | <div style={{fontSize:"1em"}}> | ||||
{status} | |||||
{t(status)} | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | <div style={{ fontSize:"1em", fontWeight:"bold"}}> | ||||
<u> | <u> | ||||
Planned Resources | |||||
{t("Planned Resources")} | |||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | <div style={{fontSize:"1em"}}> | ||||
{plannedResources.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} Manhours | |||||
{plannedResources.toFixed(2)} {t("Manhours")} | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | <div style={{ fontSize:"1em", fontWeight:"bold"}}> | ||||
<u> | <u> | ||||
Actual Resources Spent | |||||
{t("Actual Resources Spent")} | |||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | <div style={{fontSize:"1em"}}> | ||||
{(actualResourcesSpent ?? 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} Manhours ({(actualResourcesSpent/plannedResources*100).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}%) | |||||
{(actualResourcesSpent ?? 0).toFixed(2)} {t("Manhours")} ({(actualResourcesSpent/plannedResources*100).toFixed(2)}%) | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | <div style={{ fontSize:"1em", fontWeight:"bold"}}> | ||||
<u> | <u> | ||||
Remaining Resources | |||||
{t("Remaining Resources")} | |||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | |||||
{(remainingResources ?? 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} Manhours ({(remainingResources/plannedResources*100).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}%) | |||||
<div style={{fontSize:"1em"}} className={"mb-5"}> | |||||
{(remainingResources ?? 0).toFixed(2)} {t("Manhours")} ({(remainingResources/plannedResources*100).toFixed(2)}%) | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -742,25 +742,25 @@ const columns2 = [ | |||||
G5 | G5 | ||||
</TableCell> | </TableCell> | ||||
<TableCell align="center" colSpan={2} style={{backgroundColor:"rgba(218, 218, 245, 0.55)"}}> | <TableCell align="center" colSpan={2} style={{backgroundColor:"rgba(218, 218, 245, 0.55)"}}> | ||||
Total | |||||
{t("Total")} | |||||
</TableCell> | </TableCell> | ||||
</TableRow> | </TableRow> | ||||
<TableRow className="border-t-2 border-b-0 border-l-0 border-r-0 border-solid border-slate-300"> | <TableRow className="border-t-2 border-b-0 border-l-0 border-r-0 border-solid border-slate-300"> | ||||
<TableCell style={{minWidth:30}}/> | <TableCell style={{minWidth:30}}/> | ||||
<TableCell style={{fontSize:11, minWidth:150}}>Stage</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30}}>Task Count</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>Planned</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>Actual</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>Planned</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>Actual</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>Planned</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>Actual</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>Planned</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>Actual</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>Planned</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>Actual</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>Planned</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>Actual</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:150}}>{t("Stage")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30}}>{t("Task Count")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableHead> | </TableHead> | ||||
<TableBody> | <TableBody> | ||||
@@ -10,6 +10,7 @@ import EditNote from "@mui/icons-material/EditNote"; | |||||
import { useRouter, useSearchParams } from "next/navigation"; | import { useRouter, useSearchParams } from "next/navigation"; | ||||
import ProjectResourceSummary from "@/components/ProjectResourceSummary"; | import ProjectResourceSummary from "@/components/ProjectResourceSummary"; | ||||
import ArticleIcon from '@mui/icons-material/Article'; | import ArticleIcon from '@mui/icons-material/Article'; | ||||
import Typography from "@mui/material/Typography"; | |||||
interface Props { | interface Props { | ||||
projects: ResourceSummaryResult[]; | projects: ResourceSummaryResult[]; | ||||
@@ -19,7 +20,7 @@ type SearchParamNames = keyof SearchQuery; | |||||
const ProjectResourceSummarySearch: React.FC<Props> = ({ projects }) => { | const ProjectResourceSummarySearch: React.FC<Props> = ({ projects }) => { | ||||
const { t } = useTranslation("projects"); | |||||
const { t } = useTranslation("dashboard"); | |||||
const router = useRouter(); | const router = useRouter(); | ||||
const searchParams = useSearchParams() | const searchParams = useSearchParams() | ||||
// If project searching is done on the server-side, then no need for this. | // If project searching is done on the server-side, then no need for this. | ||||
@@ -27,10 +28,10 @@ const ProjectResourceSummarySearch: React.FC<Props> = ({ projects }) => { | |||||
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | ||||
() => [ | () => [ | ||||
{ label: "Project Code", paramName: "projectCode", type: "text" }, | |||||
{ label: "Project Name", paramName: "projectName", type: "text" }, | |||||
{ label: "Client Code", paramName: "customerCode", type: "text" }, | |||||
{ label: "Client Name", paramName: "customerName", type: "text" }, | |||||
{ label: t("Project Code"), paramName: "projectCode", type: "text" }, | |||||
{ label: t("Project Name"), paramName: "projectName", type: "text" }, | |||||
{ label: t("Client Code"), paramName: "customerCode", type: "text" }, | |||||
{ label: t("Client Name"), paramName: "customerName", type: "text" }, | |||||
], | ], | ||||
[t], | [t], | ||||
); | ); | ||||
@@ -51,7 +52,7 @@ const ProjectResourceSummarySearch: React.FC<Props> = ({ projects }) => { | |||||
() => [ | () => [ | ||||
{ | { | ||||
name: "id", | name: "id", | ||||
label: t("View"), | |||||
label: t("Details"), | |||||
onClick: onTaskClick, | onClick: onTaskClick, | ||||
buttonIcon: <ArticleIcon />, | buttonIcon: <ArticleIcon />, | ||||
}, | }, | ||||
@@ -66,6 +67,9 @@ const ProjectResourceSummarySearch: React.FC<Props> = ({ projects }) => { | |||||
return ( | return ( | ||||
<> | <> | ||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
{t("Project Resource Summary")} | |||||
</Typography> | |||||
<SearchBox | <SearchBox | ||||
criteria={searchCriteria} | criteria={searchCriteria} | ||||
onSearch={(query) => { | onSearch={(query) => { | ||||
@@ -35,6 +35,7 @@ import { fetchTeamCombo, fetchweeklyTeamTotalManhours, fetchmonthlyTeamTotalManh | |||||
import { SessionStaff } from "@/config/authConfig"; | import { SessionStaff } from "@/config/authConfig"; | ||||
import { VIEW_DASHBOARD_ALL } from "@/middleware"; | import { VIEW_DASHBOARD_ALL } from "@/middleware"; | ||||
import { QrCode } from "@mui/icons-material"; | import { QrCode } from "@mui/icons-material"; | ||||
import Typography from "@mui/material/Typography"; | |||||
dayjs.extend(isBetweenPlugin); | dayjs.extend(isBetweenPlugin); | ||||
interface CustomPickerDayProps extends PickersDayProps<Dayjs> { | interface CustomPickerDayProps extends PickersDayProps<Dayjs> { | ||||
@@ -104,6 +105,7 @@ interface Props { | |||||
} | } | ||||
const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | ||||
const { t } = useTranslation("dashboard"); | |||||
const abilityViewDashboardAll = abilities.includes(VIEW_DASHBOARD_ALL) | const abilityViewDashboardAll = abilities.includes(VIEW_DASHBOARD_ALL) | ||||
const todayDate = new Date(); | const todayDate = new Date(); | ||||
@@ -275,8 +277,8 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
const [totalLeaveHours, setTotalLeaveHours]: any = React.useState('NA'); | const [totalLeaveHours, setTotalLeaveHours]: any = React.useState('NA'); | ||||
const [currentPage, setCurrentPage] = useState(1); | const [currentPage, setCurrentPage] = useState(1); | ||||
const recordsPerPage = 10; | const recordsPerPage = 10; | ||||
const [datePickerToLabel, setDatePickerToLabel] = React.useState("To"); | |||||
const [datePickerToLabel2, setDatePickerToLabel2] = React.useState("To"); | |||||
const [datePickerToLabel, setDatePickerToLabel] = React.useState(t("To")); | |||||
const [datePickerToLabel2, setDatePickerToLabel2] = React.useState(t("To")); | |||||
const fetchComboData = async () => { | const fetchComboData = async () => { | ||||
const staffComboList = [] | const staffComboList = [] | ||||
@@ -812,7 +814,10 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
yaxis: [ | yaxis: [ | ||||
{ | { | ||||
title: { | title: { | ||||
text: "Team Total Manhours Spent (Hour)", | |||||
text: t("Team Total Manhours Spent (Hours)"), | |||||
style: { | |||||
fontSize: "14px" | |||||
} | |||||
}, | }, | ||||
min: 0, | min: 0, | ||||
max: totalManHoursMaxValue, | max: totalManHoursMaxValue, | ||||
@@ -830,13 +835,13 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
annotations: {}, | annotations: {}, | ||||
series: [ | series: [ | ||||
{ | { | ||||
name: "Planned", | |||||
name: t("Planned"), | |||||
type: "line", | type: "line", | ||||
color: "#efbe7d", | color: "#efbe7d", | ||||
data: teamTotalManhoursSpentPlanData, | data: teamTotalManhoursSpentPlanData, | ||||
}, | }, | ||||
{ | { | ||||
name: "Actual", | |||||
name: t("Actual"), | |||||
type: "line", | type: "line", | ||||
color: "#7cd3f2", | color: "#7cd3f2", | ||||
data: teamTotalManhoursSpentActualData, | data: teamTotalManhoursSpentActualData, | ||||
@@ -867,7 +872,10 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
yaxis: [ | yaxis: [ | ||||
{ | { | ||||
title: { | title: { | ||||
text: "Staff Grade", | |||||
text: t("Staff Grade"), | |||||
style: { | |||||
fontSize: "14px" | |||||
} | |||||
}, | }, | ||||
min: 0, | min: 0, | ||||
max: totalManHoursByGradeMaxValue, | max: totalManHoursByGradeMaxValue, | ||||
@@ -880,13 +888,13 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
annotations: {}, | annotations: {}, | ||||
series: [ | series: [ | ||||
{ | { | ||||
name: "Planned", | |||||
name: t("Planned"), | |||||
type: "bar", | type: "bar", | ||||
color: "#efbe7d", | color: "#efbe7d", | ||||
data: totalManhourByGradePlannedManhours, | data: totalManhourByGradePlannedManhours, | ||||
}, | }, | ||||
{ | { | ||||
name: "Actual", | |||||
name: t("Actual"), | |||||
type: "bar", | type: "bar", | ||||
color: "#00acb1", | color: "#00acb1", | ||||
data: totalManhourByGradeActualManhours, | data: totalManhourByGradeActualManhours, | ||||
@@ -917,7 +925,10 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
yaxis: [ | yaxis: [ | ||||
{ | { | ||||
title: { | title: { | ||||
text: "Project", | |||||
text: t("Project"), | |||||
style: { | |||||
fontSize: "14px" | |||||
} | |||||
}, | }, | ||||
min: 0, | min: 0, | ||||
max: individualManhoursMaxValue, | max: individualManhoursMaxValue, | ||||
@@ -937,7 +948,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
}, | }, | ||||
series: [ | series: [ | ||||
{ | { | ||||
name: "Manhours(Hour)", | |||||
name: t("Manhours (Hour)"), | |||||
type: "bar", | type: "bar", | ||||
color: "#00acb1", | color: "#00acb1", | ||||
data: individualStaffManhours, | data: individualStaffManhours, | ||||
@@ -968,7 +979,10 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
yaxis: [ | yaxis: [ | ||||
{ | { | ||||
title: { | title: { | ||||
text: "Staff", | |||||
text: t("Staff"), | |||||
style: { | |||||
fontSize: "14px" | |||||
} | |||||
}, | }, | ||||
min: 0, | min: 0, | ||||
max: unsubmittedMaxValue, | max: unsubmittedMaxValue, | ||||
@@ -981,7 +995,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
annotations: {}, | annotations: {}, | ||||
series: [ | series: [ | ||||
{ | { | ||||
name: "Unsubmitted Time Sheet", | |||||
name: t("Unsubmitted Time Sheet"), | |||||
type: "bar", | type: "bar", | ||||
color: "#00acb1", | color: "#00acb1", | ||||
data: currentPageunsubmitCount, | data: currentPageunsubmitCount, | ||||
@@ -1325,20 +1339,23 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
return ( | return ( | ||||
<> | <> | ||||
<Grid item sm> | <Grid item sm> | ||||
<div style={{ display: "inline-block", width: "40%" }}> | |||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
{t("Staff Utilization")} | |||||
</Typography> | |||||
<div style={{ display: "inline-block", width: "40%" }} className={"mt-5"}> | |||||
<div> | <div> | ||||
<Grid item xs={12} md={12} lg={12}> | <Grid item xs={12} md={12} lg={12}> | ||||
<Card> | <Card> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Team Total Manhours Spent" | |||||
title= {t("Team Total Manhours Spent")} | |||||
/> | /> | ||||
<div style={{ display: "inline-block", width: "99%" }}> | <div style={{ display: "inline-block", width: "99%" }}> | ||||
<div className="w-fit align-top mr-5 float-right"> | <div className="w-fit align-top mr-5 float-right"> | ||||
{teamTotalManhoursSpentSelect === "Weekly" && ( | {teamTotalManhoursSpentSelect === "Weekly" && ( | ||||
<> | <> | ||||
<button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid rounded-l-md w-32"> | <button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid rounded-l-md w-32"> | ||||
Weekly | |||||
{t("Weekly")} | |||||
</button> | </button> | ||||
<button | <button | ||||
onClick={() => { | onClick={() => { | ||||
@@ -1353,7 +1370,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
} | } | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid rounded-r-md w-32" | className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid rounded-r-md w-32" | ||||
> | > | ||||
Monthly | |||||
{t("Monthly")} | |||||
</button> | </button> | ||||
</> | </> | ||||
)} | )} | ||||
@@ -1372,10 +1389,10 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
} | } | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid rounded-l-md w-32" | className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid rounded-l-md w-32" | ||||
> | > | ||||
Weekly | |||||
{t("Weekly")} | |||||
</button> | </button> | ||||
<button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid rounded-r-md w-32"> | <button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid rounded-r-md w-32"> | ||||
Monthly | |||||
{t("Monthly")} | |||||
</button> | </button> | ||||
</> | </> | ||||
)} | )} | ||||
@@ -1385,12 +1402,12 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
<div className="inline-block"> | <div className="inline-block"> | ||||
<div className="inline-block ml-6"> | <div className="inline-block ml-6"> | ||||
<Label className="text-slate-500 font-medium"> | <Label className="text-slate-500 font-medium"> | ||||
Team: | |||||
{t("Team")}: | |||||
</Label> | </Label> | ||||
</div> | </div> | ||||
<div className="inline-block ml-1 w-60"> | <div className="inline-block ml-1 w-60"> | ||||
<Select | <Select | ||||
placeholder="Please select a team" | |||||
placeholder={t("Please select a team")} | |||||
options={teamManhoursTeamOptions} | options={teamManhoursTeamOptions} | ||||
isClearable={true} | isClearable={true} | ||||
onChange={(selectedOption: any) => { | onChange={(selectedOption: any) => { | ||||
@@ -1404,7 +1421,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
setDatePickerToLabel("") | setDatePickerToLabel("") | ||||
}} | }} | ||||
onMenuClose={() => { | onMenuClose={() => { | ||||
setDatePickerToLabel("To") | |||||
setDatePickerToLabel(t("To")) | |||||
}} | }} | ||||
/> | /> | ||||
</div> | </div> | ||||
@@ -1417,7 +1434,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
<LocalizationProvider dateAdapter={AdapterDayjs}> | <LocalizationProvider dateAdapter={AdapterDayjs}> | ||||
<DatePicker | <DatePicker | ||||
className="w-72 h-10 align-top" | className="w-72 h-10 align-top" | ||||
label="Period:" | |||||
label= {t("Week") + ":"} | |||||
value={value} | value={value} | ||||
format="DD-MM-YYYY" | format="DD-MM-YYYY" | ||||
onChange={(newValue) => { | onChange={(newValue) => { | ||||
@@ -1448,8 +1465,9 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
selectMonthlyPeriodFrom(newValue) | selectMonthlyPeriodFrom(newValue) | ||||
} | } | ||||
defaultValue={totalManHoursMonthlyFromValue} | defaultValue={totalManHoursMonthlyFromValue} | ||||
label={"From"} | |||||
label={t("From")} | |||||
views={["month", "year"]} | views={["month", "year"]} | ||||
format="MM-YYYY" | |||||
/> | /> | ||||
<DatePicker | <DatePicker | ||||
className="w-40 h-10 align-top" | className="w-40 h-10 align-top" | ||||
@@ -1459,6 +1477,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
defaultValue={totalManHoursMonthlyToValue} | defaultValue={totalManHoursMonthlyToValue} | ||||
label={datePickerToLabel} | label={datePickerToLabel} | ||||
views={["month", "year"]} | views={["month", "year"]} | ||||
format="MM-YYYY" | |||||
/> | /> | ||||
</LocalizationProvider> | </LocalizationProvider> | ||||
)} | )} | ||||
@@ -1480,14 +1499,14 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
<Card> | <Card> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Total Manhours Spent by Staff Grade" | |||||
title= {t("Total Manhours Spent by Staff Grade")} | |||||
/> | /> | ||||
<div style={{ display: "inline-block", width: "99%" }}> | <div style={{ display: "inline-block", width: "99%" }}> | ||||
<div className="w-fit align-top mr-5 float-right"> | <div className="w-fit align-top mr-5 float-right"> | ||||
{staffGradeManhoursSpentSelect === "Weekly" && ( | {staffGradeManhoursSpentSelect === "Weekly" && ( | ||||
<> | <> | ||||
<button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid rounded-l-md w-32"> | <button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid rounded-l-md w-32"> | ||||
Weekly | |||||
{t("Weekly")} | |||||
</button> | </button> | ||||
<button | <button | ||||
onClick={() => { | onClick={() => { | ||||
@@ -1502,7 +1521,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
} | } | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid rounded-r-md w-48" | className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid rounded-r-md w-48" | ||||
> | > | ||||
Monthly | |||||
{t("Monthly")} | |||||
</button> | </button> | ||||
</> | </> | ||||
)} | )} | ||||
@@ -1521,10 +1540,10 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
} | } | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid rounded-l-md w-32" | className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid rounded-l-md w-32" | ||||
> | > | ||||
Weekly | |||||
{t("Weekly")} | |||||
</button> | </button> | ||||
<button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid rounded-r-md w-48"> | <button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid rounded-r-md w-48"> | ||||
Monthly | |||||
{t("Monthly")} | |||||
</button> | </button> | ||||
</> | </> | ||||
)} | )} | ||||
@@ -1534,12 +1553,12 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
<div className="inline-block"> | <div className="inline-block"> | ||||
<div className="inline-block ml-6"> | <div className="inline-block ml-6"> | ||||
<Label className="text-slate-500 font-medium"> | <Label className="text-slate-500 font-medium"> | ||||
Team: | |||||
{t("Team")}: | |||||
</Label> | </Label> | ||||
</div> | </div> | ||||
<div className="inline-block ml-1 w-60"> | <div className="inline-block ml-1 w-60"> | ||||
<Select | <Select | ||||
placeholder="Please select a team" | |||||
placeholder={t("Please select a team")} | |||||
options={teamManhoursTeamOptions} | options={teamManhoursTeamOptions} | ||||
isClearable={true} | isClearable={true} | ||||
onChange={(selectedOption: any) => { | onChange={(selectedOption: any) => { | ||||
@@ -1553,7 +1572,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
setDatePickerToLabel2("") | setDatePickerToLabel2("") | ||||
}} | }} | ||||
onMenuClose={() => { | onMenuClose={() => { | ||||
setDatePickerToLabel2("To") | |||||
setDatePickerToLabel2(t("To")) | |||||
}} | }} | ||||
/> | /> | ||||
</div> | </div> | ||||
@@ -1563,7 +1582,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
<LocalizationProvider dateAdapter={AdapterDayjs}> | <LocalizationProvider dateAdapter={AdapterDayjs}> | ||||
<DatePicker | <DatePicker | ||||
className="w-72 h-10 align-top" | className="w-72 h-10 align-top" | ||||
label="Period:" | |||||
label={t("Week") + ":"} | |||||
value={weeklyValueByStaffGrade} | value={weeklyValueByStaffGrade} | ||||
format="DD-MM-YYYY" | format="DD-MM-YYYY" | ||||
onChange={(newValue) => | onChange={(newValue) => | ||||
@@ -1596,8 +1615,9 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
defaultValue={ | defaultValue={ | ||||
totalManHoursByStaffGradeMonthlyFromValue | totalManHoursByStaffGradeMonthlyFromValue | ||||
} | } | ||||
label={"From"} | |||||
label={t("From")} | |||||
views={["month", "year"]} | views={["month", "year"]} | ||||
format="MM-YYYY" | |||||
/> | /> | ||||
<DatePicker | <DatePicker | ||||
className="w-40 h-10 align-top" | className="w-40 h-10 align-top" | ||||
@@ -1609,6 +1629,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
} | } | ||||
label={datePickerToLabel2} | label={datePickerToLabel2} | ||||
views={["month", "year"]} | views={["month", "year"]} | ||||
format="MM-YYYY" | |||||
/> | /> | ||||
</LocalizationProvider> | </LocalizationProvider> | ||||
)} | )} | ||||
@@ -1642,19 +1663,20 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
verticalAlign: "top", | verticalAlign: "top", | ||||
marginLeft: 10, | marginLeft: 10, | ||||
}} | }} | ||||
className="mt-5" | |||||
> | > | ||||
<Grid item xs={12} md={12} lg={12}> | <Grid item xs={12} md={12} lg={12}> | ||||
<Card className="mb-5"> | <Card className="mb-5"> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Unsubmitted Time Sheet by Staff" | |||||
title= {t("Unsubmitted Time Sheet by Staff")} | |||||
/> | /> | ||||
<div style={{ display: "inline-block", width: "99%" }}> | <div style={{ display: "inline-block", width: "99%" }}> | ||||
<div className="w-fit align-top mr-5 float-right"> | <div className="w-fit align-top mr-5 float-right"> | ||||
{unsubmittedTimeSheetSelect === "Weekly" && ( | {unsubmittedTimeSheetSelect === "Weekly" && ( | ||||
<> | <> | ||||
<button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid w-32"> | <button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid w-32"> | ||||
Weekly | |||||
{t("Weekly")} | |||||
</button> | </button> | ||||
<button | <button | ||||
onClick={() => { | onClick={() => { | ||||
@@ -1669,7 +1691,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
} | } | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid rounded-r-md w-32" | className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid rounded-r-md w-32" | ||||
> | > | ||||
Monthly | |||||
{t("Monthly")} | |||||
</button> | </button> | ||||
</> | </> | ||||
)} | )} | ||||
@@ -1688,10 +1710,10 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
} | } | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid w-32" | className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid w-32" | ||||
> | > | ||||
Weekly | |||||
{t("Weekly")} | |||||
</button> | </button> | ||||
<button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid rounded-r-md w-32"> | <button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid rounded-r-md w-32"> | ||||
Monthly | |||||
{t("Monthly")} | |||||
</button> | </button> | ||||
</> | </> | ||||
)} | )} | ||||
@@ -1700,12 +1722,12 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
{abilityViewDashboardAll && <div className="inline-block"> | {abilityViewDashboardAll && <div className="inline-block"> | ||||
<div className="inline-block ml-6"> | <div className="inline-block ml-6"> | ||||
<Label className="text-slate-500 font-medium"> | <Label className="text-slate-500 font-medium"> | ||||
Team: | |||||
{t("Team")}: | |||||
</Label> | </Label> | ||||
</div> | </div> | ||||
<div className="inline-block ml-1 w-60"> | <div className="inline-block ml-1 w-60"> | ||||
<Select | <Select | ||||
placeholder="Please select a team" | |||||
placeholder={t("Please select a team")} | |||||
options={teamManhoursTeamOptions} | options={teamManhoursTeamOptions} | ||||
isClearable={true} | isClearable={true} | ||||
onChange={(selectedOption: any) => { | onChange={(selectedOption: any) => { | ||||
@@ -1727,7 +1749,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
<LocalizationProvider dateAdapter={AdapterDayjs}> | <LocalizationProvider dateAdapter={AdapterDayjs}> | ||||
<DatePicker | <DatePicker | ||||
className="w-72 h-10 align-top" | className="w-72 h-10 align-top" | ||||
label="Period:" | |||||
label={t("Week") + ":"} | |||||
value={value} | value={value} | ||||
format="DD-MM-YYYY" | format="DD-MM-YYYY" | ||||
onChange={(newValue) => | onChange={(newValue) => | ||||
@@ -1759,8 +1781,9 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
defaultValue={ | defaultValue={ | ||||
unsubmitMonthlyFromValue | unsubmitMonthlyFromValue | ||||
} | } | ||||
label={"On"} | |||||
label={t("Month") + ":"} | |||||
views={["month", "year"]} | views={["month", "year"]} | ||||
format="MM-YYYY" | |||||
/> | /> | ||||
{/* <DatePicker | {/* <DatePicker | ||||
className="w-40 h-10 align-top" | className="w-40 h-10 align-top" | ||||
@@ -1787,25 +1810,25 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
<div className="float-right mr-4 mb-10"> | <div className="float-right mr-4 mb-10"> | ||||
{currentPage === 1 && ( | {currentPage === 1 && ( | ||||
<button className="bg-lime-600 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-l"> | <button className="bg-lime-600 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-l"> | ||||
Pervious | |||||
{t("Previous")} | |||||
</button> | </button> | ||||
)} | )} | ||||
{currentPage !== 1 && ( | {currentPage !== 1 && ( | ||||
<button onClick={handlePrevPage} className="bg-lime-600 hover:bg-lime-700 text-white font-bold py-2 px-4 outline-none rounded-l"> | <button onClick={handlePrevPage} className="bg-lime-600 hover:bg-lime-700 text-white font-bold py-2 px-4 outline-none rounded-l"> | ||||
Previous | |||||
{t("Previous")} | |||||
</button> | </button> | ||||
)} | )} | ||||
{endIndex >= unsubmitCount.length && ( | {endIndex >= unsubmitCount.length && ( | ||||
<button className="bg-lime-600 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-r mr-2"> | <button className="bg-lime-600 text-white font-bold py-2 px-4 opacity-50 cursor-not-allowed rounded-r mr-2"> | ||||
Next | |||||
{t("Next")} | |||||
</button> | </button> | ||||
)} | )} | ||||
{endIndex < unsubmitCount.length && ( | {endIndex < unsubmitCount.length && ( | ||||
<button onClick={handleNextPage} className="bg-lime-600 hover:bg-lime-700 text-white font-bold py-2 px-4 outline-none rounded-r mr-2"> | <button onClick={handleNextPage} className="bg-lime-600 hover:bg-lime-700 text-white font-bold py-2 px-4 outline-none rounded-r mr-2"> | ||||
Next | |||||
{t("Next")} | |||||
</button> | </button> | ||||
)} | )} | ||||
Page | |||||
{t("Page")} | |||||
{unsubmitCount.length === 0 && ( | {unsubmitCount.length === 0 && ( | ||||
0 | 0 | ||||
)} | )} | ||||
@@ -1822,7 +1845,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
<Card> | <Card> | ||||
<CardHeader | <CardHeader | ||||
className="text-slate-500" | className="text-slate-500" | ||||
title="Manhours Spent by Individual Staff" | |||||
title={t("Manhours Spent by Individual Staff")} | |||||
/> | /> | ||||
<div style={{ display: "inline-block", width: "99%" }}> | <div style={{ display: "inline-block", width: "99%" }}> | ||||
<div className="w-fit align-top mr-5 float-right"> | <div className="w-fit align-top mr-5 float-right"> | ||||
@@ -1839,7 +1862,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
} | } | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid w-32" | className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid w-32" | ||||
> | > | ||||
Weekly | |||||
{t("Weekly")} | |||||
</button> | </button> | ||||
<button | <button | ||||
onClick={() => { | onClick={() => { | ||||
@@ -1849,7 +1872,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
} | } | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid rounded-r-md w-32" | className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid rounded-r-md w-32" | ||||
> | > | ||||
Monthly | |||||
{t("Monthly")} | |||||
</button> | </button> | ||||
</> | </> | ||||
)} | )} | ||||
@@ -1866,7 +1889,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
Daily | Daily | ||||
</button> */} | </button> */} | ||||
<button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid w-32"> | <button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid w-32"> | ||||
Weekly | |||||
{t("Weekly")} | |||||
</button> | </button> | ||||
<button | <button | ||||
onClick={() => { | onClick={() => { | ||||
@@ -1881,7 +1904,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
} | } | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid rounded-r-md w-32" | className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid rounded-r-md w-32" | ||||
> | > | ||||
Monthly | |||||
{t("Monthly")} | |||||
</button> | </button> | ||||
</> | </> | ||||
)} | )} | ||||
@@ -1910,10 +1933,10 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
} | } | ||||
className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid w-32" | className="hover:cursor-pointer hover:bg-lime-50 text-lg bg-transparent border-lime-600 text-lime-600 border-solid w-32" | ||||
> | > | ||||
Weekly | |||||
{t("Weekly")} | |||||
</button> | </button> | ||||
<button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid rounded-r-md w-32"> | <button className="text-lg bg-lime-100 border-lime-600 text-lime-600 border-solid rounded-r-md w-32"> | ||||
Monthly | |||||
{t("Monthly")} | |||||
</button> | </button> | ||||
</> | </> | ||||
)} | )} | ||||
@@ -1921,12 +1944,12 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
<div className="inline-block w-fit mt-2"> | <div className="inline-block w-fit mt-2"> | ||||
<div className="inline-block ml-6"> | <div className="inline-block ml-6"> | ||||
<Label className="text-slate-500 font-medium"> | <Label className="text-slate-500 font-medium"> | ||||
Staff Code and Name: | |||||
{t("Staff Code and Name")}: | |||||
</Label> | </Label> | ||||
</div> | </div> | ||||
<div className="inline-block ml-1 w-60"> | <div className="inline-block ml-1 w-60"> | ||||
<Select | <Select | ||||
placeholder="Please select a staff" | |||||
placeholder={t("Please select a staff")} | |||||
options={staffOptions} | options={staffOptions} | ||||
isClearable={true} | isClearable={true} | ||||
onChange={(selectedOption: any) => { | onChange={(selectedOption: any) => { | ||||
@@ -1954,7 +1977,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
defaultValue={ | defaultValue={ | ||||
totalManHoursByIndividualStaffDailyFromValue | totalManHoursByIndividualStaffDailyFromValue | ||||
} | } | ||||
label={"On"} | |||||
label={t("On")} | |||||
views={["day"]} | views={["day"]} | ||||
/> | /> | ||||
{/* <DatePicker | {/* <DatePicker | ||||
@@ -1974,7 +1997,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
<LocalizationProvider dateAdapter={AdapterDayjs}> | <LocalizationProvider dateAdapter={AdapterDayjs}> | ||||
<DatePicker | <DatePicker | ||||
className="w-72 h-10 align-top" | className="w-72 h-10 align-top" | ||||
label="Period:" | |||||
label={t("Week") + ":"} | |||||
value={value} | value={value} | ||||
format="DD-MM-YYYY" | format="DD-MM-YYYY" | ||||
onChange={(newValue) => | onChange={(newValue) => | ||||
@@ -2009,8 +2032,9 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
defaultValue={ | defaultValue={ | ||||
indivdualManHoursMonthlyFromValue | indivdualManHoursMonthlyFromValue | ||||
} | } | ||||
label={"On"} | |||||
label={t("Month") + ":"} | |||||
views={["month", "year"]} | views={["month", "year"]} | ||||
format="MM-YYYY" | |||||
/> | /> | ||||
{/* <DatePicker | {/* <DatePicker | ||||
className="w-40 h-10 align-top" | className="w-40 h-10 align-top" | ||||
@@ -2047,7 +2071,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
> | > | ||||
<Card style={{ height: 90 }}> | <Card style={{ height: 90 }}> | ||||
<div className="text-slate-500 text-center text-base"> | <div className="text-slate-500 text-center text-base"> | ||||
Total Normal Hours Spent | |||||
{t("Total Normal Hours Spent")} | |||||
</div> | </div> | ||||
<div | <div | ||||
className="text-center w-full text-3xl font-bold" | className="text-center w-full text-3xl font-bold" | ||||
@@ -2058,7 +2082,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
</Card> | </Card> | ||||
<Card style={{ marginTop: 10, height: 90 }}> | <Card style={{ marginTop: 10, height: 90 }}> | ||||
<div className="text-slate-500 text-center text-base"> | <div className="text-slate-500 text-center text-base"> | ||||
Total Leave Hours | |||||
{t("Total Leave Hours")} | |||||
</div> | </div> | ||||
<div | <div | ||||
className="text-center w-full text-3xl font-bold" | className="text-center w-full text-3xl font-bold" | ||||
@@ -2079,7 +2103,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
> | > | ||||
<Card style={{ height: 90 }}> | <Card style={{ height: 90 }}> | ||||
<div className="text-slate-500 text-center text-base"> | <div className="text-slate-500 text-center text-base"> | ||||
Total Other Hours Spent | |||||
{t("Total Other Hours Spent")} | |||||
</div> | </div> | ||||
<div | <div | ||||
className="text-center w-full text-3xl font-bold" | className="text-center w-full text-3xl font-bold" | ||||
@@ -2103,7 +2127,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "50%", verticalAlign: "top", marginTop: 10 }}> | <div style={{ display: "inline-block", width: "50%", verticalAlign: "top", marginTop: 10 }}> | ||||
<Card> | <Card> | ||||
<CardHeader className="text-slat-500" title="Effort Proportion for individual Staff" /> | |||||
<CardHeader className="text-slat-500" title= {t("Effort Proportion for individual Staff")} /> | |||||
<ReactApexChart | <ReactApexChart | ||||
options={options2} | options={options2} | ||||
series={options2.series} | series={options2.series} | ||||
@@ -30,5 +30,16 @@ | |||||
"Submit": "Submit", | "Submit": "Submit", | ||||
"Save": "Save", | "Save": "Save", | ||||
"Save And Submit": "Save And Submit", | "Save And Submit": "Save And Submit", | ||||
"Reset": "Reset" | |||||
"Reset": "Reset", | |||||
"Overview": "Overview", | |||||
"Dashboard": "Dashboard", | |||||
"Financial Summary": "Financial Summary", | |||||
"Company / Team Cash Flow": "Company / Team Cash Flow", | |||||
"Project Cash Flow": "Project Cash Flow", | |||||
"Project Status by Client": "Project Status by Client", | |||||
"Project Status by Team": "Project Status by Team", | |||||
"Project Resource Consumption Ranking": "Project Resource Consumption Ranking", | |||||
"Staff Utilization": "Staff Utilization", | |||||
"Project Resource Summary": "Project Resource Summary" | |||||
} | } |
@@ -1 +1,159 @@ | |||||
{} | |||||
{ | |||||
"Financial Summary": "Financial Summary", | |||||
"Active Project Financial Status": "Active Project Financial Status", | |||||
"All Team": "All Team", | |||||
"Total Active Project": "Total Active Project", | |||||
"Total Fees": "Total Fees", | |||||
"Total Budget": "Total Budget", | |||||
"Total Cumulative Expenditure": "Total Cumulative Expenditure", | |||||
"Total Invoiced Amount": "Total Invoiced Amount", | |||||
"Total Un-Invoiced Amount": "Total Un-Invoiced Amount", | |||||
"Total Received Amount": "Total Received Amount", | |||||
"Cash Flow Status": "Cash Flow Status", | |||||
"Cost Performance Index": "Cost Peformance Index", | |||||
"Projected Cash Flow Status": "Projected Cash Flow Status", | |||||
"Projected Cost Performance Index": "Projected Cost Peformance Index", | |||||
"Formula": "Formula", | |||||
"Invoiced Amount": "Invoiced Amount", | |||||
"Cumulative Expenditure": "Cumulative Expenditure", | |||||
"Positive when CPI": "Positive when CPI >= 1", | |||||
"Projected CPI": "Projected CPI", | |||||
"Project Fee": "Project Fee", | |||||
"Positive when Projected CPI": "Positive when Projected CPI >= 1", | |||||
"Financial Status (by Project)": "Financial Status (by Project)", | |||||
"Financial Status (by Client)": "Financial Status (by Client)", | |||||
"Project Code": "Project Code", | |||||
"Project Name": "Project Name", | |||||
"Client Code": "Client Code", | |||||
"Client Name": "Client Name", | |||||
"Subsidiary": "Subsidiary", | |||||
"Total Project Involved": "Total Project Involved", | |||||
"HKD": "(HKD)", | |||||
"Negative": "Negative", | |||||
"Positive": "Positive", | |||||
"Export Excel": "Export Excel", | |||||
"Company / Team Cash Flow": "Company / Team Cash Flow", | |||||
"Company and Team Cash Flow By Month": "Company and Team Cash Flow By Month", | |||||
"Year": "Year", | |||||
"Team": "Team", | |||||
"Monthly Income and Expenditure (HKD)": "Monthly Income and Expenditure (HKD)", | |||||
"Cumulative Income and Expenditure (HKD)": "Cumulative Income and Expenditure (HKD)", | |||||
"Monthly Income": "Monthly Income", | |||||
"Monthly Expenditure": "Monthly Expenditure", | |||||
"Cumulative Income": "Cumulative Income", | |||||
"JAN": "JAN", | |||||
"FEB": "FEB", | |||||
"MAR": "MAR", | |||||
"APR": "APR", | |||||
"MAY": "MAY", | |||||
"JUN": "JUN", | |||||
"JUL": "JUL", | |||||
"AUG": "AUG", | |||||
"SEP": "SEP", | |||||
"OCT": "OCT", | |||||
"NOV": "NOV", | |||||
"DEC": "DEC", | |||||
"Project Cash Flow": "Project Cash Flow", | |||||
"Start Date From": "Start Date From", | |||||
"Start Date To": "Start Date To", | |||||
"Team Leader": "Team Leader", | |||||
"Start Date": "Start Date", | |||||
"Target End Date": "Target End Date", | |||||
"Client": "Client", | |||||
"Project Cash Flow by Month": "Project Cash Flow by Month", | |||||
"Accounts Receivable (HKD)": "Accounts Receivable (HKD)", | |||||
"Accounts Receivable": "Accounts Receivable", | |||||
"Receivable (HKD)": "Receivable (HKD)", | |||||
"Receivable": "Receivable", | |||||
"Invoiced": "Invoiced", | |||||
"Total Project Fee": "Total Project Fee", | |||||
"Expenditure": "Expenditure", | |||||
"Remaining Budget": "Remaining Budget", | |||||
"Anticipate Cash Flow by Month": "Anticipate Cash Flow by Month", | |||||
"Anticipate Monthly Income and Expenditure": "Anticipate Monthly Income and Expenditure", | |||||
"Cash Flow Ledger by Month": "Cash Flow Ledger by Month", | |||||
"Date": "Date", | |||||
"Expenditure (HKD)": "Expenditure (HKD)", | |||||
"Income (HKD)": "Income (HKD)", | |||||
"Cash Flow Balance (HKD)": "Cash Flow Balance (HKD)", | |||||
"Remarks": "Remarks", | |||||
"Project Status by Client": "Project Status by Client", | |||||
"Details": "Details", | |||||
"Subsidiary Code": "Subsidiary Code", | |||||
"No. of Projects": "No. of Projects", | |||||
"Project Resource Consumption": "Project Resource Consumption", | |||||
"Sorting": "Sorting", | |||||
"Percentage (Ascending Order)": "Percentage (Ascending Order)", | |||||
"Percentage (Descending Order)": "Percentage (Descending Order)", | |||||
"Project Resource Consumption Percentage": "Project Resource Consumption Percentage", | |||||
"Project Resource Consumption Percentage (%)": "Project Resource Consumption Percentage (%)", | |||||
"Projects": "Projects", | |||||
"Overall Progress per Project": "Overall Progress per Project", | |||||
"Please select the project you want to check.": "Please select the project you want to check.", | |||||
"Spent": "Spent", | |||||
"Resource Consumption and Coming Milestones": "Resource Consumption and Coming Milestones", | |||||
"Expected Stage": "Expected Stage", | |||||
"Budgeted Manhours": "Budgeted Manhours", | |||||
"Spent Manhours": "Spent Manhours", | |||||
"Remained Manhours": "Remained Manhours", | |||||
"Coming Payment Milestones": "Coming Payment Milestones", | |||||
"Alert": "Alert", | |||||
"Project Budget Manhours": "Project Budget Manhours", | |||||
"Actual Manhours Spent": "Actual Manhours Spent", | |||||
"Last Update": "Last Update", | |||||
"Previous": "Previous", | |||||
"Next": "Next", | |||||
"Page": "Page", | |||||
"Project Status by Team": "Project Status by Team", | |||||
"Team Code": "Team Code", | |||||
"Team Name": "Team Name", | |||||
"Project Resource Consumption Ranking": "Project Resource Consumption Ranking", | |||||
"Staff Utilization": "Staff Utilization", | |||||
"Team Total Manhours Spent": "Team Total Manhours Spent", | |||||
"Weekly": "Weekly", | |||||
"Monthly": "Monthly", | |||||
"Please select a team": "Please select a team", | |||||
"From": "From", | |||||
"To": "To", | |||||
"Team Total Manhours Spent (Hours)": "Team Total Manhours Spent (Hours)", | |||||
"Planned": "Planned", | |||||
"Actual": "Actual", | |||||
"Unsubmitted Time Sheet by Staff": "Unsubmitted Time Sheet by Staff", | |||||
"Unsubmitted Time Sheet": "Unsubmitted Time Sheet", | |||||
"On": "On", | |||||
"Staff": "Staff", | |||||
"Total Manhours Spent by Staff Grade": "Total Manhours Spent by Staff Grade", | |||||
"Staff Grade": "Staff Grade", | |||||
"Manhours Spent by Individual Staff": "Manhours Spent by Individual Staff", | |||||
"Staff Code and Name": "Staff Code and Name", | |||||
"Please select a staff": "Please select a staff", | |||||
"Total Normal Hours Spent": "Total Normal Hours Spent", | |||||
"Total Other Hours Spent": "Total Other Hours Spent", | |||||
"Total Leave Hours": "Total Leave Hours", | |||||
"Effort Proportion for individual Staff": "Effort Proportion for individual Staff", | |||||
"Week": "Week", | |||||
"Month": "Month", | |||||
"Project": "Project", | |||||
"Manhours (Hour)": "Manhours (Hour)", | |||||
"Project Resource Summary": "Project Resource Summary", | |||||
"Client Code And Name": "Client Code And Name", | |||||
"Subsidiary Code And Name": "Subsidiary Code And Name", | |||||
"Project Information": "Project Information", | |||||
"Remaining Resources": "Remaining Resources", | |||||
"Planned Resources": "Planned Resources", | |||||
"Actual Resources Spent": "Actual Resources Spent", | |||||
"Manhours": "Manhours", | |||||
"Within Budget": "Within Budget", | |||||
"Overconsumption": "Overconsumption", | |||||
"Stage": "Stage", | |||||
"Task Count": "Task Count", | |||||
"Total": "Total", | |||||
"Status": "Status" | |||||
} |
@@ -28,5 +28,16 @@ | |||||
"Submit": "提交", | "Submit": "提交", | ||||
"Save": "儲存", | "Save": "儲存", | ||||
"Save And Submit": "儲存及提交", | "Save And Submit": "儲存及提交", | ||||
"Reset": "重置" | |||||
"Reset": "重置", | |||||
"Overview": "總覽", | |||||
"Dashboard": "儀表板", | |||||
"Financial Summary": "財務摘要", | |||||
"Company / Team Cash Flow": "公司/團隊現金流", | |||||
"Project Cash Flow": "項目現金流", | |||||
"Project Status by Client": "按客戶查看項目狀態", | |||||
"Project Status by Team": "按團隊查看項目狀態", | |||||
"Project Resource Consumption Ranking": "項目資源消耗排名", | |||||
"Staff Utilization": "員工利用率", | |||||
"Project Resource Summary": "項目資源摘要" | |||||
} | } |
@@ -1,3 +1,160 @@ | |||||
{ | { | ||||
"Dashboard": "儀表板" | |||||
"Financial Summary": "財務摘要", | |||||
"Active Project Financial Status": "活躍項目財務狀況", | |||||
"All Team": "所有團隊", | |||||
"Total Active Project": "總活躍項目", | |||||
"Total Fees": "總費用", | |||||
"Total Budget": "總預算", | |||||
"Total Cumulative Expenditure": "累計支出總額", | |||||
"Total Invoiced Amount": "已開發票總額", | |||||
"Total Un-Invoiced Amount": "未開發票總額", | |||||
"Total Received Amount": "已收款總額", | |||||
"Cash Flow Status": "現金流狀況", | |||||
"Cost Performance Index": "成本績效指數", | |||||
"Projected Cash Flow Status": "預計現金流狀況", | |||||
"Projected Cost Performance Index": "預計成本績效指數", | |||||
"Formula": "公式", | |||||
"Invoiced Amount": "已開發票金額", | |||||
"Cumulative Expenditure": "累計支出", | |||||
"Positive when CPI": "當 CPI 大於1時為正數", | |||||
"Projected CPI": "預計 CPI", | |||||
"Project Fee": "項目費用", | |||||
"Positive when Projected CPI": "當預計 CPI 大於1時為正數", | |||||
"Financial Status (by Project)": "財務狀況(按項目)", | |||||
"Financial Status (by Client)": "財務狀況(按客戶)", | |||||
"Project Code": "項目代碼", | |||||
"Project Name": "項目名稱", | |||||
"Client Code": "客戶代碼", | |||||
"Client Name": "客戶名稱", | |||||
"Subsidiary": "子公司", | |||||
"Total Project Involved": "總項目數", | |||||
"HKD": "(港幣)", | |||||
"Negative": "負數", | |||||
"Positive": "正數", | |||||
"Export Excel": "導出 Excel", | |||||
"Company / Team Cash Flow": "公司/團隊現金流", | |||||
"Company and Team Cash Flow By Month": "公司及團隊按月現金流", | |||||
"Year": "年份", | |||||
"Team": "團隊", | |||||
"Monthly Income and Expenditure (HKD)": "月收入與支出(港幣)", | |||||
"Cumulative Income and Expenditure (HKD)": "累計收入與支出(港幣)", | |||||
"Monthly Income": "月收入", | |||||
"Monthly Expenditure": "月支出", | |||||
"Cumulative Income": "累計收入", | |||||
"JAN": "一月", | |||||
"FEB": "二月", | |||||
"MAR": "三月", | |||||
"APR": "四月", | |||||
"MAY": "五月", | |||||
"JUN": "六月", | |||||
"JUL": "七月", | |||||
"AUG": "八月", | |||||
"SEP": "九月", | |||||
"OCT": "十月", | |||||
"NOV": "十一月", | |||||
"DEC": "十二月", | |||||
"Project Cash Flow": "項目現金流", | |||||
"Start Date From": "開始日期從", | |||||
"Start Date To": "開始日期至", | |||||
"Team Leader": "團隊領導", | |||||
"Start Date": "開始日期", | |||||
"Target End Date": "目標結束日期", | |||||
"Client": "客戶", | |||||
"Project Cash Flow by Month": "按月項目現金流", | |||||
"Accounts Receivable (HKD)": "應收賬款(港幣)", | |||||
"Accounts Receivable": "應收賬款", | |||||
"Receivable (HKD)": "應收款(港幣)", | |||||
"Receivable": "應收款", | |||||
"Invoiced": "已開發票", | |||||
"Total Project Fee": "項目總費用", | |||||
"Expenditure": "支出", | |||||
"Remaining Budget": "剩餘預算", | |||||
"Anticipate Cash Flow by Month": "按月預計現金流", | |||||
"Anticipate Monthly Income and Expenditure": "預計月收入與支出", | |||||
"Cash Flow Ledger by Month": "按月現金流賬本", | |||||
"Date": "日期", | |||||
"Expenditure (HKD)": "支出(港幣)", | |||||
"Income (HKD)": "收入(港幣)", | |||||
"Cash Flow Balance (HKD)": "現金流餘額(港幣)", | |||||
"Remarks": "備註", | |||||
"Project Status by Client": "按客戶查看項目狀態", | |||||
"Details": "詳情", | |||||
"Subsidiary Code": "子公司代碼", | |||||
"No. of Projects": "項目數量", | |||||
"Project Resource Consumption": "項目資源消耗", | |||||
"Sorting": "排序", | |||||
"Percentage (Ascending Order)": "百分比(升序)", | |||||
"Percentage (Descending Order)": "百分比(降序)", | |||||
"Project Resource Consumption Percentage": "項目資源消耗百分比", | |||||
"Project Resource Consumption Percentage (%)": "項目資源消耗百分比 (%)", | |||||
"Projects": "項目", | |||||
"Overall Progress per Project": "每個項目的整體進度", | |||||
"Please select the project you want to check.": "請選擇您要查看的項目。", | |||||
"Spent": "已用", | |||||
"Resource Consumption and Coming Milestones": "資源消耗與即將到來的里程碑", | |||||
"Expected Stage": "預計階段", | |||||
"Budgeted Manhours": "預算工時", | |||||
"Spent Manhours": "已用工時", | |||||
"Remained Manhours": "剩餘工時", | |||||
"Remained": "剩餘", | |||||
"Coming Payment Milestones": "即將到來的付款里程碑", | |||||
"Alert": "警告", | |||||
"Project Budget Manhours": "項目預算工時", | |||||
"Actual Manhours Spent": "實際已用工時", | |||||
"Last Update": "最後更新", | |||||
"Previous": "上一頁", | |||||
"Next": "下一頁", | |||||
"Page": "頁", | |||||
"Project Status by Team": "按團隊查看項目狀態", | |||||
"Team Code": "團隊代碼", | |||||
"Team Name": "團隊名稱", | |||||
"Project Resource Consumption Ranking": "項目資源消耗排名", | |||||
"Staff Utilization": "員工利用率", | |||||
"Team Total Manhours Spent": "團隊總工時花費", | |||||
"Weekly": "每週", | |||||
"Monthly": "每月", | |||||
"Please select a team": "請選擇一個團隊", | |||||
"From": "從", | |||||
"To": "到", | |||||
"Team Total Manhours Spent (Hours)": "團隊總工時花費(小時)", | |||||
"Planned": "計劃", | |||||
"Actual": "實際", | |||||
"Unsubmitted Time Sheet by Staff": "員工未提交的時間表", | |||||
"Unsubmitted Time Sheet": "未提交的時間表", | |||||
"On": "於", | |||||
"Staff": "員工", | |||||
"Total Manhours Spent by Staff Grade": "按員工級別統計的總工時花費", | |||||
"Staff Grade": "員工級別", | |||||
"Manhours Spent by Individual Staff": "個別員工的工時花費", | |||||
"Staff Code and Name": "員工代碼與姓名", | |||||
"Please select a staff": "請選擇一名員工", | |||||
"Total Normal Hours Spent": "總正常工時花費", | |||||
"Total Other Hours Spent": "總其他工時花費", | |||||
"Total Leave Hours": "總請假時數", | |||||
"Effort Proportion for individual Staff": "個別員工的工作比例", | |||||
"Week": "週", | |||||
"Month": "月份", | |||||
"Project": "項目", | |||||
"Manhours (Hour)": "工時(小時)", | |||||
"Project Resource Summary": "項目資源摘要", | |||||
"Client Code And Name": "客戶代碼與名稱", | |||||
"Subsidiary Code And Name": "子公司代碼與名稱", | |||||
"Project Information": "項目信息", | |||||
"Remaining Resources": "剩餘資源", | |||||
"Planned Resources": "計劃資源", | |||||
"Actual Resources Spent": "實際資源花費", | |||||
"Manhours": "工時(小時)", | |||||
"Within Budget": "在預算內", | |||||
"Overconsumption": "超量消耗", | |||||
"Stage": "階段", | |||||
"Task Count": "工作數量", | |||||
"Total": "總計", | |||||
"Status": "狀態" | |||||
} | } |