Przeglądaj źródła

update cross team report

(cherry picked from commit 13b6cc9f12)
tags/Baseline_30082024_FRONTEND_UAT
cyril.tsui 1 rok temu
rodzic
commit
0deeda45a9
5 zmienionych plików z 150 dodań i 11 usunięć
  1. +2
    -0
      src/app/api/reports/index.ts
  2. +18
    -4
      src/components/GenerateCrossTeamChargeReport/GenerateCrossTeamChargeReport.tsx
  3. +6
    -1
      src/components/GenerateCrossTeamChargeReport/GenerateCrossTeamChargeReportWrapper.tsx
  4. +52
    -2
      src/components/NavigationContent/NavigationContent.tsx
  5. +72
    -4
      src/middleware.ts

+ 2
- 0
src/app/api/reports/index.ts Wyświetl plik

@@ -120,8 +120,10 @@ export interface CostAndExpenseReportRequest {
// - Cross Team Charge Report
export interface CrossTeamChargeReportFilter {
month: string;
team: string[];
}

export interface CrossTeamChargeReportRequest {
month: string;
teamId: number | "All";
}

+ 18
- 4
src/components/GenerateCrossTeamChargeReport/GenerateCrossTeamChargeReport.tsx Wyświetl plik

@@ -6,15 +6,20 @@ import { useTranslation } from "react-i18next";
import { CrossTeamChargeReportFilter } from "@/app/api/reports";
import { fetchCrossTeamChargeReport } from "@/app/api/reports/actions";
import { downloadFile } from "@/app/utils/commonUtil";
import { TeamResult } from "@/app/api/team";
import { SessionStaff } from "@/config/authConfig";

interface Props {
teams: TeamResult[];
userStaff: SessionStaff;
}

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

const GenerateCrossTeamChargeReport: React.FC<Props> = () => {
const GenerateCrossTeamChargeReport: React.FC<Props> = ({ teams, userStaff }) => {
const { t } = useTranslation("report");
const teamCombo = teams.map(team => `${team.code} - ${team.name}`)

const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
() => [
@@ -23,6 +28,13 @@ const GenerateCrossTeamChargeReport: React.FC<Props> = () => {
paramName: "month",
type: "monthYear",
},
{
label: t("Team"),
paramName: "team",
type: "select",
options: teamCombo,
needAll: !Boolean(userStaff?.isTeamLead)
},
],
[t],
);
@@ -33,10 +45,12 @@ const GenerateCrossTeamChargeReport: React.FC<Props> = () => {
criteria={searchCriteria}
onSearch={async (query) => {

console.log(query.month)
if (Boolean(query.month)) {
console.log(query)
if (Boolean(query.month) && Boolean(query.team)) {
// const projectIndex = projectCombo.findIndex(({value}) => value === parseInt(query.project))
const response = await fetchCrossTeamChargeReport({ month: query.month })
const teamIndex = teamCombo.findIndex(team => team === query.team)

const response = await fetchCrossTeamChargeReport({ month: query.month, teamId: teamIndex >= 0 ? teams[teamIndex].id : "All", })
if (response) {
downloadFile(new Uint8Array(response.blobValue), response.filename!!)
}


+ 6
- 1
src/components/GenerateCrossTeamChargeReport/GenerateCrossTeamChargeReportWrapper.tsx Wyświetl plik

@@ -1,13 +1,18 @@
import React from "react";
import GenerateCrossTeamChargeReportLoading from "./GenerateCrossTeamChargeReportLoading";
import GenerateCrossTeamChargeReport from "./GenerateCrossTeamChargeReport";
import { fetchTeam } from "@/app/api/team";
import { getUserStaff } from "@/app/utils/commonUtil";

interface SubComponents {
Loading: typeof GenerateCrossTeamChargeReportLoading;
}

const GenerateCrossTeamChargeReportWrapper: React.FC & SubComponents = async () => {
return <GenerateCrossTeamChargeReport/>;

const [teams, userStaff] = await Promise.all([fetchTeam(), getUserStaff()])

return <GenerateCrossTeamChargeReport teams={!Boolean(userStaff?.isTeamLead) ? teams : teams.filter(team => team.id === userStaff?.teamId)} userStaff={userStaff}/>;
};

GenerateCrossTeamChargeReportWrapper.Loading = GenerateCrossTeamChargeReportLoading;


+ 52
- 2
src/components/NavigationContent/NavigationContent.tsx Wyświetl plik

@@ -36,7 +36,6 @@ import ManageAccountsIcon from "@mui/icons-material/ManageAccounts";
import EmojiEventsIcon from "@mui/icons-material/EmojiEvents";
import FileUploadIcon from '@mui/icons-material/FileUpload';
import {
GENERATE_REPORTS,
IMPORT_INVOICE,
IMPORT_RECEIPT,
MAINTAIN_PROJECT,
@@ -68,6 +67,16 @@ import {
MAINTAIN_GROUP,
MAINTAIN_HOLIDAY,
VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING,
GENERATE_LATE_START_REPORTS,
GENERATE_PROJECT_POTENTIAL_DELAY_REPORT,
GENERATE_RESOURCE_OVERCONSUMPTION_REPORT,
GENERATE_COST_ANT_EXPENSE_REPORT,
GENERATE_PROJECT_COMPLETION_REPORT,
GENERATE_PROJECT_PANDL_REPORT,
GENERATE_FINANCIAL_STATUS_REPORT,
GENERATE_PROJECT_CASH_FLOW_REPORT,
GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT,
GENERATE_CROSS_TEAM_CHARGE_REPORT,
} from "@/middleware";
import { SessionWithAbilities } from "../AppBar/NavigationToggle";
import { authOptions } from "@/config/authConfig";
@@ -180,7 +189,18 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => {
icon: <Analytics />,
label: "Analysis Report",
path: "",
isHidden: ![GENERATE_REPORTS].some((ability) =>
isHidden: ![
GENERATE_LATE_START_REPORTS,
GENERATE_PROJECT_POTENTIAL_DELAY_REPORT,
GENERATE_RESOURCE_OVERCONSUMPTION_REPORT,
GENERATE_COST_ANT_EXPENSE_REPORT,
GENERATE_PROJECT_COMPLETION_REPORT,
GENERATE_PROJECT_PANDL_REPORT,
GENERATE_FINANCIAL_STATUS_REPORT,
GENERATE_PROJECT_CASH_FLOW_REPORT,
GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT,
GENERATE_CROSS_TEAM_CHARGE_REPORT,
].some((ability) =>
abilities!.includes(ability),
),
children: [
@@ -188,26 +208,41 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => {
icon: <Analytics />,
label: "Late Start Report",
path: "/analytics/LateStartReport",
isHidden: ![GENERATE_LATE_START_REPORTS].some((ability) =>
abilities!.includes(ability),
),
},
{
icon: <Analytics />,
label: "Project Potential Delay Report",
path: "/analytics/ProjectPotentialDelayReport",
isHidden: ![GENERATE_PROJECT_POTENTIAL_DELAY_REPORT].some((ability) =>
abilities!.includes(ability),
),
},
{
icon: <Analytics />,
label: "Resource Overconsumption Report",
path: "/analytics/ResourceOverconsumptionReport",
isHidden: ![GENERATE_RESOURCE_OVERCONSUMPTION_REPORT].some((ability) =>
abilities!.includes(ability),
),
},
{
icon: <Analytics />,
label: "Cost and Expense Report",
path: "/analytics/CostandExpenseReport",
isHidden: ![GENERATE_COST_ANT_EXPENSE_REPORT].some((ability) =>
abilities!.includes(ability),
),
},
{
icon: <Analytics />,
label: "Project Completion Report",
path: "/analytics/ProjectCompletionReport",
isHidden: ![GENERATE_PROJECT_COMPLETION_REPORT].some((ability) =>
abilities!.includes(ability),
),
},
// {
// icon: <Analytics />,
@@ -223,26 +258,41 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => {
icon: <Analytics />,
label: "Project P&L Report",
path: "/analytics/ProjectPandLReport",
isHidden: ![GENERATE_PROJECT_COMPLETION_REPORT].some((ability) =>
abilities!.includes(ability),
),
},
{
icon: <Analytics />,
label: "Financial Status Report",
path: "/analytics/FinancialStatusReport",
isHidden: ![GENERATE_FINANCIAL_STATUS_REPORT].some((ability) =>
abilities!.includes(ability),
),
},
{
icon: <Analytics />,
label: "Project Cash Flow Report",
path: "/analytics/ProjectCashFlowReport",
isHidden: ![GENERATE_PROJECT_CASH_FLOW_REPORT].some((ability) =>
abilities!.includes(ability),
),
},
{
icon: <Analytics />,
label: "Staff Monthly Work Hours Analysis Report",
path: "/analytics/StaffMonthlyWorkHoursAnalysisReport",
isHidden: ![GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT].some((ability) =>
abilities!.includes(ability),
),
},
{
icon: <Analytics />,
label: "Cross Team Charge Report",
path: "/analytics/CrossTeamChargeReport",
isHidden: ![GENERATE_CROSS_TEAM_CHARGE_REPORT].some((ability) =>
abilities!.includes(ability),
),
},
],
},


+ 72
- 4
src/middleware.ts Wyświetl plik

@@ -48,7 +48,6 @@ export const [
VIEW_DASHBOARD_SELF,
VIEW_DASHBOARD_ALL,
IMPORT_INVOICE,
GENERATE_REPORTS,
VIEW_STAFF_PROFILE,
IMPORT_RECEIPT,
MAINTAIN_TASK_TEMPLATE,
@@ -60,6 +59,16 @@ export const [
VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING,
MAINTAIN_NORMAL_STAFF_WORKSPACE,
MAINTAIN_MANAGEMENT_STAFF_WORKSPACE,
GENERATE_LATE_START_REPORTS,
GENERATE_PROJECT_POTENTIAL_DELAY_REPORT,
GENERATE_RESOURCE_OVERCONSUMPTION_REPORT,
GENERATE_COST_ANT_EXPENSE_REPORT,
GENERATE_PROJECT_COMPLETION_REPORT,
GENERATE_PROJECT_PANDL_REPORT,
GENERATE_FINANCIAL_STATUS_REPORT,
GENERATE_PROJECT_CASH_FLOW_REPORT,
GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT,
GENERATE_CROSS_TEAM_CHARGE_REPORT,
] = [
'MAINTAIN_USER',
'MAINTAIN_TIMESHEET',
@@ -89,7 +98,6 @@ export const [
'VIEW_DASHBOARD_SELF',
'VIEW_DASHBOARD_ALL',
'IMPORT_INVOICE',
'GENERATE_REPORTS',
'VIEW_STAFF_PROFILE',
'IMPORT_RECEIPT',
'MAINTAIN_TASK_TEMPLATE',
@@ -100,7 +108,17 @@ export const [
'MAINTAIN_TIMESHEET_FAST_TIME_ENTRY',
'VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING',
'MAINTAIN_NORMAL_STAFF_WORKSPACE',
'MAINTAIN_MANAGEMENT_STAFF_WORKSPACE'
'MAINTAIN_MANAGEMENT_STAFF_WORKSPACE',
'GENERATE_LATE_START_REPORTS',
'GENERATE_PROJECT_POTENTIAL_DELAY_REPORT',
'GENERATE_RESOURCE_OVERCONSUMPTION_REPORT',
'GENERATE_COST_ANT_EXPENSE_REPORT',
'GENERATE_PROJECT_COMPLETION_REPORT',
'GENERATE_PROJECT_P&L_REPORT',
'GENERATE_FINANCIAL_STATUS_REPORT',
'GENERATE_PROJECT_CASH_FLOW_REPORT',
'GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT',
'GENERATE_CROSS_TEAM_CHARGE_REPORT',
]

const PRIVATE_ROUTES = [
@@ -224,7 +242,57 @@ export default async function middleware(
}

if (req.nextUrl.pathname.startsWith('/analytics')) {
isAuth = [GENERATE_REPORTS].some((ability) => abilities.includes(ability));
isAuth = [
GENERATE_LATE_START_REPORTS,
GENERATE_PROJECT_POTENTIAL_DELAY_REPORT,
GENERATE_RESOURCE_OVERCONSUMPTION_REPORT,
GENERATE_COST_ANT_EXPENSE_REPORT,
GENERATE_PROJECT_COMPLETION_REPORT,
GENERATE_PROJECT_PANDL_REPORT,
GENERATE_FINANCIAL_STATUS_REPORT,
GENERATE_PROJECT_CASH_FLOW_REPORT,
GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT,
GENERATE_CROSS_TEAM_CHARGE_REPORT,].some((ability) => abilities.includes(ability));
}

if (req.nextUrl.pathname.startsWith('/analytics/LateStartReport')) {
isAuth = [GENERATE_LATE_START_REPORTS].some((ability) => abilities.includes(ability));
}

if (req.nextUrl.pathname.startsWith('/analytics/ProjectPotentialDelayReport')) {
isAuth = [GENERATE_PROJECT_POTENTIAL_DELAY_REPORT].some((ability) => abilities.includes(ability));
}

if (req.nextUrl.pathname.startsWith('/analytics/ResourceOverconsumptionReport')) {
isAuth = [GENERATE_RESOURCE_OVERCONSUMPTION_REPORT].some((ability) => abilities.includes(ability));
}

if (req.nextUrl.pathname.startsWith('/analytics/CostandExpenseReport')) {
isAuth = [GENERATE_COST_ANT_EXPENSE_REPORT].some((ability) => abilities.includes(ability));
}

if (req.nextUrl.pathname.startsWith('/analytics/ProjectCompletionReport')) {
isAuth = [GENERATE_PROJECT_COMPLETION_REPORT].some((ability) => abilities.includes(ability));
}

if (req.nextUrl.pathname.startsWith('/analytics/ProjectPandLReport')) {
isAuth = [GENERATE_PROJECT_PANDL_REPORT].some((ability) => abilities.includes(ability));
}

if (req.nextUrl.pathname.startsWith('/analytics/FinancialStatusReport')) {
isAuth = [GENERATE_FINANCIAL_STATUS_REPORT].some((ability) => abilities.includes(ability));
}

if (req.nextUrl.pathname.startsWith('/analytics/ProjectCashFlowReport')) {
isAuth = [GENERATE_PROJECT_CASH_FLOW_REPORT].some((ability) => abilities.includes(ability));
}

if (req.nextUrl.pathname.startsWith('/analytics/StaffMonthlyWorkHoursAnalysisReport')) {
isAuth = [GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT].some((ability) => abilities.includes(ability));
}

if (req.nextUrl.pathname.startsWith('/analytics/CrossTeamChargeReport')) {
isAuth = [GENERATE_CROSS_TEAM_CHARGE_REPORT].some((ability) => abilities.includes(ability));
}

if (req.nextUrl.pathname.startsWith('/settings/staff/edit')) {


Ładowanie…
Anuluj
Zapisz