Browse Source

update cost and expense report

tags/Baseline_30082024_FRONTEND_UAT
MSI\derek 1 year ago
parent
commit
f36e5147f9
8 changed files with 186 additions and 15 deletions
  1. +14
    -10
      src/app/(main)/analytics/CostandExpenseReport/page.tsx
  2. +14
    -1
      src/app/api/reports/actions.ts
  3. +11
    -0
      src/app/api/reports/index.ts
  4. +85
    -0
      src/components/CostAndExpenseReport/CostAndExpenseReport.tsx
  5. +41
    -0
      src/components/CostAndExpenseReport/CostAndExpenseReportLoading.tsx
  6. +20
    -0
      src/components/CostAndExpenseReport/CostAndExpenseReportWrapper.tsx
  7. +1
    -0
      src/components/CostAndExpenseReport/index.ts
  8. +0
    -4
      src/components/ProjectCompletionReport/ProjectCompletionReport.tsx

+ 14
- 10
src/app/(main)/analytics/CostandExpenseReport/page.tsx View File

@@ -1,24 +1,28 @@
//src\app\(main)\analytics\CostandExpenseReport\page.tsx
import { Metadata } from "next";
import { I18nProvider } from "@/i18n";
import { I18nProvider, getServerI18n } from "@/i18n";
import Typography from "@mui/material/Typography";
import CostandExpenseReportComponent from "@/components/Report/CostandExpenseReport";
import { Suspense } from "react";
import CostAndExpenseReport from "@/components/CostAndExpenseReport";

export const metadata: Metadata = {
title: "Cost and Expense Report",
};

const CostandExpenseReport: React.FC = () => {
const CostandExpenseReport: React.FC = async () => {
const { t } = await getServerI18n("report");

return (
<I18nProvider namespaces={["analytics"]}>
<>
<Typography variant="h4" marginInlineEnd={2}>
Cost and Expense Report
{t("Cost and Expense Report")}
</Typography>
{/* <Suspense fallback={<ProgressCashFlowSearch.Loading />}>
<ProgressCashFlowSearch/>
</Suspense> */}
<CostandExpenseReportComponent />
</I18nProvider>
<I18nProvider namespaces={["analytics"]}>
<Suspense fallback={<CostAndExpenseReport.Loading />}>
<CostAndExpenseReport />
</Suspense>
</I18nProvider>
</>
);
};
export default CostandExpenseReport;

+ 14
- 1
src/app/api/reports/actions.ts View File

@@ -1,7 +1,7 @@
"use server";

import { serverFetchBlob } from "@/app/utils/fetchUtil";
import { MonthlyWorkHoursReportRequest, ProjectCashFlowReportRequest, LateStartReportRequest, ProjectResourceOverconsumptionReportRequest, ProjectPandLReportRequest, ProjectCompletionReportRequest, ProjectPotentialDelayReportRequest } from ".";
import { MonthlyWorkHoursReportRequest, ProjectCashFlowReportRequest, LateStartReportRequest, ProjectResourceOverconsumptionReportRequest, ProjectPandLReportRequest, ProjectCompletionReportRequest, ProjectPotentialDelayReportRequest, CostAndExpenseReportRequest } from ".";
import { BASE_API_URL } from "@/config/api";

export interface FileResponse {
@@ -109,3 +109,16 @@ export const fetchProjectPandLReport = async (data: ProjectPandLReportRequest) =
return reportBlob
};

export const fetchCostAndExpenseReport = async (data: CostAndExpenseReportRequest) => {
const reportBlob = await serverFetchBlob<FileResponse>(
`${BASE_API_URL}/reports/costandexpenseReport`,
{
method: "POST",
body: JSON.stringify(data),
headers: { "Content-Type": "application/json" },
},
);

return reportBlob
};


+ 11
- 0
src/app/api/reports/index.ts View File

@@ -88,3 +88,14 @@ export interface ProjectCompletionReportRequest {
endDate: String;
outstanding: Boolean;
}
export interface CostAndExpenseReportFilter {
team: string[];
customer: string[];
budgetPercentage: String[];
}

export interface CostAndExpenseReportRequest {
teamId: number | null;
clientId: number | null;
budgetPercentage: string;
}

+ 85
- 0
src/components/CostAndExpenseReport/CostAndExpenseReport.tsx View File

@@ -0,0 +1,85 @@
"use client";
import { CostAndExpenseReportFilter, CostAndExpenseReportRequest } from "@/app/api/reports";
import { useTranslation } from "react-i18next";
import SearchBox, { Criterion } from "../SearchBox";
import { useMemo } from "react";
import { TeamResult } from "@/app/api/team";
import { Customer } from "@/app/api/customer";
import { fetchCostAndExpenseReport } from "@/app/api/reports/actions";
import { downloadFile } from "@/app/utils/commonUtil";

interface Props {
team: TeamResult[];
customer: Customer[];
}

type SearchQuery = Partial<Omit<CostAndExpenseReportFilter, "id">>;
type SearchParamNames = keyof SearchQuery;

const CostAndExpenseReport: React.FC<Props> = ({ team, customer }) => {
const { t } = useTranslation("report");
const teamCombo = team.map((t) => `${t.name} - ${t.code}`);
const custCombo = customer.map(c => `${c.name} - ${c.code}`)
const percentList = [">50%", ">90%"]

const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
() => [
{
label: t("Team"),
paramName: "team",
type: "select",
options: teamCombo,
needAll: true,
},
{
label: t("Client"),
paramName: "customer",
type: "select",
options: custCombo,
needAll: true,
},
{
label: t("Remaining Percentage"),
paramName: "budgetPercentage",
type: "select",
options: percentList,
needAll: true,
},
],
[t]
);

return (
<>
<SearchBox
criteria={searchCriteria}
onSearch={async (query: any) => {
let index = 0
let postData: CostAndExpenseReportRequest = {
teamId: null,
clientId: null,
budgetPercentage: ">50%"
}
if (query.team.length > 0 && query.team.toLocaleLowerCase() !== "all") {
index = teamCombo.findIndex(team => team === query.team)
postData.teamId = team[index].id
}
if (query.customer.length > 0 && query.customer.toLocaleLowerCase() !== "all") {
index = custCombo.findIndex(customer => customer === query.customer)
postData.clientId = customer[index].id
}
if (query.budgetPercentage.length > 0 && query.budgetPercentage.toLocaleLowerCase() !== "all") {
postData.budgetPercentage = query.budgetPercentage
}
console.log(postData)
const response = await fetchCostAndExpenseReport(postData)
if (response) {
downloadFile(new Uint8Array(response.blobValue), response.filename!!)
}
}}
/>
</>
);
};

