Procházet zdrojové kódy

Financial Summary Update

tags/Baseline_30082024_FRONTEND_UAT
MSI\User před 1 rokem
rodič
revize
ef9b229eee
12 změnil soubory, kde provedl 190 přidání a 55 odebrání
  1. +4
    -2
      src/app/(main)/projects/page.tsx
  2. +2
    -2
      src/components/AppBar/Profile.tsx
  3. +1
    -1
      src/components/Breadcrumb/Breadcrumb.tsx
  4. +7
    -1
      src/components/CustomDatagrid/CustomDatagrid.tsx
  5. +35
    -19
      src/components/ProjectCashFlow/ProjectCashFlow.tsx
  6. +77
    -20
      src/components/ProjectFinancialSummary/ProjectFinancialCard.tsx
  7. +24
    -2
      src/components/ProjectFinancialSummary/ProjectFinancialSummary.tsx
  8. +4
    -4
      src/components/ProjectSearch/ProjectSearch.tsx
  9. +2
    -1
      src/i18n/en/dashboard.json
  10. +16
    -1
      src/i18n/en/projects.json
  11. +2
    -1
      src/i18n/zh/dashboard.json
  12. +16
    -1
      src/i18n/zh/projects.json

+ 4
- 2
src/app/(main)/projects/page.tsx Zobrazit soubor

