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