diff --git a/src/app/(main)/projects/create/not-found.tsx b/src/app/(main)/projects/create/not-found.tsx
new file mode 100644
index 0000000..002e9f5
--- /dev/null
+++ b/src/app/(main)/projects/create/not-found.tsx
@@ -0,0 +1,17 @@
+import { getServerI18n } from "@/i18n";
+import { Stack, Typography, Link } from "@mui/material";
+import NextLink from "next/link";
+
+export default async function NotFound() {
+ const { t } = await getServerI18n("projects", "common");
+
+ return (
+
+ {t("Not Found")}
+ {t("The create project page was not found!")}
+
+ {t("Return to all projects")}
+
+
+ );
+}
diff --git a/src/app/(main)/projects/create/page.tsx b/src/app/(main)/projects/create/page.tsx
index 1671262..62f2492 100644
--- a/src/app/(main)/projects/create/page.tsx
+++ b/src/app/(main)/projects/create/page.tsx
@@ -11,10 +11,13 @@ import {
} from "@/app/api/projects";
import { preloadStaff, preloadTeamLeads } from "@/app/api/staff";
import { fetchAllTasks, fetchTaskTemplates } from "@/app/api/tasks";
+import { getUserAbilities } from "@/app/utils/commonUtil";
import CreateProject from "@/components/CreateProject";
import { I18nProvider, getServerI18n } from "@/i18n";
+import { MAINTAIN_PROJECT } from "@/middleware";
import Typography from "@mui/material/Typography";
import { Metadata } from "next";
+import { notFound } from "next/navigation";
export const metadata: Metadata = {
title: "Create Project",
@@ -23,6 +26,12 @@ export const metadata: Metadata = {
const Projects: React.FC = async () => {
const { t } = await getServerI18n("projects");
+ const abilities = await getUserAbilities()
+
+ if (!abilities.includes(MAINTAIN_PROJECT)) {
+ notFound();
+ }
+
// Preload necessary dependencies
fetchAllTasks();
fetchTaskTemplates();
diff --git a/src/app/(main)/projects/createSub/page.tsx b/src/app/(main)/projects/createSub/page.tsx
index 3f474de..cc5be9c 100644
--- a/src/app/(main)/projects/createSub/page.tsx
+++ b/src/app/(main)/projects/createSub/page.tsx
@@ -13,9 +13,11 @@ import {
} from "@/app/api/projects";
import { preloadStaff, preloadTeamLeads } from "@/app/api/staff";
import { fetchAllTasks, fetchTaskTemplates } from "@/app/api/tasks";
+import { getUserAbilities } from "@/app/utils/commonUtil";
import { ServerFetchError } from "@/app/utils/fetchUtil";
import CreateProject from "@/components/CreateProject";
import { I18nProvider, getServerI18n } from "@/i18n";
+import { MAINTAIN_PROJECT } from "@/middleware";
import Typography from "@mui/material/Typography";
import { Metadata } from "next";
import { notFound } from "next/navigation";
@@ -26,6 +28,11 @@ export const metadata: Metadata = {
const Projects: React.FC = async () => {
const { t } = await getServerI18n("projects");
+ const abilities = await getUserAbilities()
+
+ if (!abilities.includes(MAINTAIN_PROJECT)) {
+ notFound();
+ }
// Preload necessary dependencies
fetchAllTasks();
diff --git a/src/app/(main)/projects/edit/page.tsx b/src/app/(main)/projects/edit/page.tsx
index 78e0ed1..55f401a 100644
--- a/src/app/(main)/projects/edit/page.tsx
+++ b/src/app/(main)/projects/edit/page.tsx
@@ -12,9 +12,11 @@ import {
} from "@/app/api/projects";
import { preloadStaff, preloadTeamLeads } from "@/app/api/staff";
import { fetchAllTasks, fetchTaskTemplates } from "@/app/api/tasks";
+import { getUserAbilities } from "@/app/utils/commonUtil";
import { ServerFetchError } from "@/app/utils/fetchUtil";
import CreateProject from "@/components/CreateProject";
import { I18nProvider, getServerI18n } from "@/i18n";
+import { MAINTAIN_PROJECT } from "@/middleware";
import Typography from "@mui/material/Typography";
import { isArray } from "lodash";
import { Metadata } from "next";
@@ -32,8 +34,9 @@ const Projects: React.FC = async ({ searchParams }) => {
const { t } = await getServerI18n("projects");
// Assume projectId is string here
const projectId = searchParams["id"];
+ const abilities = await getUserAbilities()
- if (!projectId || isArray(projectId)) {
+ if (!projectId || isArray(projectId) || abilities.includes(MAINTAIN_PROJECT)) {
notFound();
}
diff --git a/src/app/(main)/projects/editSub/page.tsx b/src/app/(main)/projects/editSub/page.tsx
index eb4f5c6..37279a1 100644
--- a/src/app/(main)/projects/editSub/page.tsx
+++ b/src/app/(main)/projects/editSub/page.tsx
@@ -13,8 +13,10 @@ import {
} from "@/app/api/projects";
import { preloadStaff, preloadTeamLeads } from "@/app/api/staff";
import { fetchAllTasks, fetchTaskTemplates } from "@/app/api/tasks";
+import { getUserAbilities } from "@/app/utils/commonUtil";
import CreateProject from "@/components/CreateProject";
import { I18nProvider, getServerI18n } from "@/i18n";
+import { MAINTAIN_PROJECT } from "@/middleware";
import Typography from "@mui/material/Typography";
import { isArray } from "lodash";
import { Metadata } from "next";
@@ -32,7 +34,8 @@ const Projects: React.FC = async ({ searchParams }) => {
const { t } = await getServerI18n("projects");
const projectId = searchParams["id"];
- if (!projectId || isArray(projectId)) {
+ const abilities = await getUserAbilities()
+ if (!projectId || isArray(projectId) || !abilities.includes(MAINTAIN_PROJECT)) {
notFound();
}
diff --git a/src/app/(main)/projects/not-found.tsx b/src/app/(main)/projects/not-found.tsx
new file mode 100644
index 0000000..6464b10
--- /dev/null
+++ b/src/app/(main)/projects/not-found.tsx
@@ -0,0 +1,17 @@
+import { getServerI18n } from "@/i18n";
+import { Stack, Typography, Link } from "@mui/material";
+import NextLink from "next/link";
+
+export default async function NotFound() {
+ const { t } = await getServerI18n("projects", "common");
+
+ return (
+
+ {t("Not Found")}
+ {t("The project page was not found!")}
+
+ {t("Return to home")}
+
+
+ );
+}
diff --git a/src/app/(main)/projects/page.tsx b/src/app/(main)/projects/page.tsx
index 7cf44d0..faaa2d9 100644
--- a/src/app/(main)/projects/page.tsx
+++ b/src/app/(main)/projects/page.tsx
@@ -1,13 +1,15 @@
import { fetchProjectCategories, fetchProjects, preloadProjects } from "@/app/api/projects";
+import { getUserAbilities } from "@/app/utils/commonUtil";
import ProjectSearch from "@/components/ProjectSearch";
import { getServerI18n } from "@/i18n";
+import { MAINTAIN_PROJECT, VIEW_PROJECT } from "@/middleware";
import Add from "@mui/icons-material/Add";
-import { ButtonGroup } from "@mui/material";
import Button from "@mui/material/Button";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import { Metadata } from "next";
import Link from "next/link";
+import { notFound } from "next/navigation";
import { Suspense } from "react";
export const metadata: Metadata = {
@@ -19,6 +21,10 @@ const Projects: React.FC = async () => {
// preloadProjects();
fetchProjectCategories();
const projects = await fetchProjects();
+ const abilities = await getUserAbilities()
+ if (!abilities.includes(VIEW_PROJECT)) {
+ notFound();
+ }
return (
<>
@@ -31,7 +37,7 @@ const Projects: React.FC = async () => {
{t("Projects")}
- {
>
{t("Create Project")}
-
+ }
}>
diff --git a/src/app/utils/commonUtil.ts b/src/app/utils/commonUtil.ts
index d942bec..9356047 100644
--- a/src/app/utils/commonUtil.ts
+++ b/src/app/utils/commonUtil.ts
@@ -1,8 +1,9 @@
+import { SessionWithTokens, authOptions } from "@/config/authConfig"
+import { getServerSession } from "next-auth"
export interface WildCard {
[key: string]: any;
}
-
export const dateInRange = (currentDate: string, startDate: string, endDate: string) => {
if (currentDate === undefined) {
@@ -46,6 +47,11 @@ export function readIntFromString(input: string): [string, number | null] | stri
const stringPart = parts.slice(0, parts.length - 1).join("-");
const intPartStr = parts[parts.length - 1];
const intPart = intPartStr ? parseInt(intPartStr, 10) : null;
-
+
return [stringPart, intPart];
- }
\ No newline at end of file
+}
+
+export const getUserAbilities = async () => {
+ const session = await getServerSession(authOptions) as SessionWithTokens;
+ return session?.abilities ?? []
+}
\ No newline at end of file
diff --git a/src/app/utils/fetchUtil.ts b/src/app/utils/fetchUtil.ts
index a97a09c..9d9a63d 100644
--- a/src/app/utils/fetchUtil.ts
+++ b/src/app/utils/fetchUtil.ts
@@ -22,7 +22,7 @@ export const serverFetch: typeof fetch = async (input, init) => {
const session = await getServerSession(authOptions);
const accessToken = session?.accessToken;
- console.log(accessToken);
+ // console.log(accessToken);
return fetch(input, {
...init,
headers: {
diff --git a/src/components/AppBar/AppBar.tsx b/src/components/AppBar/AppBar.tsx
index 57c190a..10cf3fe 100644
--- a/src/components/AppBar/AppBar.tsx
+++ b/src/components/AppBar/AppBar.tsx
@@ -16,7 +16,7 @@ export interface AppBarProps {
const AppBar: React.FC = async ({ avatarImageSrc, profileName }) => {
const session = await getServerSession(authOptions) as any;
const abilities: string[] = session.abilities
- console.log(abilities)
+ // console.log(abilities)
return (
diff --git a/src/components/CreateProject/CreateProject.tsx b/src/components/CreateProject/CreateProject.tsx
index 0161188..31ea689 100644
--- a/src/components/CreateProject/CreateProject.tsx
+++ b/src/components/CreateProject/CreateProject.tsx
@@ -50,6 +50,7 @@ import {
successDialog,
} from "../Swal/CustomAlerts";
import dayjs from "dayjs";
+import { DELETE_PROJECT } from "@/middleware";
export interface Props {
isEditMode: boolean;
@@ -70,6 +71,7 @@ export interface Props {
workNatures: WorkNature[];
allStaffs: StaffResult[];
grades: Grade[];
+ abilities: string[];
}
const hasErrorsInTab = (
@@ -113,6 +115,7 @@ const CreateProject: React.FC = ({
buildingTypes,
workNatures,
allStaffs,
+ abilities,
}) => {
const [serverError, setServerError] = useState("");
const [tabIndex, setTabIndex] = useState(0);
@@ -302,7 +305,7 @@ const CreateProject: React.FC = ({
{isEditMode && !(formProps.getValues("projectDeleted") === true) && (
{/* {!formProps.getValues("projectActualStart") && ( */}
- {formProps.getValues("projectStatus").toLowerCase() === "pending to start" && (
+ {formProps.getValues("projectStatus")?.toLowerCase() === "pending to start" && (