export default CostAndExpenseReport;

+ 41
- 0
src/components/CostAndExpenseReport/CostAndExpenseReportLoading.tsx View File

@@ -0,0 +1,41 @@
//src\components\LateStartReportGen\LateStartReportGenLoading.tsx
import Card from "@mui/material/Card";
import CardContent from "@mui/material/CardContent";
import Skeleton from "@mui/material/Skeleton";
import Stack from "@mui/material/Stack";
import React from "react";

// Can make this nicer
export const CostAndExpenseReportLoading: React.FC = () => {
return (
<>
<Card>
<CardContent>
<Stack spacing={2}>
<Skeleton variant="rounded" height={60} />
<Skeleton variant="rounded" height={60} />
<Skeleton variant="rounded" height={60} />
<Skeleton
variant="rounded"
height={50}
width={100}
sx={{ alignSelf: "flex-end" }}
/>
</Stack>
</CardContent>
</Card>
<Card>
<CardContent>
<Stack spacing={2}>
<Skeleton variant="rounded" height={40} />
<Skeleton variant="rounded" height={40} />
<Skeleton variant="rounded" height={40} />
<Skeleton variant="rounded" height={40} />
</Stack>
</CardContent>
</Card>
</>
);
};

export default CostAndExpenseReportLoading;

+ 20
- 0
src/components/CostAndExpenseReport/CostAndExpenseReportWrapper.tsx View File

@@ -0,0 +1,20 @@
import React from "react";
import { fetchAllCustomers } from "@/app/api/customer";
import { fetchTeam } from "@/app/api/team";
import CostAndExpenseReport from "./CostAndExpenseReport";
import CostAndExpenseReportLoading from "./CostAndExpenseReportLoading";

interface SubComponents {
Loading: typeof CostAndExpenseReportLoading;
}

const CostAndExpenseReportWrapper: React.FC & SubComponents = async () => {
const customers = await fetchAllCustomers()
const teams = await fetchTeam ()

return <CostAndExpenseReport team={teams} customer={customers}/>
};

CostAndExpenseReportWrapper.Loading = CostAndExpenseReportLoading;

export default CostAndExpenseReportWrapper;

+ 1
- 0
src/components/CostAndExpenseReport/index.ts View File

@@ -0,0 +1 @@
export { default } from "./CostAndExpenseReportWrapper";

+ 0
- 4
src/components/ProjectCompletionReport/ProjectCompletionReport.tsx View File

@@ -12,8 +12,6 @@ import { downloadFile } from "@/app/utils/commonUtil";
import { fetchProjectCompletionReport } from "@/app/api/reports/actions";

interface Props {
// team: TeamResult[]
// customer: Customer[]
}

type SearchQuery = Partial<Omit<ProjectCompletionReportFilter, "id">>;
@@ -21,8 +19,6 @@ type SearchParamNames = keyof SearchQuery;

const ProjectCompletionReport: React.FC<Props> = (
{
// team,
// customer
}
) => {
const { t } = useTranslation("report");


Loading…
Cancel
Save