Przeglądaj źródła

update dashboard

tags/Baseline_30082024_FRONTEND_UAT
Mac\David 1 rok temu
rodzic
commit
898e74b819
7 zmienionych plików z 97 dodań i 54 usunięć
  1. +4
    -17
      src/app/api/cashflow/index.ts
  2. +21
    -9
      src/app/api/financialsummary/actions.ts
  3. +1
    -0
      src/components/Breadcrumb/Breadcrumb.tsx
  4. +6
    -0
      src/components/CustomDatagrid/CustomDatagrid.tsx
  5. +41
    -6
      src/components/ProjectCashFlow/ProjectCashFlow.tsx
  6. +5
    -7
      src/components/ProjectFinancialSummary/ProjectFinancialCard.tsx
  7. +19
    -15
      src/components/ProjectFinancialSummary/ProjectFinancialSummary.tsx

+ 4
- 17
src/app/api/cashflow/index.ts Wyświetl plik

@@ -1,4 +1,7 @@
"use server";
import { cache } from "react";
import { serverFetchJson } from "@/app/utils/fetchUtil";
import { BASE_API_URL } from "@/config/api";

export interface CashFlow {
id: number;
@@ -19,21 +22,5 @@ export const preloadProjects = () => {
};

export const fetchProjectsCashFlow = cache(async () => {
return mockProjects;
return serverFetchJson<CashFlow[]>(`${BASE_API_URL}/dashboard/searchCashFlowProject`);
});

const mockProjects: CashFlow[] = [
{
id: 1,
projectCode: "CUST-001",
projectName: "Client A",
team: "N/A",
teamLeader: "N/A",
startDate: "5",
startDateFrom: "5",
startDateTo: "5",
targetEndDate: "s",
client: "ss",
subsidiary: "ss",
},
];

+ 21
- 9
src/app/api/financialsummary/actions.ts Wyświetl plik

@@ -39,16 +39,28 @@ export interface FinancialSummaryByProjectResult {
totalUninvoiced: number;
}

export const searchFinancialSummaryByClient = cache(async (teamId: number) => {
return serverFetchJson<FinancialSummaryByClientResult[]>(
`${BASE_API_URL}/dashboard/searchFinancialSummaryByClient?teamId=${teamId}`
);
export const searchFinancialSummaryByClient = cache(async (teamId?: number) => {
if (teamId === undefined) {
return serverFetchJson<FinancialSummaryByClientResult[]>(
`${BASE_API_URL}/dashboard/searchFinancialSummaryByClient`
);
} else {
return serverFetchJson<FinancialSummaryByClientResult[]>(
`${BASE_API_URL}/dashboard/searchFinancialSummaryByClient?teamId=${teamId}`
);
}
});

export const searchFinancialSummaryByProject = cache(async (teamId: number) => {
export const searchFinancialSummaryByProject = cache(async (teamId?: number, customerId?:number) => {
if (teamId === undefined) {
return serverFetchJson<FinancialSummaryByProjectResult[]>(
`${BASE_API_URL}/dashboard/searchFinancialSummaryByProject`
);
} else {
return serverFetchJson<FinancialSummaryByProjectResult[]>(
`${BASE_API_URL}/dashboard/searchFinancialSummaryByProject?teamId=${teamId}&customerId=${customerId}`
);
}
return serverFetchJson<FinancialSummaryByProjectResult[]>(
`${BASE_API_URL}/dashboard/searchFinancialSummaryByProject?teamId=${teamId}`
);
});

+ 1
- 0
src/components/Breadcrumb/Breadcrumb.tsx Wyświetl plik

@@ -13,6 +13,7 @@ import { I18nProvider } from "@/i18n";
const pathToLabelMap: { [path: string]: string } = {
"": "Overview",
"/home": "User Workspace",
"/dashboard": "Dashboard",
"/projects": "Projects",
"/projects/create": "Create Project",
"/projects/createSub": "Sub Project",


+ 6
- 0
src/components/CustomDatagrid/CustomDatagrid.tsx Wyświetl plik

@@ -15,6 +15,7 @@ interface CustomDatagridProps {
dataGridHeight?: number | string;
[key: string]: any;
checkboxSelection?: boolean;
onRowClick?: any;
onRowSelectionModelChange?: (
newSelectionModel: GridRowSelectionModel,
) => void;
@@ -34,6 +35,7 @@ const CustomDatagrid: React.FC<CustomDatagridProps> = ({
checkboxSelection, // Destructure the new prop
onRowSelectionModelChange, // Destructure the new prop
selectionModel,
onRowClick,
columnGroupingModel,
pageSize,
...props
@@ -195,6 +197,7 @@ const CustomDatagrid: React.FC<CustomDatagridProps> = ({
rows={rowsWithDefaultValues}
columns={modifiedColumns}
editMode="row"
onRowClick={onRowClick}
checkboxSelection={checkboxSelection}
onRowSelectionModelChange={onRowSelectionModelChange}
experimentalFeatures={{ columnGrouping: true }}
@@ -226,6 +229,7 @@ const CustomDatagrid: React.FC<CustomDatagridProps> = ({
rows={rowsWithDefaultValues}
columns={modifiedColumns}
editMode="row"
onRowClick={onRowClick}
checkboxSelection={checkboxSelection}
onRowSelectionModelChange={onRowSelectionModelChange}
experimentalFeatures={{ columnGrouping: true }}
@@ -257,6 +261,7 @@ const CustomDatagrid: React.FC<CustomDatagridProps> = ({
rows={rowsWithDefaultValues}
columns={modifiedColumns}
editMode="row"
onRowClick={onRowClick}
checkboxSelection={checkboxSelection}
onRowSelectionModelChange={onRowSelectionModelChange}
experimentalFeatures={{ columnGrouping: true }}
@@ -289,6 +294,7 @@ const CustomDatagrid: React.FC<CustomDatagridProps> = ({
rows={rowsWithDefaultValues}
columns={modifiedColumns}
editMode="row"
onRowClick={onRowClick}
style={{ marginRight: 0 }}
checkboxSelection={checkboxSelection}
onRowSelectionModelChange={onRowSelectionModelChange}


+ 41
- 6
src/components/ProjectCashFlow/ProjectCashFlow.tsx Wyświetl plik

@@ -19,17 +19,34 @@ import SearchBox, { Criterion } from "../SearchBox";
import ProgressByClientSearch from "@/components/ProgressByClientSearch";
import { Suspense } from "react";
import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch";
import { fetchProjectsCashFlow} from "@/app/api/cashflow";
import { Input, Label } from "reactstrap";
import { CashFlow } from "@/app/api/cashflow";

interface Props {
projects: CashFlow[];
}
type SearchQuery = Partial<Omit<CashFlow, "id">>;
type SearchParamNames = keyof SearchQuery;

const ProjectCashFlow: React.FC = () => {
const { t } = useTranslation("projects");
const todayDate = new Date();
const [selectionModel, setSelectionModel]: any[] = React.useState([]);
const [projectData, setProjectData]: any[] = React.useState([]);
const [cashFlowYear, setCashFlowYear]: any[] = React.useState(
todayDate.getFullYear(),
);
const [anticipateCashFlowYear, setAnticipateCashFlowYear]: any[] = React.useState(
todayDate.getFullYear(),
);
const fetchData = async () => {
const cashFlowProject = await fetchProjectsCashFlow();
setProjectData(cashFlowProject)
}
useEffect(() => {
fetchData()
}, []);
const columns = [
{
id: "projectCode",
@@ -50,8 +67,8 @@ const ProjectCashFlow: React.FC = () => {
flex: 1,
},
{
id: "teamLeader",
field: "teamLeader",
id: "teamLead",
field: "teamLead",
headerName: "Team Leader",
flex: 1,
},
@@ -530,8 +547,6 @@ const ProjectCashFlow: React.FC = () => {
remarks: "Monthly Manpower Expenditure",
},
];

const [projectData, setProjectData]: any[] = React.useState(rows);
const [ledgerData, setLedgerData]: any[] = React.useState(ledgerRows);
const handleSelectionChange = (newSelectionModel: GridRowSelectionModel) => {
const selectedRowsData = projectData.filter((row: any) =>
@@ -540,11 +555,31 @@ const ProjectCashFlow: React.FC = () => {
console.log(selectedRowsData);
};

const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
() => [
{ label: "Project Code", paramName: "projectCode", type: "text" },
{ label: "Project Name", paramName: "projectName", type: "text" },
{
label: "Start Date From",
label2: "Start Date To",
paramName: "startDateFrom",
type: "dateRange",
},
],
[t],
);

return (
<>
<Suspense fallback={<ProgressCashFlowSearch.Loading />}>
{/* <Suspense fallback={<ProgressCashFlowSearch.Loading />}>
<ProgressCashFlowSearch />
</Suspense>
</Suspense> */}
<SearchBox
criteria={searchCriteria}
onSearch={(query) => {
console.log(query);
}}
/>
<CustomDatagrid
rows={projectData}
columns={columns}


+ 5
- 7
src/components/ProjectFinancialSummary/ProjectFinancialCard.tsx Wyświetl plik

@@ -53,8 +53,6 @@ const ProjectFinancialCard: React.FC<Props> = ({
: "border-green-200 border-solid";
const selectedBackgroundColor =
ClickedIndex === Index ? "rgb(235 235 235)" : "rgb(255 255 255)";
console.log(ClickedIndex);
console.log(Index);
return (
<Card
style={{
@@ -84,35 +82,35 @@ const ProjectFinancialCard: React.FC<Props> = ({
Total Fees
</div>
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}>
{TotalFees.toLocaleString()}
{TotalFees.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<hr />
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
Total Budget
</div>
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}>
{TotalBudget.toLocaleString()}
{TotalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<hr />
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
Total Cumulative Expenditure
</div>
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}>
{TotalCumulative.toLocaleString()}
{TotalCumulative.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<hr />
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
Total Invoiced Amount
</div>
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}>
{TotalInvoicedAmount.toLocaleString()}
{TotalInvoicedAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<hr />
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>
Total Received Amount
</div>
<div className="text-lg font-medium ml-5" style={{ color: "#6b87cf" }}>
{TotalReceivedAmount.toLocaleString()}
{TotalReceivedAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<hr />
<div className="text-sm font-medium ml-5" style={{ color: "#898d8d" }}>


+ 19
- 15
src/components/ProjectFinancialSummary/ProjectFinancialSummary.tsx Wyświetl plik

@@ -21,6 +21,7 @@ import { Suspense } from "react";
import { fetchFinancialSummaryCard } from "@/app/api/financialsummary";
import { searchFinancialSummaryByClient,searchFinancialSummaryByProject } from "@/app/api/financialsummary/actions";
import ProjectFinancialCard from "./ProjectFinancialCard";
import VisibilityIcon from '@mui/icons-material/Visibility';

const ProjectFinancialSummary: React.FC = () => {
const [SearchCriteria, setSearchCriteria] = React.useState({});
@@ -33,16 +34,16 @@ const ProjectFinancialSummary: React.FC = () => {
const financialSummaryCard = await fetchFinancialSummaryCard();
setProjectFinancialData(financialSummaryCard)
}
const fetchTableData = async (teamId:any) => {
const fetchTableData = async (teamId?:any) => {
const financialSummaryByClient = await searchFinancialSummaryByClient(teamId);
const financialSummaryByProject = await searchFinancialSummaryByProject(teamId);
console.log(financialSummaryByClient)
console.log(financialSummaryByProject)
// console.log(financialSummaryByProject)
setClientFinancialRows(financialSummaryByClient)
setProjectFinancialRows(financialSummaryByProject)
}
useEffect(() => {
fetchData()
fetchTableData(undefined)
}, []);

const rows0 = [{id: 1,projectCode:"M1201",projectName:"Consultancy Project C", team:"XXX", teamLeader:"XXX", startDate:"01/08/2022", targetEndDate: "01/05/2024", client:"Client A", subsidiary:"N/A"},
@@ -73,16 +74,9 @@ const ProjectFinancialSummary: React.FC = () => {

const [selectedTeamData, setSelectedTeamData]: any[] = React.useState(rows0);

const handleCardClick = (r: any) => {
const handleCardClick = (r: any, index:any) => {
fetchTableData(r.teamId)
// setIsCardClickedIndex(r);
// if (r === 0) {
// setSelectedTeamData(rows0);
// } else if (r === 1) {
// setSelectedTeamData(rows1);
// } else if (r === 2) {
// setSelectedTeamData(rows2);
// }
setIsCardClickedIndex(index)
};

const columns = [
@@ -380,6 +374,16 @@ const columns2 = [
);
console.log(selectedRowsData);
};
const fetchProjectTableData = async (teamId?:any,customerId?:any) => {
const financialSummaryByProject = await searchFinancialSummaryByProject(teamId,customerId);
setProjectFinancialRows(financialSummaryByProject)
}

const handleRowClick = (params:any) => {
console.log(params.row.teamId);
fetchProjectTableData(params.row.teamId,params.row.cid)
};

return (
<Grid item sm>
@@ -387,7 +391,7 @@ const columns2 = [
<CardHeader className="text-slate-500" title="Active Project Financial Status"/>
<div className="ml-10 mr-10" style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'start'}}>
{projectFinancialData.map((record:any, index:any) => (
<div className="hover:cursor-pointer ml-4 mt-5 mb-4 inline-block" key={index} onClick={(r) => handleCardClick(record)}>
<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} TotalInvoicedAmount={record.totalInvoiced} TotalReceivedAmount={record.totalReceived} CashFlowStatus={record.cashFlowStatus} CostPerformanceIndex={record.cpi} ClickedIndex={isCardClickedIndex} Index={index}/>
</div>
))}
@@ -397,7 +401,7 @@ const columns2 = [
<CardHeader className="text-slate-500" title="Financial Status (by Client)"/>
<div style={{display:"inline-block",width:"99%",marginLeft:10}}>
{/* <CustomDatagrid rows={clientFinancialRows} columns={columns} columnWidth={200} dataGridHeight={300} checkboxSelection={true} onRowSelectionModelChange={handleSelectionChange} selectionModel={selectionModel}/> */}
<CustomDatagrid rows={clientFinancialRows} columns={columns} columnWidth={200} dataGridHeight={300}/>
<CustomDatagrid onRowClick={handleRowClick} rows={clientFinancialRows} columns={columns} columnWidth={200} dataGridHeight={300}/>
</div>
</Card>
<Card className="mt-5">


Ładowanie…
Anuluj
Zapisz