@@ -1,7 +1,7 @@
import { fetchProjectCategories, fetchProjects, preloadProjects } from "@/app/api/projects";
import { fetchUserAbilities } from "@/app/utils/fetchUtil";
import ProjectSearch from "@/components/ProjectSearch";
import { getServerI18n } from "@/i18n";
import { getServerI18n, I18nProvider } from "@/i18n";
import { MAINTAIN_PROJECT, VIEW_PROJECT } from "@/middleware";
import Add from "@mui/icons-material/Add";
import Button from "@mui/material/Button";
@@ -28,6 +28,7 @@ const Projects: React.FC = async () => {

return (
<>
<I18nProvider namespaces={["projects","common"]}>
<Stack
direction="row"
justifyContent="space-between"
@@ -35,7 +36,7 @@ const Projects: React.FC = async () => {
rowGap={2}
>
<Typography variant="h4" marginInlineEnd={2}>
{t("Projects")}
{t("Project Management")}
</Typography>
{abilities.includes(MAINTAIN_PROJECT) && <Stack
direction="row"
@@ -66,6 +67,7 @@ const Projects: React.FC = async () => {
<Suspense fallback={<ProjectSearch.Loading />}>
<ProjectSearch />
</Suspense>
</I18nProvider>
</>
);
};


+ 2
- 2
src/components/AppBar/Profile.tsx Zobrazit soubor

@@ -66,8 +66,8 @@ const Profile: React.FC<Props> = ({ avatarImageSrc, profileName }) => {
</Typography>
<Divider />
<MenuItem onClick={() => { router.replace("/changepassword") }}>{t("Change Password")}</MenuItem>
{/* {language === "zh" && <MenuItem onClick={() => { onLangClick("en") }}>{t("Change To English Version")}</MenuItem>}
{language === "en" && <MenuItem onClick={() => { onLangClick("zh") }}>{t("Change To Chinese Version")}</MenuItem>} */}
{language === "zh" && <MenuItem onClick={() => { onLangClick("en") }}>{t("Change To English Version")}</MenuItem>}
{language === "en" && <MenuItem onClick={() => { onLangClick("zh") }}>{t("Change To Chinese Version")}</MenuItem>}
<MenuItem onClick={() => signOut()}>{t("Sign out")}</MenuItem>
</Menu>
</>


+ 1
- 1
src/components/Breadcrumb/Breadcrumb.tsx Zobrazit soubor

@@ -23,7 +23,7 @@ const pathToLabelMap: { [path: string]: string } = {
"/dashboard/ProjectStatusByTeam": "Project Status by Team",
"/dashboard/ProjectResourceConsumptionRanking": "Project Resource Consumption Ranking",
"/dashboard/StaffUtilization": "Staff Utilization",
"/projects": "Projects",
"/projects": "Project Management",
"/projects/create": "Create Project",
"/projects/createSub": "Sub Project",
"/projects/edit": "Edit Project",


+ 7
- 1
src/components/CustomDatagrid/CustomDatagrid.tsx Zobrazit soubor

@@ -19,7 +19,8 @@ interface CustomDatagridProps {
onRowSelectionModelChange?: (
newSelectionModel: GridRowSelectionModel,
) => void;
selectionModel?: any;
selectionModel?: GridRowSelectionModel;
rowSelectionModel?: GridRowSelectionModel;
columnGroupingModel?: any;
pageSize?:any;
}
@@ -33,6 +34,7 @@ const CustomDatagrid: React.FC<CustomDatagridProps> = ({
sx,
dataGridHeight,
checkboxSelection, // Destructure the new prop
rowSelectionModel,
onRowSelectionModelChange, // Destructure the new prop
selectionModel,
onRowClick,
@@ -200,6 +202,7 @@ const CustomDatagrid: React.FC<CustomDatagridProps> = ({
getRowHeight={() => 'auto'}
onRowClick={onRowClick}
checkboxSelection={checkboxSelection}
rowSelectionModel={rowSelectionModel}
onRowSelectionModelChange={onRowSelectionModelChange}
experimentalFeatures={{ columnGrouping: true }}
columnGroupingModel={columnGroupingModel}
@@ -233,6 +236,7 @@ const CustomDatagrid: React.FC<CustomDatagridProps> = ({
getRowHeight={() => 'auto'}
onRowClick={onRowClick}
checkboxSelection={checkboxSelection}
rowSelectionModel={rowSelectionModel}
onRowSelectionModelChange={onRowSelectionModelChange}
experimentalFeatures={{ columnGrouping: true }}
columnGroupingModel={columnGroupingModel}
@@ -266,6 +270,7 @@ const CustomDatagrid: React.FC<CustomDatagridProps> = ({
getRowHeight={() => 'auto'}
onRowClick={onRowClick}
checkboxSelection={checkboxSelection}
rowSelectionModel={rowSelectionModel}
onRowSelectionModelChange={onRowSelectionModelChange}
experimentalFeatures={{ columnGrouping: true }}
columnGroupingModel={columnGroupingModel}
@@ -301,6 +306,7 @@ const CustomDatagrid: React.FC<CustomDatagridProps> = ({
onRowClick={onRowClick}
style={{ marginRight: 0 }}
checkboxSelection={checkboxSelection}
rowSelectionModel={rowSelectionModel}
onRowSelectionModelChange={onRowSelectionModelChange}
experimentalFeatures={{ columnGrouping: true }}
columnGroupingModel={columnGroupingModel}


+ 35
- 19
src/components/ProjectCashFlow/ProjectCashFlow.tsx Zobrazit soubor

@@ -25,6 +25,7 @@ import { CashFlow } from "@/app/api/cashflow";
import dayjs from 'dayjs';
import ProjectTotalFee from "../CreateInvoice_forGen/ProjectTotalFee";
import Typography from "@mui/material/Typography";
import { useSearchParams } from 'next/navigation';

interface Props {
projects: CashFlow[];
@@ -34,8 +35,10 @@ type SearchParamNames = keyof SearchQuery;

const ProjectCashFlow: React.FC = () => {
const { t } = useTranslation("dashboard");
const searchParams = useSearchParams();
const projectId = searchParams.get('projectId');
const todayDate = new Date();
const [selectionModel, setSelectionModel]: any[] = React.useState([]);
const [selectionModel, setSelectionModel]: any[] = useState<GridRowSelectionModel>([]);
const [projectData, setProjectData]: any[] = React.useState([]);
const [filteredResult, setFilteredResult]:any[] = useState([]);
const [selectedProjectIdList, setSelectedProjectIdList]: any[] = React.useState([]);
@@ -59,6 +62,7 @@ const ProjectCashFlow: React.FC = () => {
const [monthlyAnticipateIncomeList, setMonthlyAnticipateIncomeList]: any[] = React.useState([0,0,0,0,0,0,0,0,0,0,0,0]);
const [monthlyAnticipateExpenditureList, setMonthlyAnticipateExpenditureList]: any[] = React.useState([0,0,0,0,0,0,0,0,0,0,0,0]);
const [ledgerData, setLedgerData]: any[] = React.useState([]);
const [isInitializing, setIsInitializing] = useState(true);
const [cashFlowYear, setCashFlowYear]: any[] = React.useState(
todayDate.getFullYear(),
);
@@ -67,14 +71,18 @@ const ProjectCashFlow: React.FC = () => {
);

const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => {
const selectedRowsData = projectData.filter((row: any) =>
newSelectionModel.includes(row.id),
);
const projectIdList = []
for (var i=0; i<selectedRowsData.length; i++){
projectIdList.push(selectedRowsData[i].id)
if (!isInitializing) {
setSelectionModel(newSelectionModel);
console.log(newSelectionModel)
console.log(projectData)
const selectedRowsData = projectData.filter((row: any) =>
newSelectionModel.includes(row.id)
);
const projectIdList = selectedRowsData.map((row: any) => row.id);
console.log(selectedRowsData)
setSelectedProjectIdList(projectIdList);
}
setSelectedProjectIdList(projectIdList)
};

const fetchData = async () => {
@@ -85,7 +93,6 @@ const ProjectCashFlow: React.FC = () => {
}
const fetchChartData = async () => {
const cashFlowMonthlyChartData = await fetchProjectsCashFlowMonthlyChart(selectedProjectIdList,cashFlowYear);
console.log(cashFlowMonthlyChartData)
const monthlyIncome = []
const cumulativeIncome = []
const monthlyExpenditure = []
@@ -122,6 +129,7 @@ const ProjectCashFlow: React.FC = () => {
}
const fetchReceivableAndExpenditureData = async () => {
console.log("s2")
if (selectedProjectIdList.length === 0) {
setReceivedPercentage(0)
setInvoicedPercentage(0)
@@ -165,8 +173,7 @@ const ProjectCashFlow: React.FC = () => {
setMonthlyAnticipateIncomeList([0,0,0,0,0,0,0,0,0,0,0,0])
setMonthlyAnticipateExpenditureList([0,0,0,0,0,0,0,0,0,0,0,0])
}
console.log(cashFlowAnticipateData)
if(cashFlowAnticipateData.length !== 0){
if (cashFlowAnticipateData[0].anticipateExpenditureList.length !== 0) {
const anticipateExpenditureList = []
@@ -186,7 +193,6 @@ const ProjectCashFlow: React.FC = () => {
}
anticipateExpenditureList.push(subAnticipateExpenditure)
}
console.log(anticipateExpenditureList)
const result = new Array(anticipateExpenditureList[0].length).fill(0);
for (const arr of anticipateExpenditureList) {
for (let i = 0; i < arr.length; i++) {
@@ -211,18 +217,28 @@ const ProjectCashFlow: React.FC = () => {
setLedgerData(cashFlowLedgerData)
}
useEffect(() => {
fetchData()
if (projectId !== null) {
setSelectedProjectIdList([parseInt(projectId)])
setSelectionModel([parseInt(projectId)]);
}
fetchData().then(() => {
setIsInitializing(false);
});
}, []);

useEffect(() => {
fetchChartData()
fetchReceivableAndExpenditureData()
fetchAnticipateData()
fetchProjectCashFlowLedger()
fetchChartData();
fetchReceivableAndExpenditureData();
fetchAnticipateData();
fetchProjectCashFlowLedger();
}, [cashFlowYear,selectedProjectIdList]);

useEffect(() => {
fetchAnticipateData()
fetchAnticipateData();
}, [anticipateCashFlowYear,selectedProjectIdList]);

const columns = [
{
id: "projectCode",
@@ -791,7 +807,7 @@ const ProjectCashFlow: React.FC = () => {
dataGridHeight={300}
checkboxSelection={true}
onRowSelectionModelChange={handleSelectionChange}
selectionModel={selectionModel}
rowSelectionModel={selectionModel}
/>
<Grid item sm>
<div style={{ display: "inline-block", width: "50%" }}>


+ 77
- 20
src/components/ProjectFinancialSummary/ProjectFinancialCard.tsx Zobrazit soubor

@@ -17,9 +17,13 @@ import { AnyARecord, AnyCnameRecord } from "dns";
import SearchBox, { Criterion } from "../SearchBox";
import ProgressByClientSearch from "@/components/ProgressByClientSearch";
import { Suspense } from "react";
import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked';
import RadioButtonCheckedIcon from '@mui/icons-material/RadioButtonChecked';
import { useRouter } from "next/navigation";

interface Props {
Title: string;
TeamId: number;
TotalActiveProjectNumber: number;
TotalFees: number;
TotalBudget: number;
@@ -37,6 +41,7 @@ interface Props {

const ProjectFinancialCard: React.FC<Props> = ({
Title,
TeamId,
TotalActiveProjectNumber,
TotalFees,
TotalBudget,
@@ -51,8 +56,12 @@ const ProjectFinancialCard: React.FC<Props> = ({
ProjectedCashFlowStatus,
Index,
}) => {
const router = useRouter();
const [SearchCriteria, setSearchCriteria] = React.useState({});
const { t } = useTranslation("dashboard");
const handleCheckProjectStatusClick = (TeamId:number) => {
router.push(`/dashboard/ProjectStatusByTeam?teamLeadId=${TeamId}`);
};
const borderColor =
CashFlowStatus === "Negative"
? "border-red-300 border-solid"
@@ -71,72 +80,100 @@ const ProjectFinancialCard: React.FC<Props> = ({
className={`${borderColor}`}
>
<div
className="text-xl mt-2 font-medium"
className="text-xl mt-2 font-medium inline-block"
style={{ width: "100%", textAlign: "center", color: "#898d8d" }}
>
{Title}
{Title !== t("All Team") ?
<div className="ml-10 inline-block">{Title}</div>
:
<div className="ml-10 inline-block mb-7">{Title}</div>
}
{ClickedIndex === Index ?
<div className="inline-block float-right mt-1 mr-5 text-gray-500"><RadioButtonCheckedIcon /></div>
:
<div className="inline-block float-right mt-1 mr-5 text-gray-400"><RadioButtonUncheckedIcon /></div>
}
</div>
<hr />
{Title !== t("All Team") ?
<>
<div onClick={(r) => handleCheckProjectStatusClick(TeamId)} className="bg-lime-100 mb-2 border-b-2 pt-1 pb-1 hover:bg-lime-200" style={{ width: "100%", textAlign: "center", color: "#898d8d" }}>{t("Check Project Status")}</div>
</>
:
<><hr /></>
}
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
{t("Total Active Project")}
{"(a) " + t("Total Active Project")}
</div>
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}>
{TotalActiveProjectNumber.toLocaleString()}
</div>
<hr />
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
{t("Total Fees")}
{"(b) " + t("Total Fees")}
</div>
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}>
{TotalFees.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<hr />
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
{t("Total Budget")}
{"(c) " + t("Total Budget")}
</div>
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}>
{TotalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<div className="text-sm font-medium ml-5 border-solid w-fit rounded-md mt-2" style={{ color: "#888d8f" }}>
<div className="ml-2 mr-2 ">{"(c) = (b) * 80%"}</div>
</div>
<hr />
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
{t("Total Cumulative Expenditure")}
{"(d) " + t("Total Cumulative Expenditure")}
</div>
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}>
{TotalCumulative.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<hr />
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
{t("Total Invoiced Amount")}
{"(e) " + t("Total Invoiced Amount")}
</div>
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}>
{TotalInvoicedAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<hr />
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
{t("Total Un-Invoiced Amount")}
{"(f) " + t("Total Un-Invoiced Amount")}
</div>
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}>
{TotalUnInvoicedAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<div className="text-sm font-medium ml-5 border-solid w-fit rounded-md mt-2" style={{ color: "#888d8f" }}>
<div className="ml-2 mr-2 ">{"(f) =(b) - (e)"}</div>
</div>
<hr />
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
{t("Total Received Amount")}
{"(g) " + t("Total Received Amount")}
</div>
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}>
{TotalReceivedAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<hr />
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
{t("Cash Flow Status")}
{"(h) " + t("Cash Flow Status")}
</div>
{CashFlowStatus === "Negative" && (
<>
<div
className="text-lg font-medium ml-5"
style={{ color: "#f896aa" }}
>
{t(CashFlowStatus)}
</div>
<div
className="text-lg font-medium ml-5"
style={{ color: "#f896aa" }}
>
{t(CashFlowStatus)}
</div>
<div className="text-sm font-medium ml-5 border-solid w-fit rounded-md mt-2" style={{ color: "#888d8f" }}>
<div className="ml-2 mr-2 ">{"Positive: (e) > or = (d)"}</div>
<div className="ml-2 mr-2 ">{"Negative: (e) < (d)"}</div>
</div>
<hr />
</>
)}
@@ -148,6 +185,10 @@ const ProjectFinancialCard: React.FC<Props> = ({
>
{t(CashFlowStatus)}
</div>
<div className="text-sm font-medium ml-5 border-solid w-fit rounded-md mt-2" style={{ color: "#888d8f" }}>
<div className="ml-2 mr-2 ">{"Positive: (e) > or = (d)"}</div>
<div className="ml-2 mr-2 ">{"Negative: (e) < (d)"}</div>
</div>
<hr />
</>
)}
@@ -155,7 +196,7 @@ const ProjectFinancialCard: React.FC<Props> = ({
className="text-sm mt-2 font-medium ml-5"
style={{ color: "#898d8d" }}
>
{t("Cost Performance Index") + " (CPI)"}
{"(i) " + t("Cost Performance Index") + " (CPI)"}
</div>
{Number(CostPerformanceIndex) < 1 && (
<>
@@ -165,6 +206,9 @@ const ProjectFinancialCard: React.FC<Props> = ({
>
{CostPerformanceIndex}
</div>
<div className="text-sm font-medium ml-5 border-solid w-fit rounded-md mt-2" style={{ color: "#888d8f" }}>
<div className="ml-2 mr-2 ">{"(i) = (e) / (d)"}</div>
</div>
<hr />
</>
)}
@@ -176,11 +220,14 @@ const ProjectFinancialCard: React.FC<Props> = ({
>
{CostPerformanceIndex}
</div>
<div className="text-sm font-medium ml-5 border-solid w-fit rounded-md mt-2" style={{ color: "#888d8f" }}>
<div className="ml-2 mr-2 ">{"(i) =(e) / (d)"}</div>
</div>
<hr />
</>
)}
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
{t("Projected Cash Flow Status")}
{"(j) " + t("Projected Cash Flow Status")}
</div>
{ProjectedCashFlowStatus === "Negative" && (
<>
@@ -190,6 +237,10 @@ const ProjectFinancialCard: React.FC<Props> = ({
>
{t(ProjectedCashFlowStatus)}
</div>
<div className="text-sm font-medium ml-5 border-solid w-fit rounded-md mt-2" style={{ color: "#888d8f" }}>
<div className="ml-2 mr-2 ">{"Positive: (b) > or = (d)"}</div>
<div className="ml-2 mr-2 ">{"Negative: (b) < (d)"}</div>
</div>
<hr />
</>
)}
@@ -208,7 +259,7 @@ const ProjectFinancialCard: React.FC<Props> = ({
className="text-sm mt-2 font-medium ml-5"
style={{ color: "#898d8d" }}
>
{t("Projected Cost Performance Index") + " (CPI)"}
{"(k) " + t("Projected Cost Performance Index") + " (CPI)"}
</div>
{Number(ProjectedCPI) < 1 && (
<>
@@ -218,6 +269,9 @@ const ProjectFinancialCard: React.FC<Props> = ({
>
{ProjectedCPI}
</div>
<div className="text-sm font-medium ml-5 border-solid w-fit rounded-md mt-2 mb-2" style={{ color: "#888d8f" }}>
<div className="ml-2 mr-2 ">{"Positive: (b) / (d)"}</div>
</div>
</>
)}
{Number(ProjectedCPI) >= 1 && (
@@ -228,6 +282,9 @@ const ProjectFinancialCard: React.FC<Props> = ({
>
{ProjectedCPI}
</div>
<div className="text-sm font-medium ml-5 border-solid w-fit rounded-md mt-2 mb-2" style={{ color: "#888d8f" }}>
<div className="ml-2 mr-2 ">{"Positive: (b) / (d)"}</div>
</div>
</>
)}
</Card>


+ 24
- 2
src/components/ProjectFinancialSummary/ProjectFinancialSummary.tsx Zobrazit soubor

@@ -24,6 +24,7 @@ import ProjectFinancialCard from "./ProjectFinancialCard";
import VisibilityIcon from '@mui/icons-material/Visibility';
import { downloadFile } from "@/app/utils/commonUtil";
import Typography from "@mui/material/Typography";
import { useRouter } from "next/navigation";

type SearchProjectQuery = Partial<Omit<FinancialSummaryByProjectResult, "id">>;
type SearchClientQuery = Partial<Omit<FinancialSummaryByClientResult, "id">>;
@@ -31,6 +32,7 @@ type SearchProjectParamNames = keyof SearchProjectQuery;
type SearchClientParamNames = keyof SearchClientQuery;

const ProjectFinancialSummary: React.FC = () => {
const router = useRouter();
const [SearchCriteria, setSearchCriteria] = React.useState({});
const { t } = useTranslation("dashboard");
const [selectionModel, setSelectionModel]: any[] = React.useState([]);
@@ -111,7 +113,17 @@ const ProjectFinancialSummary: React.FC = () => {
id: 'customerCode',
field: 'customerCode',
headerName: t("Client Code"),
minWidth:50
minWidth:50,
renderCell: (params: any) => (
<div
className="text-blue-600 hover:underline cursor-pointer"
onClick={() => {
router.push(`/dashboard/ProjectStatusByClient?customerId=${params.row.id}&subsidiaryId=-`);
}}
>
{params.value}
</div>
),
},
{
id: 'customerName',
@@ -317,6 +329,16 @@ const columns2 = [
field: 'projectCode',
headerName: t("Project Code"),
minWidth:50,
renderCell: (params: any) => (
<div
className="text-blue-600 hover:underline cursor-pointer"
onClick={() => {
router.push(`/dashboard/ProjectCashFlow?projectId=${params.row.id}`);
}}
>
{params.value}
</div>
),
},
{
id: 'projectName',
@@ -512,7 +534,7 @@ const columns2 = [
<div className="ml-10 mr-10" style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'start'}}>
{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)}>
<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}/>
<ProjectFinancialCard Title={record.teamName == "All Team" ? t("All Team") : record.teamName} TeamId={record.teamId} 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>


+ 4
- 4
src/components/ProjectSearch/ProjectSearch.tsx Zobrazit soubor

@@ -28,16 +28,16 @@ const ProjectSearch: React.FC<Props> = ({ projects, projectCategories, abilities

const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
() => [
{ label: t("Project code"), paramName: "code", type: "text" },
{ label: t("Project name"), paramName: "name", type: "text" },
{ label: t("Project Code"), paramName: "code", type: "text" },
{ label: t("Project Name"), paramName: "name", type: "text" },
{
label: t("Client name"),
label: t("Client Name"),
paramName: "client",
type: "autocomplete",
options: uniqBy(projects.map((project) => ({value: project.client, label: project.client})), "value").sort((a, b) => a.value >= b.value ? 1 : -1),
},
{
label: t("Project category"),
label: t("Project Category"),
paramName: "category",
type: "select",
options: projectCategories.map((category) => category.name),


+ 2
- 1
src/i18n/en/dashboard.json Zobrazit soubor

@@ -155,5 +155,6 @@
"Stage": "Stage",
"Task Count": "Task Count",
"Total": "Total",
"Status": "Status"
"Status": "Status",
"Check Project Status": "Check Project Status"
}

+ 16
- 1
src/i18n/en/projects.json Zobrazit soubor

@@ -1 +1,16 @@
{}
{
"Project Management": "Project Management",
"Create Sub Project": "Create Sub Project",
"Create Project": "Create Project",
"Project Code": "Project Code",
"Project Name": "Project Name",
"Client Name": "Client Name",
"Client": "Client",
"Project Category": "Project Category",
"Team": "Team",
"Status": "Status",
"Details": "Details",
"Awarded Project": "Awarded Project",
"Project to be bidded": "Project to be bidded",
"On-going": "On-going"
}

+ 2
- 1
src/i18n/zh/dashboard.json Zobrazit soubor

@@ -156,5 +156,6 @@
"Stage": "階段",
"Task Count": "工作數量",
"Total": "總計",
"Status": "狀態"
"Status": "狀態",
"Check Project Status": "查看項目狀態"
}

+ 16
- 1
src/i18n/zh/projects.json Zobrazit soubor

@@ -1 +1,16 @@
{}
{
"Project Management": "項目管理",
"Create Sub Project": "創建子項目",
"Create Project": "創建項目",
"Project Code": "項目代碼",
"Project Name": "項目名稱",
"Client Name": "客戶名稱",
"Client": "客戶",
"Project Category": "項目類別",
"Team": "團隊",
"Status": "狀態",
"Details": "詳細信息",
"Awarded Project": "已獲得的項目",
"Project to be bidded": "待投標項目",
"On-going": "進行中"
}

Načítá se…
Zrušit
Uložit