Explorar el Código

added all dashboard i18n

tags/Baseline_30082024_FRONTEND_UAT
MSI\User hace 1 año
padre
commit
e7144779d9
Se han modificado 26 ficheros con 828 adiciones y 437 borrados
  1. +0
    -3
      src/app/(main)/dashboard/CompanyTeamCashFlow/page.tsx
  2. +1
    -4
      src/app/(main)/dashboard/ProjectCashFlow/page.tsx
  3. +2
    -4
      src/app/(main)/dashboard/ProjectFinancialSummary/page.tsx
  4. +1
    -4
      src/app/(main)/dashboard/ProjectResourceConsumptionRanking/page.tsx
  5. +3
    -5
      src/app/(main)/dashboard/ProjectResourceSummary/page.tsx
  6. +1
    -4
      src/app/(main)/dashboard/ProjectStatusByClient/page.tsx
  7. +1
    -4
      src/app/(main)/dashboard/ProjectStatusByTeam/page.tsx
  8. +0
    -3
      src/app/(main)/dashboard/StaffUtilization/page.tsx
  9. +7
    -4
      src/components/Breadcrumb/Breadcrumb.tsx
  10. +36
    -25
      src/components/CompanyTeamCashFlow/CompanyTeamCashFlow.tsx
  11. +3
    -2
      src/components/NavigationContent/NavigationContent.tsx
  12. +34
    -30
      src/components/ProgressByClient/ProgressByClient.tsx
  13. +8
    -4
      src/components/ProgressByClientSearch/ProgressByClientSearch.tsx
  14. +35
    -35
      src/components/ProgressByTeam/ProgressByTeam.tsx
  15. +7
    -3
      src/components/ProgressByTeamSearch/ProgressByTeamSearch.tsx
  16. +80
    -67
      src/components/ProjectCashFlow/ProjectCashFlow.tsx
  17. +15
    -15
      src/components/ProjectFinancialSummary/ProjectFinancialCard.tsx
  18. +54
    -50
      src/components/ProjectFinancialSummary/ProjectFinancialSummary.tsx
  19. +44
    -40
      src/components/ProjectResourceConsumptionRanking/ProjectResourceConsumptionRanking.tsx
  20. +58
    -58
      src/components/ProjectResourceSummary/ProjectResourceSummary.tsx
  21. +10
    -6
      src/components/ProjectResourceSummarySearch/ProjectResourceSummarySearch.tsx
  22. +87
    -63
      src/components/StaffUtilization/StaffUtilization.tsx
  23. +12
    -1
      src/i18n/en/common.json
  24. +159
    -1
      src/i18n/en/dashboard.json
  25. +12
    -1
      src/i18n/zh/common.json
  26. +158
    -1
      src/i18n/zh/dashboard.json

+ 0
- 3
src/app/(main)/dashboard/CompanyTeamCashFlow/page.tsx Ver fichero

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


+ 1
- 4
src/app/(main)/dashboard/ProjectCashFlow/page.tsx Ver fichero

@@ -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> */}


+ 2
- 4
src/app/(main)/dashboard/ProjectFinancialSummary/page.tsx Ver fichero

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


+ 1
- 4
src/app/(main)/dashboard/ProjectResourceConsumptionRanking/page.tsx Ver fichero

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


+ 3
- 5
src/app/(main)/dashboard/ProjectResourceSummary/page.tsx Ver fichero

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


+ 1
- 4
src/app/(main)/dashboard/ProjectStatusByClient/page.tsx Ver fichero

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


+ 1
- 4
src/app/(main)/dashboard/ProjectStatusByTeam/page.tsx Ver fichero

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


+ 0
- 3
src/app/(main)/dashboard/StaffUtilization/page.tsx Ver fichero

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


+ 7
- 4
src/components/Breadcrumb/Breadcrumb.tsx Ver fichero

@@ -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 (


+ 36
- 25
src/components/CompanyTeamCashFlow/CompanyTeamCashFlow.tsx Ver fichero

@@ -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:&nbsp;
{t("Year")}:&nbsp;
</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:&nbsp;
{t("Team")}:&nbsp;
</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) => {


+ 3
- 2
src/components/NavigationContent/NavigationContent.tsx Ver fichero

@@ -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) => {


+ 34
- 30
src/components/ProgressByClient/ProgressByClient.tsx Ver fichero

@@ -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"


+ 8
- 4
src/components/ProgressByClientSearch/ProgressByClientSearch.tsx Ver fichero

@@ -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) => {


+ 35
- 35
src/components/ProgressByTeam/ProgressByTeam.tsx Ver fichero

@@ -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&nbsp;
{t("Page")}&nbsp;
{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"


+ 7
- 3
src/components/ProgressByTeamSearch/ProgressByTeamSearch.tsx Ver fichero

@@ -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) => {


+ 80
- 67
src/components/ProjectCashFlow/ProjectCashFlow.tsx Ver fichero

@@ -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:&nbsp;
{t("Year")}:&nbsp;
</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:&nbsp;
{t("Year")}:&nbsp;
</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


+ 15
- 15
src/components/ProjectFinancialSummary/ProjectFinancialCard.tsx Ver fichero

@@ -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 && (
<> <>


+ 54
- 50
src/components/ProjectFinancialSummary/ProjectFinancialSummary.tsx Ver fichero

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


+ 44
- 40
src/components/ProjectResourceConsumptionRanking/ProjectResourceConsumptionRanking.tsx Ver fichero

@@ -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&nbsp;
{t("Page")}&nbsp;
{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"


+ 58
- 58
src/components/ProjectResourceSummary/ProjectResourceSummary.tsx Ver fichero

@@ -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
src/components/ProjectResourceSummarySearch/ProjectResourceSummarySearch.tsx Ver fichero

@@ -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) => {


+ 87
- 63
src/components/StaffUtilization/StaffUtilization.tsx Ver fichero

@@ -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:&nbsp;
{t("Team")}:&nbsp;
</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:&nbsp;
{t("Team")}:&nbsp;
</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:&nbsp;
{t("Team")}:&nbsp;
</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&nbsp;
{t("Page")}&nbsp;
{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:&nbsp;
{t("Staff Code and Name")}:&nbsp;
</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}


+ 12
- 1
src/i18n/en/common.json Ver fichero

@@ -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"
} }

+ 159
- 1
src/i18n/en/dashboard.json Ver fichero

@@ -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"
}

+ 12
- 1
src/i18n/zh/common.json Ver fichero

@@ -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": "項目資源摘要"
} }

+ 158
- 1
src/i18n/zh/dashboard.json Ver fichero

@@ -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": "狀態"
} }

Cargando…
Cancelar
Guardar