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