| @@ -84,6 +84,8 @@ export interface CreateProjectResponse { | |||
| category: string; | |||
| team: string; | |||
| client: string; | |||
| message: string; | |||
| errorPosition: string; | |||
| } | |||
| export const saveProject = async (data: CreateProjectInputs) => { | |||
| @@ -81,7 +81,7 @@ const hasErrorsInTab = ( | |||
| switch (tabIndex) { | |||
| case 0: | |||
| return ( | |||
| errors.projectName || errors.projectDescription || errors.clientId | |||
| errors.projectName || errors.projectDescription || errors.clientId || errors.projectCode | |||
| ); | |||
| case 2: | |||
| return ( | |||
| @@ -230,12 +230,17 @@ const CreateProject: React.FC<Props> = ({ | |||
| data.taskTemplateId = data.taskTemplateId === "All" ? undefined : data.taskTemplateId; | |||
| const response = await saveProject(data); | |||
| if (response.id > 0) { | |||
| if (response.id > 0 && response.message?.toLowerCase() === "success" && response.errorPosition === null) { | |||
| successDialog(successTitle, t).then(() => { | |||
| router.replace("/projects"); | |||
| }); | |||
| } else { | |||
| errorDialog(errorTitle, t).then(() => { | |||
| errorDialog(response.message ?? errorTitle, t).then(() => { | |||
| if (response.errorPosition !== null && response.errorPosition === "projectCode") { | |||
| formProps.setError("projectCode", { message: response.message, type: "invalid" }) | |||
| setTabIndex(0) | |||
| } | |||
| return false; | |||
| }); | |||
| } | |||
| @@ -257,7 +262,7 @@ const CreateProject: React.FC<Props> = ({ | |||
| if ( | |||
| errors.projectName || | |||
| errors.projectDescription || | |||
| // errors.projectCode || | |||
| errors.projectCode || | |||
| errors.clientId | |||
| ) { | |||
| setTabIndex(0); | |||
| @@ -216,13 +216,13 @@ const ProjectClientDetails: React.FC<Props> = ({ | |||
| <TextField | |||
| label={t("Project Code")} | |||
| fullWidth | |||
| disabled | |||
| disabled={isSubProject && mainProjects !== undefined} | |||
| {...register("projectCode", | |||
| // { | |||
| // required: "Project code required!", | |||
| // } | |||
| { | |||
| required: !(isSubProject && mainProjects !== undefined) && "Project code required!", | |||
| } | |||
| )} | |||
| // error={Boolean(errors.projectCode)} | |||
| error={Boolean(errors.projectCode)} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| @@ -348,6 +348,7 @@ const ProjectClientDetails: React.FC<Props> = ({ | |||
| <Checkbox | |||
| {...register("isClpProject")} | |||
| checked={Boolean(watch("isClpProject"))} | |||
| disabled={isSubProject && mainProjects !== undefined} | |||
| /> | |||
| <Typography variant="overline" display="inline"> | |||
| {t("CLP Project")} | |||
| @@ -67,6 +67,7 @@ import { | |||
| MAINTAIN_TEAM, | |||
| MAINTAIN_GROUP, | |||
| MAINTAIN_HOLIDAY, | |||
| VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING, | |||
| } from "@/middleware"; | |||
| import { SessionWithAbilities } from "../AppBar/NavigationToggle"; | |||
| import { authOptions } from "@/config/authConfig"; | |||
| @@ -131,6 +132,9 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | |||
| icon: <AccountTreeIcon />, | |||
| label: "Project Resource Consumption Ranking", | |||
| path: "/dashboard/ProjectResourceConsumptionRanking", | |||
| isHidden: ![VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING].some((ability) => | |||
| abilities!.includes(ability), | |||
| ) | |||
| }, | |||
| { | |||
| icon: <PeopleIcon />, | |||
| @@ -273,7 +277,7 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | |||
| abilities!.includes(ability), | |||
| ), | |||
| children: [ | |||
| { | |||
| { | |||
| icon: <GroupIcon />, | |||
| label: "Client", | |||
| path: "/settings/customer", | |||
| @@ -285,19 +289,19 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | |||
| path: "/settings/subsidiary", | |||
| isHidden: ![VIEW_SUBSIDIARY, MAINTAIN_SUBSIDIARY].some((ability) => abilities!.includes(ability),), | |||
| }, | |||
| { | |||
| icon: <Staff />, | |||
| label: "Staff", | |||
| { | |||
| icon: <Staff />, | |||
| label: "Staff", | |||
| path: "/settings/staff", | |||
| isHidden: ![VIEW_STAFF, MAINTAIN_STAFF].some((ability) => abilities!.includes(ability),), | |||
| }, | |||
| { | |||
| { | |||
| icon: <Company />, | |||
| label: "Company", | |||
| path: "/settings/company", | |||
| isHidden: ![VIEW_COMPANY, MAINTAIN_COMPANY].some((ability) => abilities!.includes(ability),), | |||
| }, | |||
| { | |||
| { | |||
| icon: <EmojiEventsIcon />, | |||
| label: "Skill", | |||
| path: "/settings/skill", | |||
| @@ -309,19 +313,19 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | |||
| path: "/settings/department", | |||
| isHidden: ![VIEW_DEPARTMENT, MAINTAIN_DEPARTMENT].some((ability) => abilities!.includes(ability),), | |||
| }, | |||
| { | |||
| { | |||
| icon: <Position />, | |||
| label: "Position", | |||
| path: "/settings/position", | |||
| isHidden: ![VIEW_POSITION, MAINTAIN_POSITION].some((ability) => abilities!.includes(ability),), | |||
| }, | |||
| { | |||
| { | |||
| icon: <Salary />, | |||
| label: "Salary", | |||
| path: "/settings/salary", | |||
| isHidden: ![VIEW_SALARY, MAINTAIN_SALARY].some((ability) => abilities!.includes(ability),), | |||
| }, | |||
| { | |||
| { | |||
| icon: <Team />, | |||
| label: "Team", | |||
| path: "/settings/team", | |||
| @@ -334,7 +338,7 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | |||
| path: "/settings/group", | |||
| isHidden: ![VIEW_GROUP, MAINTAIN_GROUP].some((ability) => abilities!.includes(ability),), | |||
| }, | |||
| { | |||
| { | |||
| icon: <Holiday />, | |||
| label: "Holiday", | |||
| path: "/settings/holiday", | |||
| @@ -57,6 +57,7 @@ export const [ | |||
| MAINTAIN_PROJECT, | |||
| DELETE_PROJECT, | |||
| MAINTAIN_TIMESHEET_FAST_TIME_ENTRY, | |||
| VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING, | |||
| ] = [ | |||
| 'MAINTAIN_USER', | |||
| 'MAINTAIN_TIMESHEET', | |||
| @@ -94,7 +95,8 @@ export const [ | |||
| 'VIEW_PROJECT', | |||
| 'MAINTAIN_PROJECT', | |||
| 'DELETE_PROJECT', | |||
| 'MAINTAIN_TIMESHEET_FAST_TIME_ENTRY' | |||
| 'MAINTAIN_TIMESHEET_FAST_TIME_ENTRY', | |||
| 'VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING' | |||
| ] | |||
| const PRIVATE_ROUTES = [ | |||
| @@ -233,6 +235,9 @@ export default async function middleware( | |||
| isAuth = [VIEW_DASHBOARD_ALL, VIEW_DASHBOARD_SELF].some((ability) => abilities.includes(ability)); | |||
| } | |||
| if (req.nextUrl.pathname.startsWith('/dashboard/ProjectResourceConsumptionRanking')) { | |||
| isAuth = [VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING].some((ability) => abilities.includes(ability)); | |||
| } | |||
| return isAuth | |||
| } | |||
| } | |||