Bladeren bron

update

tags/Baseline_30082024_FRONTEND_UAT
MSI\derek 1 jaar geleden
bovenliggende
commit
e21e2cbda2
21 gewijzigde bestanden met toevoegingen van 246 en 35 verwijderingen
  1. +28
    -0
      src/app/(main)/analytics/StaffMonthlyWorkHoursAnalysisReport/page.tsx
  2. +17
    -10
      src/app/(main)/settings/skill/edit/page.tsx
  3. +7
    -3
      src/app/(main)/settings/staff/user/page.tsx
  4. +12
    -2
      src/app/(main)/settings/user/edit/page.tsx
  5. +1
    -1
      src/app/api/group/actions.ts
  6. +14
    -1
      src/app/api/reports/actions.ts
  7. +15
    -1
      src/app/api/reports/index.ts
  8. +6
    -0
      src/app/api/skill/index.ts
  9. +4
    -4
      src/app/api/staff/actions.ts
  10. +0
    -1
      src/app/api/user/actions.ts
  11. +10
    -0
      src/app/api/user/index.ts
  12. +1
    -1
      src/components/CreateGroup/CreateGroupWrapper.tsx
  13. +0
    -1
      src/components/CreateTeam/StaffAllocation.tsx
  14. +7
    -4
      src/components/EditSkill/EditSkillWrapper.tsx
  15. +0
    -1
      src/components/EditTeam/Allocation.tsx
  16. +9
    -4
      src/components/EditUser/EditUserWrapper.tsx
  17. +55
    -0
      src/components/GenerateMonthlyWorkHoursReport/GenerateMonthlyWorkHoursReport.tsx
  18. +38
    -0
      src/components/GenerateMonthlyWorkHoursReport/GenerateMonthlyWorkHoursReportLoading.tsx
  19. +19
    -0
      src/components/GenerateMonthlyWorkHoursReport/GenerateMonthlyWorkHoursReportWrapper.tsx
  20. +1
    -0
      src/components/GenerateMonthlyWorkHoursReport/index.ts
  21. +2
    -1
      src/components/NavigationContent/NavigationContent.tsx

+ 28
- 0
src/app/(main)/analytics/StaffMonthlyWorkHoursAnalysisReport/page.tsx Bestand weergeven

@@ -0,0 +1,28 @@
import { Metadata } from "next";
import { Suspense } from "react";
import { I18nProvider, getServerI18n } from "@/i18n";
import GenerateMonthlyWorkHoursReport from "@/components/GenerateMonthlyWorkHoursReport";
import { Typography } from "@mui/material";

export const metadata: Metadata = {
title: "Staff Monthly Work Hours Analysis Report",
};

const StaffMonthlyWorkHoursAnalysisReport: React.FC = async () => {
const { t } = await getServerI18n("User Group");

return (
<>
<Typography variant="h4" marginInlineEnd={2}>
{t("Staff Monthly Work Hours Analysis Report")}
</Typography>
<I18nProvider namespaces={["report", "common"]}>
<Suspense fallback={<GenerateMonthlyWorkHoursReport.Loading />}>
<GenerateMonthlyWorkHoursReport />
</Suspense>
</I18nProvider>
</>
);
};

export default StaffMonthlyWorkHoursAnalysisReport;

+ 17
- 10
src/app/(main)/settings/skill/edit/page.tsx Bestand weergeven

@@ -7,21 +7,28 @@ import { I18nProvider, getServerI18n } from "@/i18n";
import { Metadata } from "next"; import { Metadata } from "next";
import EditSkill from "@/components/EditSkill"; import EditSkill from "@/components/EditSkill";
import { Typography } from "@mui/material"; import { Typography } from "@mui/material";
import { fetchSkill } from "@/app/api/skill";


export interface searchParamsProps {
searchParams: { [key: string]: string | string[] | undefined };
}


const EditSkillPage: React.FC = async () => {
const EditSkillPage: React.FC<searchParamsProps> = async ({
searchParams,
}) => {
console.log(searchParams.id)
const { t } = await getServerI18n("staff"); const { t } = await getServerI18n("staff");


return ( return (
<>
<Typography variant="h4">{t("Edit Skill")}</Typography>
<I18nProvider namespaces={["team", "common"]}>
<Suspense fallback={<EditSkill.Loading />}>
<EditSkill />
</Suspense>
</I18nProvider>
{/* <EditStaff /> */}
</>
<>
<Typography variant="h4">{t("Edit Skill")}</Typography>
<I18nProvider namespaces={["team", "common"]}>
<Suspense fallback={<EditSkill.Loading />}>
<EditSkill id={parseInt(searchParams.id as string)}/>
</Suspense>
</I18nProvider>
</>
); );
}; };




