From 383944b844823731486038916f147e859284c54a Mon Sep 17 00:00:00 2001 From: "cyril.tsui" Date: Wed, 10 Jul 2024 17:24:23 +0800 Subject: [PATCH] update workspace, export finanical status by client excel --- src/app/api/financialsummary/actions.ts | 30 ++++++++++++++++++- src/app/api/projects/index.ts | 2 ++ .../ProjectFinancialSummary.tsx | 9 ++++-- .../UserWorkspacePage/AssignedProjects.tsx | 6 ++-- .../UserWorkspacePage/ProjectGrid.tsx | 16 +++++----- .../UserWorkspacePage/UserWorkspacePage.tsx | 8 +++-- .../UserWorkspaceWrapper.tsx | 6 +++- src/middleware.ts | 6 +++- 8 files changed, 67 insertions(+), 16 deletions(-) diff --git a/src/app/api/financialsummary/actions.ts b/src/app/api/financialsummary/actions.ts index b56d3d2..d3adfb0 100644 --- a/src/app/api/financialsummary/actions.ts +++ b/src/app/api/financialsummary/actions.ts @@ -1,9 +1,10 @@ "use server"; -import { serverFetchJson } from "@/app/utils/fetchUtil"; +import { serverFetchBlob, serverFetchJson } from "@/app/utils/fetchUtil"; import { BASE_API_URL } from "@/config/api"; import { Dayjs } from "dayjs"; import { cache } from "react"; +import { FileResponse } from "../reports/actions"; export interface FinancialSummaryByClientResult { @@ -65,3 +66,30 @@ export const searchFinancialSummaryByProject = cache(async (teamId?: number, cus } }); + +export interface FinancialSummaryByClientExcel { + customerCode: string; + customerName: string; + projectNo: number; + totalFee: number; + cumulativeExpenditure: number; + totalInvoiced: number; + totalReceived: number; +} + +export interface ExportFinancialSummaryByClientExcel { + financialSummaryByClients: FinancialSummaryByClientExcel[] +} + +export const exportFinancialSummaryByClientExcel = cache(async (data: ExportFinancialSummaryByClientExcel) => { + const reportBlob = await serverFetchBlob( + `${BASE_API_URL}/dashboard/exportFinancialSummaryByClientExcel`, + { + method: "POST", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }, +); + +return reportBlob +}) diff --git a/src/app/api/projects/index.ts b/src/app/api/projects/index.ts index a7cb551..188e4ac 100644 --- a/src/app/api/projects/index.ts +++ b/src/app/api/projects/index.ts @@ -92,6 +92,8 @@ export interface AssignedProject extends ProjectWithTasks { // Manhour info hoursSpent: number; hoursSpentOther: number; + currentStaffHoursSpent: number; + currentStaffHoursSpentOther: number; hoursAllocated: number; } diff --git a/src/components/ProjectFinancialSummary/ProjectFinancialSummary.tsx b/src/components/ProjectFinancialSummary/ProjectFinancialSummary.tsx index 5e2d08d..bc5634a 100644 --- a/src/components/ProjectFinancialSummary/ProjectFinancialSummary.tsx +++ b/src/components/ProjectFinancialSummary/ProjectFinancialSummary.tsx @@ -19,9 +19,10 @@ import SearchBox, { Criterion } from "../SearchBox"; import ProgressByClientSearch from "@/components/ProgressByClientSearch"; import { Suspense } from "react"; import { fetchFinancialSummaryCard } from "@/app/api/financialsummary"; -import { searchFinancialSummaryByClient,searchFinancialSummaryByProject } from "@/app/api/financialsummary/actions"; +import { exportFinancialSummaryByClientExcel, searchFinancialSummaryByClient,searchFinancialSummaryByProject } from "@/app/api/financialsummary/actions"; import ProjectFinancialCard from "./ProjectFinancialCard"; import VisibilityIcon from '@mui/icons-material/Visibility'; +import { downloadFile } from "@/app/utils/commonUtil"; const ProjectFinancialSummary: React.FC = () => { const [SearchCriteria, setSearchCriteria] = React.useState({}); @@ -458,7 +459,11 @@ const columns2 = [ fetchProjectTableData(params.row.teamId,params.row.cid) }; - const handleExportByClient = () => { + const handleExportByClient = async () => { + const response = await exportFinancialSummaryByClientExcel({financialSummaryByClients: clientFinancialRows}) + if (response) { + downloadFile(new Uint8Array(response.blobValue), response.filename!!) + } console.log(clientFinancialRows) }; diff --git a/src/components/UserWorkspacePage/AssignedProjects.tsx b/src/components/UserWorkspacePage/AssignedProjects.tsx index 6baa133..850f201 100644 --- a/src/components/UserWorkspacePage/AssignedProjects.tsx +++ b/src/components/UserWorkspacePage/AssignedProjects.tsx @@ -16,9 +16,11 @@ import { Props as UserWorkspaceProps } from "./UserWorkspacePage"; interface Props { assignedProjects: UserWorkspaceProps["assignedProjects"]; + maintainNormalStaffWorkspaceAbility?: boolean; + maintainManagementStaffWorkspaceAbility?: boolean; } -const AssignedProjects: React.FC = ({ assignedProjects }) => { +const AssignedProjects: React.FC = ({ assignedProjects, maintainNormalStaffWorkspaceAbility, maintainManagementStaffWorkspaceAbility }) => { const { t } = useTranslation("home"); // Projects @@ -78,7 +80,7 @@ const AssignedProjects: React.FC = ({ assignedProjects }) => { - + ); }; diff --git a/src/components/UserWorkspacePage/ProjectGrid.tsx b/src/components/UserWorkspacePage/ProjectGrid.tsx index 275d48d..cf1665c 100644 --- a/src/components/UserWorkspacePage/ProjectGrid.tsx +++ b/src/components/UserWorkspacePage/ProjectGrid.tsx @@ -6,9 +6,11 @@ import { AssignedProject } from "@/app/api/projects"; interface Props { projects: AssignedProject[]; + maintainNormalStaffWorkspaceAbility?: boolean; + maintainManagementStaffWorkspaceAbility?: boolean; } -const ProjectGrid: React.FC = ({ projects }) => { +const ProjectGrid: React.FC = ({ projects, maintainNormalStaffWorkspaceAbility, maintainManagementStaffWorkspaceAbility }) => { const { t } = useTranslation("home"); return ( @@ -30,7 +32,7 @@ const ProjectGrid: React.FC = ({ projects }) => { {project.name} {/* Hours Spent */} - {t("Hours Spent:")} + {(Boolean(maintainNormalStaffWorkspaceAbility) || Boolean(maintainManagementStaffWorkspaceAbility)) && <>{t("Hours Spent:")} = ({ projects }) => { > {t("Normal")} - {manhourFormatter.format(project.hoursSpent)} + {manhourFormatter.format(Boolean(maintainManagementStaffWorkspaceAbility) ? project.hoursSpent : project.currentStaffHoursSpent)} = ({ projects }) => { > {t("(Others)")} {`(${manhourFormatter.format( - project.hoursSpentOther, + Boolean(maintainManagementStaffWorkspaceAbility) ? project.hoursSpentOther : project.currentStaffHoursSpentOther, )})`} - + } {/* Hours Allocated */} - = ({ projects }) => { {manhourFormatter.format(project.hoursAllocated)} - + } diff --git a/src/components/UserWorkspacePage/UserWorkspacePage.tsx b/src/components/UserWorkspacePage/UserWorkspacePage.tsx index 43ca3d9..2995890 100644 --- a/src/components/UserWorkspacePage/UserWorkspacePage.tsx +++ b/src/components/UserWorkspacePage/UserWorkspacePage.tsx @@ -35,7 +35,9 @@ export interface Props { holidays: HolidaysResult[]; teamTimesheets: TeamTimeSheets; teamLeaves: TeamLeaves; - fastEntryEnabled?: boolean; + fastEntryEnabled: boolean; + maintainNormalStaffWorkspaceAbility: boolean; + maintainManagementStaffWorkspaceAbility: boolean; } const menuItemSx: SxProps = { @@ -53,6 +55,8 @@ const UserWorkspacePage: React.FC = ({ teamTimesheets, teamLeaves, fastEntryEnabled, + maintainNormalStaffWorkspaceAbility, + maintainManagementStaffWorkspaceAbility, }) => { const [anchorEl, setAnchorEl] = useState(null); @@ -190,7 +194,7 @@ const UserWorkspacePage: React.FC = ({ timesheetRecords={defaultTimesheets} /> {assignedProjects.length > 0 ? ( - + ) : ( {t("You have no assigned projects!")} diff --git a/src/components/UserWorkspacePage/UserWorkspaceWrapper.tsx b/src/components/UserWorkspacePage/UserWorkspaceWrapper.tsx index 0d5a586..dda48be 100644 --- a/src/components/UserWorkspacePage/UserWorkspaceWrapper.tsx +++ b/src/components/UserWorkspacePage/UserWorkspaceWrapper.tsx @@ -12,7 +12,7 @@ import { } from "@/app/api/timesheets"; import { fetchHolidays } from "@/app/api/holidays"; import { getUserAbilities } from "@/app/utils/commonUtil"; -import { MAINTAIN_TIMESHEET_FAST_TIME_ENTRY } from "@/middleware"; +import { MAINTAIN_TIMESHEET_FAST_TIME_ENTRY, MAINTAIN_NORMAL_STAFF_WORKSPACE, MAINTAIN_MANAGEMENT_STAFF_WORKSPACE } from "@/middleware"; const UserWorkspaceWrapper: React.FC = async () => { const [ @@ -38,6 +38,8 @@ const UserWorkspaceWrapper: React.FC = async () => { ]); const fastEntryEnabled = abilities.includes(MAINTAIN_TIMESHEET_FAST_TIME_ENTRY) + const maintainNormalStaffWorkspaceAbility = abilities.includes(MAINTAIN_NORMAL_STAFF_WORKSPACE) + const maintainManagementStaffWorkspaceAbility = abilities.includes(MAINTAIN_MANAGEMENT_STAFF_WORKSPACE) return ( { holidays={holidays} // Change to access check fastEntryEnabled={fastEntryEnabled} + maintainNormalStaffWorkspaceAbility={maintainNormalStaffWorkspaceAbility} + maintainManagementStaffWorkspaceAbility={maintainManagementStaffWorkspaceAbility} /> ); }; diff --git a/src/middleware.ts b/src/middleware.ts index 2e71b46..cb48c5b 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -58,6 +58,8 @@ export const [ DELETE_PROJECT, MAINTAIN_TIMESHEET_FAST_TIME_ENTRY, VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING, + MAINTAIN_NORMAL_STAFF_WORKSPACE, + MAINTAIN_MANAGEMENT_STAFF_WORKSPACE, ] = [ 'MAINTAIN_USER', 'MAINTAIN_TIMESHEET', @@ -96,7 +98,9 @@ export const [ 'MAINTAIN_PROJECT', 'DELETE_PROJECT', 'MAINTAIN_TIMESHEET_FAST_TIME_ENTRY', - 'VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING' + 'VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING', + 'MAINTAIN_NORMAL_STAFF_WORKSPACE', + 'MAINTAIN_MANAGEMENT_STAFF_WORKSPACE' ] const PRIVATE_ROUTES = [