From f36e5147f9eb74de8b51a18e696b3a6cc7996d0a Mon Sep 17 00:00:00 2001 From: "MSI\\derek" Date: Fri, 24 May 2024 16:27:16 +0800 Subject: [PATCH] update cost and expense report --- .../analytics/CostandExpenseReport/page.tsx | 24 +++--- src/app/api/reports/actions.ts | 15 +++- src/app/api/reports/index.ts | 11 +++ .../CostAndExpenseReport.tsx | 85 +++++++++++++++++++ .../CostAndExpenseReportLoading.tsx | 41 +++++++++ .../CostAndExpenseReportWrapper.tsx | 20 +++++ src/components/CostAndExpenseReport/index.ts | 1 + .../ProjectCompletionReport.tsx | 4 - 8 files changed, 186 insertions(+), 15 deletions(-) create mode 100644 src/components/CostAndExpenseReport/CostAndExpenseReport.tsx create mode 100644 src/components/CostAndExpenseReport/CostAndExpenseReportLoading.tsx create mode 100644 src/components/CostAndExpenseReport/CostAndExpenseReportWrapper.tsx create mode 100644 src/components/CostAndExpenseReport/index.ts diff --git a/src/app/(main)/analytics/CostandExpenseReport/page.tsx b/src/app/(main)/analytics/CostandExpenseReport/page.tsx index cf5d160..8ed34e6 100644 --- a/src/app/(main)/analytics/CostandExpenseReport/page.tsx +++ b/src/app/(main)/analytics/CostandExpenseReport/page.tsx @@ -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 ( - + <> - Cost and Expense Report + {t("Cost and Expense Report")} - {/* }> - - */} - - + + }> + + + + ); }; export default CostandExpenseReport; diff --git a/src/app/api/reports/actions.ts b/src/app/api/reports/actions.ts index c5046cb..31c670f 100644 --- a/src/app/api/reports/actions.ts +++ b/src/app/api/reports/actions.ts @@ -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( + `${BASE_API_URL}/reports/costandexpenseReport`, + { + method: "POST", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }, + ); + + return reportBlob +}; + diff --git a/src/app/api/reports/index.ts b/src/app/api/reports/index.ts index cedc436..0d3ce1a 100644 --- a/src/app/api/reports/index.ts +++ b/src/app/api/reports/index.ts @@ -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; +} diff --git a/src/components/CostAndExpenseReport/CostAndExpenseReport.tsx b/src/components/CostAndExpenseReport/CostAndExpenseReport.tsx new file mode 100644 index 0000000..ede168e --- /dev/null +++ b/src/components/CostAndExpenseReport/CostAndExpenseReport.tsx @@ -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>; +type SearchParamNames = keyof SearchQuery; + +const CostAndExpenseReport: React.FC = ({ 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[] = 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 ( + <> + { + 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; diff --git a/src/components/CostAndExpenseReport/CostAndExpenseReportLoading.tsx b/src/components/CostAndExpenseReport/CostAndExpenseReportLoading.tsx new file mode 100644 index 0000000..fdc82f1 --- /dev/null +++ b/src/components/CostAndExpenseReport/CostAndExpenseReportLoading.tsx @@ -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 ( + <> + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default CostAndExpenseReportLoading; diff --git a/src/components/CostAndExpenseReport/CostAndExpenseReportWrapper.tsx b/src/components/CostAndExpenseReport/CostAndExpenseReportWrapper.tsx new file mode 100644 index 0000000..2b32c99 --- /dev/null +++ b/src/components/CostAndExpenseReport/CostAndExpenseReportWrapper.tsx @@ -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 +}; + +CostAndExpenseReportWrapper.Loading = CostAndExpenseReportLoading; + +export default CostAndExpenseReportWrapper; \ No newline at end of file diff --git a/src/components/CostAndExpenseReport/index.ts b/src/components/CostAndExpenseReport/index.ts new file mode 100644 index 0000000..208d8a4 --- /dev/null +++ b/src/components/CostAndExpenseReport/index.ts @@ -0,0 +1 @@ +export { default } from "./CostAndExpenseReportWrapper"; \ No newline at end of file diff --git a/src/components/ProjectCompletionReport/ProjectCompletionReport.tsx b/src/components/ProjectCompletionReport/ProjectCompletionReport.tsx index 66bf505..37fd6d6 100644 --- a/src/components/ProjectCompletionReport/ProjectCompletionReport.tsx +++ b/src/components/ProjectCompletionReport/ProjectCompletionReport.tsx @@ -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>; @@ -21,8 +19,6 @@ type SearchParamNames = keyof SearchQuery; const ProjectCompletionReport: React.FC = ( { - // team, - // customer } ) => { const { t } = useTranslation("report");