+ 7
- 3
src/app/(main)/settings/staff/user/page.tsx Bestand weergeven

@@ -4,16 +4,20 @@ import { I18nProvider, getServerI18n } from "@/i18n";
import EditUser from "@/components/EditUser"; import EditUser from "@/components/EditUser";
import { Typography } from "@mui/material"; import { Typography } from "@mui/material";
import { Suspense } from "react"; import { Suspense } from "react";
import { searchParamsProps } from "../../skill/edit/page";
import { preloadUser } from "@/app/api/user";


const User: React.FC = async () => {
const User: React.FC<searchParamsProps> = async ({
searchParams
}) => {
const { t } = await getServerI18n("user"); const { t } = await getServerI18n("user");

preloadUser()
return ( return (
<> <>
<Typography variant="h4">{t("Edit User")}</Typography> <Typography variant="h4">{t("Edit User")}</Typography>
<I18nProvider namespaces={["user", "common"]}> <I18nProvider namespaces={["user", "common"]}>
<Suspense fallback={<EditUser.Loading />}> <Suspense fallback={<EditUser.Loading />}>
<EditUser />
<EditUser id={parseInt(searchParams.id as string)}/>
</Suspense> </Suspense>
</I18nProvider> </I18nProvider>
</> </>


+ 12
- 2
src/app/(main)/settings/user/edit/page.tsx Bestand weergeven

@@ -6,15 +6,25 @@ import { I18nProvider } from "@/i18n";
// import EditStaffWrapper from "@/components/EditStaff/EditStaffWrapper"; // import EditStaffWrapper from "@/components/EditStaff/EditStaffWrapper";
import { Metadata } from "next"; import { Metadata } from "next";
import EditUser from "@/components/EditUser"; import EditUser from "@/components/EditUser";
import { useRouter } from 'next/router';
import { getServerSideProps } from "next/dist/build/templates/pages";
import { searchParamsProps } from "../../skill/edit/page";
import { preloadUserDetail } from "@/app/api/user";




const EditUserPage: React.FC = () => {
const EditUserPage: React.FC<searchParamsProps> = async ({
searchParams
}) => {
const id = parseInt(searchParams.id as string)
preloadUserDetail(id)


return ( return (
<> <>
<I18nProvider namespaces={["team", "common"]}> <I18nProvider namespaces={["team", "common"]}>
<Suspense fallback={<EditUser.Loading />}> <Suspense fallback={<EditUser.Loading />}>
<EditUser />
<EditUser
// id={id}
/>
</Suspense> </Suspense>
</I18nProvider> </I18nProvider>
</> </>


+ 1
- 1
src/app/api/group/actions.ts Bestand weergeven

@@ -29,7 +29,7 @@ export interface record {
records: auth[]; records: auth[];
} }


export const fetchAuth = cache(async (target: string, id?: number) => {
export const fetchAuth = cache(async (target: string, id?: number ) => {
return serverFetchJson<record>(`${BASE_API_URL}/group/auth/${target}/${id ?? 0}`, { return serverFetchJson<record>(`${BASE_API_URL}/group/auth/${target}/${id ?? 0}`, {
next: { tags: ["auth"] }, next: { tags: ["auth"] },
}); });


+ 14
- 1
src/app/api/reports/actions.ts Bestand weergeven

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


import { serverFetchBlob, serverFetchJson } from "@/app/utils/fetchUtil"; import { serverFetchBlob, serverFetchJson } from "@/app/utils/fetchUtil";
import { ProjectCashFlowReportRequest } from ".";
import { MonthlyWorkHoursReportRequest, ProjectCashFlowReportRequest } from ".";
import { BASE_API_URL } from "@/config/api"; import { BASE_API_URL } from "@/config/api";


export interface FileResponse { export interface FileResponse {
@@ -19,5 +19,18 @@ export const fetchProjectCashFlowReport = async (data: ProjectCashFlowReportRequ
}, },
); );


return reportBlob
};

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

return reportBlob return reportBlob
}; };

+ 15
- 1
src/app/api/reports/index.ts Bestand weergeven

@@ -1,3 +1,5 @@
import { records } from "../staff/actions";

// - Project Cash Flow Report // - Project Cash Flow Report
export interface ProjectCashFlowReportFilter { export interface ProjectCashFlowReportFilter {
project: string[]; project: string[];
@@ -5,4 +7,16 @@ export interface ProjectCashFlowReportFilter {


export interface ProjectCashFlowReportRequest { export interface ProjectCashFlowReportRequest {
projectId: number; projectId: number;
}
}

// - Monthly Work Hours Report
export interface MonthlyWorkHoursReportFilter {
staff: string[];
date: any;
}

export interface MonthlyWorkHoursReportRequest {
id: number;
yearMonth: string;
}


+ 6
- 0
src/app/api/skill/index.ts Bestand weergeven

@@ -19,4 +19,10 @@ export interface SkillResult {
return serverFetchJson<SkillResult[]>(`${BASE_API_URL}/skill`, { return serverFetchJson<SkillResult[]>(`${BASE_API_URL}/skill`, {
next: { tags: ["sill"] }, next: { tags: ["sill"] },
}); });
});

export const fetchSkillDetail = cache(async (id: number) => {
return serverFetchJson<SkillResult[]>(`${BASE_API_URL}/skill/${id}`, {
next: { tags: ["sill"] },
});
}); });

+ 4
- 4
src/app/api/staff/actions.ts Bestand weergeven

@@ -39,9 +39,9 @@ export interface CreateStaffInputs {
name: string; name: string;
// team: Team[]; // team: Team[];
} }
export interface Staff4TransferList {
records: records[];
}
// export interface Staff4TransferList {
// records: records[];
// }


export const saveStaff = async (data: CreateStaffInputs) => { export const saveStaff = async (data: CreateStaffInputs) => {
return serverFetchJson(`${BASE_API_URL}/staffs/save`, { return serverFetchJson(`${BASE_API_URL}/staffs/save`, {
@@ -79,7 +79,7 @@ export const fetchStaffEdit = cache(async (id: number) => {
// }; // };


export const fetchStaffCombo = cache(async () => { export const fetchStaffCombo = cache(async () => {
return serverFetchJson<Staff4TransferList>(`${BASE_API_URL}/staffs/combo`, {
return serverFetchJson<records[]>(`${BASE_API_URL}/staffs/combo`, {
next: { tags: ["staffs"] }, next: { tags: ["staffs"] },
}); });
}); });


+ 0
- 1
src/app/api/user/actions.ts Bestand weergeven

@@ -19,7 +19,6 @@ export interface PasswordInputs {
newPasswordCheck: string; newPasswordCheck: string;
} }



export const fetchUserDetails = cache(async (id: number) => { export const fetchUserDetails = cache(async (id: number) => {
return serverFetchJson<UserDetail>(`${BASE_API_URL}/user/${id}`, { return serverFetchJson<UserDetail>(`${BASE_API_URL}/user/${id}`, {
next: { tags: ["user"] }, next: { tags: ["user"] },


+ 10
- 0
src/app/api/user/index.ts Bestand weergeven

@@ -38,8 +38,18 @@ export interface UserDetail {
fetchUser(); fetchUser();
}; };


export const preloadUserDetail = (id: number) => {
fetchUserDetail(id);
};

export const fetchUser = cache(async () => { export const fetchUser = cache(async () => {
return serverFetchJson<UserResult[]>(`${BASE_API_URL}/user`, { return serverFetchJson<UserResult[]>(`${BASE_API_URL}/user`, {
next: { tags: ["user"] }, next: { tags: ["user"] },
}); });
});

export const fetchUserDetail = cache(async (id: number) => {
return serverFetchJson<UserResult[]>(`${BASE_API_URL}/user/${id}`, {
next: { tags: ["user"] },
});
}); });

+ 1
- 1
src/components/CreateGroup/CreateGroupWrapper.tsx Bestand weergeven

@@ -11,7 +11,7 @@ interface SubComponents {
} }


const CreateGroupWrapper: React.FC & SubComponents = async () => { const CreateGroupWrapper: React.FC & SubComponents = async () => {
const records = await fetchAuth()
const records = await fetchAuth("group")
const users = await fetchUser() const users = await fetchUser()
console.log(users) console.log(users)
const auth = records.records as auth[] const auth = records.records as auth[]


+ 0
- 1
src/components/CreateTeam/StaffAllocation.tsx Bestand weergeven

@@ -13,7 +13,6 @@ import {
} from "react-hook-form"; } from "react-hook-form";
// import CreateTeamForm from "../CreateTeamForm"; // import CreateTeamForm from "../CreateTeamForm";
import { CreateTeamInputs } from "@/app/api/team/actions"; import { CreateTeamInputs } from "@/app/api/team/actions";
// import { Staff4TransferList, fetchStaffCombo } from "@/app/api/staff/actions";
import { StaffResult } from "@/app/api/staff"; import { StaffResult } from "@/app/api/staff";
import SearchResults, { Column } from "../SearchResults"; import SearchResults, { Column } from "../SearchResults";
import { Clear, PersonAdd, PersonRemove, Search } from "@mui/icons-material"; import { Clear, PersonAdd, PersonRemove, Search } from "@mui/icons-material";


+ 7
- 4
src/components/EditSkill/EditSkillWrapper.tsx Bestand weergeven

@@ -3,15 +3,18 @@ import EditSkill from "./EditSkill";
import EditSkillLoading from "./EditSkillLoading"; import EditSkillLoading from "./EditSkillLoading";
import { fetchStaff, fetchTeamLeads } from "@/app/api/staff"; import { fetchStaff, fetchTeamLeads } from "@/app/api/staff";
import { useSearchParams } from "next/navigation"; import { useSearchParams } from "next/navigation";
import { fetchSkill } from "@/app/api/skill";
import { fetchSkill, fetchSkillDetail } from "@/app/api/skill";


interface SubComponents { interface SubComponents {
Loading: typeof EditSkillLoading; Loading: typeof EditSkillLoading;
} }


const EditSkillWrapper: React.FC & SubComponents = async () => {
const skills = await fetchSkill()
console.log(skills)
interface Props {
id: number
}

const EditSkillWrapper: React.FC<Props> & SubComponents = async ({ id }) => {
const skills = await fetchSkillDetail(id)


return <EditSkill skills={skills}/>; return <EditSkill skills={skills}/>;
}; };


+ 0
- 1
src/components/EditTeam/Allocation.tsx Bestand weergeven

@@ -12,7 +12,6 @@ import {
useFormContext, useFormContext,
} from "react-hook-form"; } from "react-hook-form";
import { CreateTeamInputs } from "@/app/api/team/actions"; import { CreateTeamInputs } from "@/app/api/team/actions";
import { Staff4TransferList, fetchStaffCombo } from "@/app/api/staff/actions";
import { StaffResult, StaffTeamTable } from "@/app/api/staff"; import { StaffResult, StaffTeamTable } from "@/app/api/staff";
import SearchResults, { Column } from "../SearchResults"; import SearchResults, { Column } from "../SearchResults";
import { Clear, PersonAdd, PersonRemove, Search } from "@mui/icons-material"; import { Clear, PersonAdd, PersonRemove, Search } from "@mui/icons-material";


+ 9
- 4
src/components/EditUser/EditUserWrapper.tsx Bestand weergeven

@@ -5,15 +5,20 @@ import EditUserLoading from "./EditUserLoading";
import { useSearchParams } from "next/navigation"; import { useSearchParams } from "next/navigation";
import { fetchTeam, fetchTeamDetail } from "@/app/api/team"; import { fetchTeam, fetchTeamDetail } from "@/app/api/team";
import { fetchStaff } from "@/app/api/staff"; import { fetchStaff } from "@/app/api/staff";
import { fetchUser } from "@/app/api/user";
import { fetchUser, fetchUserDetail } from "@/app/api/user";


interface SubComponents { interface SubComponents {
Loading: typeof EditUserLoading; Loading: typeof EditUserLoading;
} }


const EditUserWrapper: React.FC & SubComponents = async () => {
const users = await fetchUser()
console.log(users)
interface Props {
// id: number
}
const EditUserWrapper: React.FC<Props> & SubComponents = async ({
// id
}) => {
// const users = await fetchUser()
// const userDetail = await fetchUserDetail(id)


return <EditUser /> return <EditUser />
}; };


+ 55
- 0
src/components/GenerateMonthlyWorkHoursReport/GenerateMonthlyWorkHoursReport.tsx Bestand weergeven

@@ -0,0 +1,55 @@
"use client";
import React, { useMemo } from "react";
import SearchBox, { Criterion } from "../SearchBox";
import { useTranslation } from "react-i18next";
import { ProjectResult } from "@/app/api/projects";
import { fetchMonthlyWorkHoursReport, fetchProjectCashFlowReport } from "@/app/api/reports/actions";
import { downloadFile } from "@/app/utils/commonUtil";
import { BASE_API_URL } from "@/config/api";
import { MonthlyWorkHoursReportFilter } from "@/app/api/reports";
import { records } from "@/app/api/staff/actions";
import { StaffResult } from "@/app/api/staff";

interface Props {
staffs: StaffResult[]
}

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

const GenerateMonthlyWorkHoursReport: React.FC<Props> = ({ staffs }) => {
const { t } = useTranslation();
const staffCombo = staffs.map(staff => `${staff.name} - ${staff.staffId}`)
console.log(staffs)

const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
() => [
{ label: t("Staff"),
paramName: "staff",
type: "select",
options: staffCombo,
needAll: false},
],
[t],
);

return (
<>
<SearchBox
criteria={searchCriteria}
onSearch={async (query: any) => {
if (query.staff.length > 0 && query.staff.toLocaleLowerCase() !== "all") {
const index = staffCombo.findIndex(staff => staff === query.staff)
const response = await fetchMonthlyWorkHoursReport({ id: staffs[index].id, yearMonth: "2023-03" })
if (response) {
downloadFile(new Uint8Array(response.blobValue), response.filename!!)
}
}
}
}
/>
</>
)
}

export default GenerateMonthlyWorkHoursReport

+ 38
- 0
src/components/GenerateMonthlyWorkHoursReport/GenerateMonthlyWorkHoursReportLoading.tsx Bestand weergeven

@@ -0,0 +1,38 @@
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 GenerateMonthlyWorkHoursReportLoading: React.FC = () => {
return (
<>
<Card>
<CardContent>
<Stack spacing={2}>
<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 GenerateMonthlyWorkHoursReportLoading;

+ 19
- 0
src/components/GenerateMonthlyWorkHoursReport/GenerateMonthlyWorkHoursReportWrapper.tsx Bestand weergeven

@@ -0,0 +1,19 @@
import React from "react";
import GenerateMonthlyWorkHoursReportLoading from "./GenerateMonthlyWorkHoursReportLoading";
import { fetchProjects } from "@/app/api/projects";
import GenerateMonthlyWorkHoursReport from "./GenerateMonthlyWorkHoursReport";
import { fetchStaff } from "@/app/api/staff";

interface SubComponents {
Loading: typeof GenerateMonthlyWorkHoursReportLoading;
}

const GenerateMonthlyWorkHoursReportWrapper: React.FC & SubComponents = async () => {
const staffs = await fetchStaff();

return <GenerateMonthlyWorkHoursReport staffs={staffs}/>;
};

GenerateMonthlyWorkHoursReportWrapper.Loading = GenerateMonthlyWorkHoursReportLoading;

export default GenerateMonthlyWorkHoursReportWrapper;

+ 1
- 0
src/components/GenerateMonthlyWorkHoursReport/index.ts Bestand weergeven

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

+ 2
- 1
src/components/NavigationContent/NavigationContent.tsx Bestand weergeven

@@ -128,6 +128,7 @@ const NavigationContent: React.FC<Props> = ({ abilities }) => {
{icon: <Analytics />, label:"Project P&L Report", path: "/analytics/ProjectPLReport"}, {icon: <Analytics />, label:"Project P&L Report", path: "/analytics/ProjectPLReport"},
{icon: <Analytics />, label:"Financial Status Report", path: "/analytics/FinancialStatusReport"}, {icon: <Analytics />, label:"Financial Status Report", path: "/analytics/FinancialStatusReport"},
{icon: <Analytics />, label:"Project Cash Flow Report", path: "/analytics/ProjectCashFlowReport"}, {icon: <Analytics />, label:"Project Cash Flow Report", path: "/analytics/ProjectCashFlowReport"},
{icon: <Analytics />, label:"Staff Monthly Work Hours Analysis Report", path: "/analytics/StaffMonthlyWorkHoursAnalysisReport"},
], ],
}, },
{ {
@@ -142,7 +143,7 @@ const NavigationContent: React.FC<Props> = ({ abilities }) => {
{ icon: <Position />, label: "Position", path: "/settings/position" }, { icon: <Position />, label: "Position", path: "/settings/position" },
{ icon: <Salary />, label: "Salary", path: "/settings/salary" }, { icon: <Salary />, label: "Salary", path: "/settings/salary" },
{ icon: <Team />, label: "Team", path: "/settings/team" }, { icon: <Team />, label: "Team", path: "/settings/team" },
{ icon: <ManageAccountsIcon />, label: "User", path: "/settings/user" },
// { icon: <ManageAccountsIcon />, label: "User", path: "/settings/user" },
{ icon: <ManageAccountsIcon />, label: "User Group", path: "/settings/group" }, { icon: <ManageAccountsIcon />, label: "User Group", path: "/settings/group" },
{ icon: <Holiday />, label: "Holiday", path: "/settings/holiday" }, { icon: <Holiday />, label: "Holiday", path: "/settings/holiday" },
], ],


Laden…
Annuleren
Opslaan