diff --git a/src/app/(main)/analytics/ProjectCashFlowReport/page.tsx b/src/app/(main)/analytics/ProjectCashFlowReport/page.tsx index 301ef12..7ba5f7e 100644 --- a/src/app/(main)/analytics/ProjectCashFlowReport/page.tsx +++ b/src/app/(main)/analytics/ProjectCashFlowReport/page.tsx @@ -1,18 +1,23 @@ import { Metadata } from "next"; import { Suspense } from "react"; -import { I18nProvider } from "@/i18n"; +import { I18nProvider, getServerI18n } from "@/i18n"; import { fetchProjects } from "@/app/api/projects"; import GenerateProjectCashFlowReport from "@/components/GenerateProjectCashFlowReport"; +import { Typography } from "@mui/material"; export const metadata: Metadata = { title: "Project Cash Flow Report", }; const ProjectCashFlowReport: React.FC = async () => { + const { t } = await getServerI18n("reports"); fetchProjects(); return ( <> + + {t("Project Cash Flow Report")} + }> diff --git a/src/app/(main)/dashboard/ProjectStatusByClient/page.tsx b/src/app/(main)/dashboard/ProjectStatusByClient/page.tsx index a4df131..1b51537 100644 --- a/src/app/(main)/dashboard/ProjectStatusByClient/page.tsx +++ b/src/app/(main)/dashboard/ProjectStatusByClient/page.tsx @@ -1,14 +1,17 @@ + import { Metadata } from "next"; import { I18nProvider } from "@/i18n"; import DashboardPage from "@/components/DashboardPage/DashboardPage"; import DashboardPageButton from "@/components/DashboardPage/DashboardTabButton"; import ProgressByClientSearch from "@/components/ProgressByClientSearch"; -import { Suspense } from "react"; +import { Suspense} from "react"; import Tabs, { TabsProps } from "@mui/material/Tabs"; import Tab from "@mui/material/Tab"; import Typography from "@mui/material/Typography"; import ProgressByClient from "@/components/ProgressByClient"; import { preloadClientProjects } from "@/app/api/clientprojects"; +import { ClientProjectResult} from "@/app/api/clientprojects"; +import { useSearchParams } from 'next/navigation'; export const metadata: Metadata = { title: "Project Status by Client", @@ -24,6 +27,7 @@ const ProjectStatusByClient: React.FC = () => { }> + ); }; diff --git a/src/app/api/clientprojects/actions.ts b/src/app/api/clientprojects/actions.ts index 27b80df..9de9ea5 100644 --- a/src/app/api/clientprojects/actions.ts +++ b/src/app/api/clientprojects/actions.ts @@ -21,8 +21,15 @@ export interface ClientSubsidiaryProjectResult { comingPaymentMilestone: string; } -export const fetchAllClientSubsidiaryProjects = cache(async (customerId: number, subsidiaryId: number) => { - return serverFetchJson( - `${BASE_API_URL}/dashboard/searchCustomerSubsidiaryProject?customerId=${customerId}&subsidiaryId=${subsidiaryId}` - ); +export const fetchAllClientSubsidiaryProjects = cache(async (customerId: number, subsidiaryId?: number) => { + if (subsidiaryId === 0){ + return serverFetchJson( + `${BASE_API_URL}/dashboard/searchCustomerSubsidiaryProject?customerId=${customerId}` + ); + } else { + return serverFetchJson( + `${BASE_API_URL}/dashboard/searchCustomerSubsidiaryProject?customerId=${customerId}&subsidiaryId=${subsidiaryId}` + ); + } + }); diff --git a/src/app/api/reports/actions.ts b/src/app/api/reports/actions.ts index b06b66b..544ea2d 100644 --- a/src/app/api/reports/actions.ts +++ b/src/app/api/reports/actions.ts @@ -35,15 +35,31 @@ export const fetchMonthlyWorkHoursReport = async (data: MonthlyWorkHoursReportRe return reportBlob }; +// export const fetchLateStartReport = async (data: LateStartReportRequest) => { +// const response = await serverFetchBlob( +// `${BASE_API_URL}/reports/downloadLateStartReport`, +// { +// method: "POST", +// body: JSON.stringify(data), +// headers: { "Content-Type": "application/json" }, +// }, +// ); + +// return response; +// }; + export const fetchLateStartReport = async (data: LateStartReportRequest) => { - const reportBlob = await serverFetchBlob( - `${BASE_API_URL}/reports/downloadLateStartReport`, - { - method: "POST", - body: JSON.stringify(data), - headers: { "Content-Type": "application/json" }, - }, - ); + const response = await fetch(`${BASE_API_URL}/reports/downloadLateStartReport`, { + method: "POST", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }); + if (!response.ok) { + const errorText = await response.text(); // Attempt to read the response text + throw new Error(`Network response was not ok: ${response.status} - ${errorText}`); + } + const blob = await response.blob(); + return { fileBlob: blob, fileName: 'Late_Start_Report.xlsx' }; + +}; - return reportBlob -}; \ No newline at end of file diff --git a/src/app/api/reports/index.ts b/src/app/api/reports/index.ts index 1cea414..797c530 100644 --- a/src/app/api/reports/index.ts +++ b/src/app/api/reports/index.ts @@ -31,7 +31,7 @@ export interface LateStartReportFilter { } export interface LateStartReportRequest { - team: string[]; - client: string[]; + team: string; + client: string; date: any; } diff --git a/src/app/api/team/index.ts b/src/app/api/team/index.ts index d9d3b27..37fa5ac 100644 --- a/src/app/api/team/index.ts +++ b/src/app/api/team/index.ts @@ -3,34 +3,46 @@ import { BASE_API_URL } from "@/config/api"; import { cache } from "react"; import "server-only"; - export interface TeamResult { - action: any; - id: number; - teamId: number; - name: string; - code: string; - description: string; - staffId: string; - staffName: string; - posLabel: string; - posCode: string; - teamLead: number; - - } - + action: any; + id: number; + teamId: number; + name: string; + code: string; + description: string; + staffId: string; + staffName: string; + posLabel: string; + posCode: string; + teamLead: number; + +} + +export interface comboProp { + id: any; + label: string; +} + +export interface combo { + records: comboProp[]; +} + export const fetchTeam = cache(async () => { - return serverFetchJson(`${BASE_API_URL}/team`, { - next: { tags: ["team"] }, - }); + return serverFetchJson(`${BASE_API_URL}/team`, { + next: { tags: ["team"] }, }); +}); - export const preloadTeamDetail = () => { - fetchTeamDetail(); - }; +export const preloadTeamDetail = () => { + fetchTeamDetail(); +}; export const fetchTeamDetail = cache(async () => { - return serverFetchJson(`${BASE_API_URL}/team/detail`, { - next: { tags: ["team"] }, - }); - }); \ No newline at end of file + return serverFetchJson(`${BASE_API_URL}/team/detail`, { + next: { tags: ["team"] }, + }); +}); + +export const fetchTeamCombo = cache(async () => { + return serverFetchJson(`${BASE_API_URL}/team/combo`); +}); \ No newline at end of file diff --git a/src/app/api/user/actions.ts b/src/app/api/user/actions.ts index b6329a8..b655631 100644 --- a/src/app/api/user/actions.ts +++ b/src/app/api/user/actions.ts @@ -11,6 +11,7 @@ export interface UserInputs { email?: string; addAuthIds?: number[]; removeAuthIds?: number[]; + password?: string; } export interface PasswordInputs { @@ -50,4 +51,12 @@ export const changePassword = async (data: any) => { body: JSON.stringify(data), headers: { "Content-Type": "application/json" }, }); + }; + +export const adminChangePassword = async (data: any) => { + return serverFetchWithNoContent(`${BASE_API_URL}/user/admin-change-password`, { + method: "PATCH", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }); }; \ No newline at end of file diff --git a/src/app/api/user/index.ts b/src/app/api/user/index.ts index 369c62d..a8d1d70 100644 --- a/src/app/api/user/index.ts +++ b/src/app/api/user/index.ts @@ -34,6 +34,15 @@ export interface UserDetail { auths: any[] } + export type passwordRule = { + min: number; + max: number; + number: boolean; + upperEng: boolean; + lowerEng: boolean; + specialChar: boolean; + } + export const preloadUser = () => { fetchUser(); }; @@ -52,4 +61,10 @@ export interface UserDetail { return serverFetchJson(`${BASE_API_URL}/user/${id}`, { next: { tags: ["user"] }, }); + }); + + export const fetchPwRules = cache(async () => { + return serverFetchJson(`${BASE_API_URL}/user/password-rule`, { + next: { tags: ["pwRule"] }, + }); }); \ No newline at end of file diff --git a/src/components/CreateProject/CreateProject.tsx b/src/components/CreateProject/CreateProject.tsx index 4242afb..fac9c79 100644 --- a/src/components/CreateProject/CreateProject.tsx +++ b/src/components/CreateProject/CreateProject.tsx @@ -170,12 +170,12 @@ const CreateProject: React.FC = ({ // Tab - Milestone let projectTotal = 0 - const milestonesKeys = Object.keys(data.milestones) + const milestonesKeys = Object.keys(data.milestones).filter(key => taskGroupKeys.includes(key)) milestonesKeys.filter(key => Object.keys(data.taskGroups).includes(key)).forEach(key => { const { startDate, endDate, payments } = data.milestones[parseFloat(key)] if (!Boolean(startDate) || startDate === "Invalid Date" || !Boolean(endDate) || endDate === "Invalid Date" || new Date(startDate) > new Date(endDate)) { - formProps.setError("milestones", {message: "milestones is not valid", type: "invalid"}) + formProps.setError("milestones", { message: "milestones is not valid", type: "invalid" }) setTabIndex(3) hasErrors = true } @@ -183,8 +183,8 @@ const CreateProject: React.FC = ({ projectTotal += payments.reduce((acc, payment) => acc + payment.amount, 0) }) - if (projectTotal !== data.expectedProjectFee) { - formProps.setError("milestones", {message: "milestones is not valid", type: "invalid"}) + if (projectTotal !== data.expectedProjectFee || milestonesKeys.length !== taskGroupKeys.length) { + formProps.setError("milestones", { message: "milestones is not valid", type: "invalid" }) setTabIndex(3) hasErrors = true } @@ -219,7 +219,7 @@ const CreateProject: React.FC = ({ data.projectActualEnd = dayjs().format("YYYY-MM-DD"); } - data.taskTemplateId = data.taskTemplateId === "All" ? undefined : data.taskTemplateId; + data.taskTemplateId = data.taskTemplateId === "All" ? undefined : data.taskTemplateId; const response = await saveProject(data); if (response.id > 0) { @@ -293,7 +293,7 @@ const CreateProject: React.FC = ({ {isEditMode && !(formProps.getValues("projectDeleted") === true) && ( {/* {!formProps.getValues("projectActualStart") && ( */} - {formProps.getValues("projectStatus") === "Pending to Start" && ( + {formProps.getValues("projectStatus").toLowerCase() === "pending to start" && ( - )} + {formProps.getValues("projectStatus").toLowerCase() === "on-going" && ( + + )} {!( // formProps.getValues("projectActualStart") && // formProps.getValues("projectActualEnd") - formProps.getValues("projectStatus") === "Completed" || + formProps.getValues("projectStatus") === "Completed" || formProps.getValues("projectStatus") === "Deleted" ) && ( diff --git a/src/i18n/en/common.json b/src/i18n/en/common.json index a7d019a..57932c1 100644 --- a/src/i18n/en/common.json +++ b/src/i18n/en/common.json @@ -19,6 +19,7 @@ "Details": "Details", "Delete": "Delete", + "Download": "Download", "Search": "Search", "Search Criteria": "Search Criteria", "Cancel": "Cancel", diff --git a/src/i18n/zh/common.json b/src/i18n/zh/common.json index 4ff2fcf..ffcec1d 100644 --- a/src/i18n/zh/common.json +++ b/src/i18n/zh/common.json @@ -17,6 +17,7 @@ "Details": "詳情", "Delete": "刪除", + "Download": "下載", "Search": "搜尋", "Search Criteria": "搜尋條件", "Cancel": "取消",