diff --git a/src/app/dashboard/roles/page.tsx b/src/app/dashboard/roles/page.tsx
index 59ec619..bd9d1a6 100644
--- a/src/app/dashboard/roles/page.tsx
+++ b/src/app/dashboard/roles/page.tsx
@@ -1,6 +1,6 @@
import checkMultiplePermissions from "@/modules/auth/utils/checkMultiplePermissions";
import unauthorized from "@/modules/dashboard/utils/unauthorized";
-import getAllRoles from "@/modules/role/actions/getAllRoles";
+import getAllRoles from "@/modules/role/services/getAllRoles";
import RolesTable from "@/modules/role/tables/RolesTable/RolesTable";
import { Card, Stack, Title } from "@mantine/core";
import { Metadata } from "next";
@@ -21,14 +21,13 @@ export default async function RolesPage() {
if (!permissions.readAll) unauthorized()
- const res = await getAllRoles();
- if (!res.success) throw new Error("Error while fetch roles");
+ const roles = await getAllRoles();
return (
Roles
-
+
);
diff --git a/src/modules/dashboard/services/checkPermission.ts b/src/modules/dashboard/services/checkPermission.ts
deleted file mode 100644
index a75a6c5..0000000
--- a/src/modules/dashboard/services/checkPermission.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import getCurrentUser from "@/modules/auth/utils/getCurrentUser";
-import "server-only";
-
-/**
- * Checks if the current user has the specified permissions.
- *
- * Deprecated. Use `checkPermission()` from auth module instead.
- *
- * @deprecated
- * @param permission - The specific permission to check. If it's "guest-only", the function returns true if the user is not authenticated. If it's "authenticated-only", it returns true if the user is authenticated. For other permissions, it checks against the user's roles and direct permissions.
- * @param currentUser - Optional. The current user object. If not provided, the function retrieves the current user.
- * @returns true if the user has the required permission, otherwise false.
- */
-export default async function checkPermission(
- permission?: "guest-only" | "authenticated-only" | (string & {}),
- currentUser?: Awaited>
-): Promise {
- // Allow if no specific permission is required.
- if (!permission) return true;
-
- // Retrieve current user if not provided.
- const user = currentUser ?? (await getCurrentUser());
-
- // Handle non-authenticated users.
- if (!user) {
- return permission === "guest-only";
- }
-
- // Allow authenticated users if the permission is 'authenticated-only'.
- if (permission === "authenticated-only") {
- return true;
- }
-
- // Short-circuit for super-admin role to allow all permissions.
- if (user.roles.some((role) => role.code === "super-admin")) return true;
-
- // Aggregate all role codes and direct permissions into a set for efficient lookup.
- const permissions = new Set([
- ...user.roles.map((role) => role.code),
- ...user.directPermissions.map((dp) => dp.code),
- ]);
-
- // Check if the user has the required permission.
- return permissions.has(permission);
-}
diff --git a/src/modules/role/actions/deleteRole.ts b/src/modules/role/actions/deleteRoleAction.ts
similarity index 67%
rename from src/modules/role/actions/deleteRole.ts
rename to src/modules/role/actions/deleteRoleAction.ts
index 2f37fc3..ef3998d 100644
--- a/src/modules/role/actions/deleteRole.ts
+++ b/src/modules/role/actions/deleteRoleAction.ts
@@ -1,22 +1,19 @@
"use server";
-import db from "@/core/db";
-import prisma from "@/db";
-import checkPermission from "@/modules/dashboard/services/checkPermission";
+import checkPermission from "@/modules/auth/utils/checkPermission";
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
import handleCatch from "@/modules/dashboard/utils/handleCatch";
import unauthorized from "@/modules/dashboard/utils/unauthorized";
import { revalidatePath } from "next/cache";
-import { notFound } from "next/navigation";
+import deleteRole from "../services/deleteRole";
-export default async function deleteRole(
+export default async function deleteRoleAction(
id: string
): Promise {
try {
if (!(await checkPermission("roles.delete"))) return unauthorized();
- const role = await db.role.delete({
- where: { id },
- });
+
+ await deleteRole(id);
revalidatePath(".");
diff --git a/src/modules/role/actions/getAllRoles.ts b/src/modules/role/actions/getAllRoles.ts
deleted file mode 100644
index c3b52e6..0000000
--- a/src/modules/role/actions/getAllRoles.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-"use server";
-import prisma from "@/db";
-import checkPermission from "@/modules/dashboard/services/checkPermission";
-import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
-import handleCatch from "@/modules/dashboard/utils/handleCatch";
-import unauthorized from "@/modules/dashboard/utils/unauthorized";
-import "server-only";
-import Role from "../types/Role";
-import db from "@/core/db";
-
-/**
- * Retrieves all roles along with the count of associated permissions and users.
- * Authorization check is performed for the operation.
- *
- * @returns An array of role objects each including details and counts of related permissions and users.
- */
-export default async function getAllRoles(): Promise<
- ServerResponseAction
-> {
- try {
- // Authorization check
- if (!(await checkPermission("roles.getAll"))) {
- unauthorized();
- }
-
- // Fetch roles from the database
- const roles = await db.role.findMany({
- include: {
- _count: {
- select: {
- permissions: true,
- users: true,
- },
- },
- },
- });
-
- // Transform the data into the desired format
- const result = roles.map(
- ({ id, code, name, description, isActive, _count }) => ({
- id,
- code,
- name,
- description,
- isActive,
- permissionCount: _count.permissions,
- userCount: _count.users,
- })
- );
-
- return {
- success: true,
- data: result
- }
- } catch (error) {
- return handleCatch(error)
- }
-}
diff --git a/src/modules/role/actions/getAllRolesAction.ts b/src/modules/role/actions/getAllRolesAction.ts
new file mode 100644
index 0000000..2493fe3
--- /dev/null
+++ b/src/modules/role/actions/getAllRolesAction.ts
@@ -0,0 +1,34 @@
+"use server";
+import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
+import handleCatch from "@/modules/dashboard/utils/handleCatch";
+import unauthorized from "@/modules/dashboard/utils/unauthorized";
+import Role from "../types/Role";
+import checkPermission from "@/modules/auth/utils/checkPermission";
+import getAllRoles from "../services/getAllRoles";
+
+/**
+ * Retrieves all roles along with the count of associated permissions and users.
+ * Authorization check is performed for the operation.
+ *
+ * @returns An array of role objects each including details and counts of related permissions and users.
+ */
+export default async function getAllRolesAction(): Promise<
+ ServerResponseAction
+> {
+ try {
+ // Authorization check
+ if (!(await checkPermission("roles.readAll"))) {
+ return unauthorized();
+ }
+
+ // Fetch roles from the database
+ const roles = await getAllRoles()
+
+ return {
+ success: true,
+ data: roles
+ }
+ } catch (error) {
+ return handleCatch(error)
+ }
+}
diff --git a/src/modules/role/actions/getRoleById.ts b/src/modules/role/actions/getRoleById.ts
deleted file mode 100644
index 1351cbf..0000000
--- a/src/modules/role/actions/getRoleById.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-"use server";
-
-import db from "@/core/db";
-import prisma from "@/db";
-import checkPermission from "@/modules/dashboard/services/checkPermission";
-import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
-import handleCatch from "@/modules/dashboard/utils/handleCatch";
-import unauthorized from "@/modules/dashboard/utils/unauthorized";
-
-type RoleData = {
- id: string;
- code: string;
- name: string;
- description: string;
- isActive: boolean;
- permissions: {
- id: string;
- code: string;
- name: string;
- }[]
-}
-
-export default async function getRoleById(id: string): Promise>{
- try{
-
- if (!(await checkPermission("roles.read"))) return unauthorized();
-
- const role = await db.role.findFirst({
- where: { id },
- select: {
- code: true,
- description: true,
- id: true,
- isActive: true,
- name: true,
- permissions: {
- select: {
- id: true,
- code: true,
- name: true,
- },
- },
- },
- });
-
- if (!role) {
- throw new Error("Permission not found")
- }
-
- return {
- success: true,
- message: "Role fetched successfully",
- data: role,
- };
- } catch (e){
- return handleCatch(e)
- }
-}
diff --git a/src/modules/role/actions/getRoleByIdAction.ts b/src/modules/role/actions/getRoleByIdAction.ts
new file mode 100644
index 0000000..cfd68b7
--- /dev/null
+++ b/src/modules/role/actions/getRoleByIdAction.ts
@@ -0,0 +1,24 @@
+"use server";
+
+import checkPermission from "@/modules/auth/utils/checkPermission";
+import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
+import handleCatch from "@/modules/dashboard/utils/handleCatch";
+import unauthorized from "@/modules/dashboard/utils/unauthorized";
+import getRoleById from "../services/getRoleById";
+
+export default async function getRoleByIdAction(id: string): Promise>>>{
+ try{
+
+ if (!(await checkPermission("roles.read"))) return unauthorized();
+
+ const role = await getRoleById(id)
+
+ return {
+ success: true,
+ message: "Role fetched successfully",
+ data: role,
+ };
+ } catch (e){
+ return handleCatch(e)
+ }
+}
diff --git a/src/modules/role/actions/upsertRole.ts b/src/modules/role/actions/upsertRole.ts
deleted file mode 100644
index 0bc1533..0000000
--- a/src/modules/role/actions/upsertRole.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-"use server";
-
-import roleFormDataSchema, { RoleFormData } from "../formSchemas/RoleFormData";
-import mapObjectToFirstValue from "@/utils/mapObjectToFirstValue";
-import prisma from "@/db";
-import { revalidatePath } from "next/cache";
-import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
-import checkPermission from "@/modules/dashboard/services/checkPermission";
-import unauthorized from "@/modules/dashboard/utils/unauthorized";
-import DashboardError from "@/modules/dashboard/errors/DashboardError";
-import handleCatch from "@/modules/dashboard/utils/handleCatch";
-import db from "@/core/db";
-
-/**
- * Upserts a role based on the provided RoleFormData.
- * If the role already exists (determined by `id`), it updates the role; otherwise, it creates a new role.
- * Authorization checks are performed based on whether it's a create or update operation.
- *
- * @param data - The data for creating or updating the role.
- * @returns An object containing the success status, message, and any errors.
- */
-export default async function upsertRole(
- data: RoleFormData
-): Promise {
- try {
- const isInsert = !data.id;
-
- // Authorization check
- const permissionType = isInsert ? "role.create" : "role.update";
- if (!(await checkPermission(permissionType))) {
- return unauthorized();
- }
-
- // Validate form data
- const validatedFields = roleFormDataSchema.safeParse(data);
- if (!validatedFields.success) {
- throw new DashboardError({
- errorCode: "INVALID_FORM_DATA",
- formErrors: mapObjectToFirstValue(
- validatedFields.error.flatten().fieldErrors
- ),
- });
- }
- const roleData = {
- code: validatedFields.data.code,
- description: validatedFields.data.description,
- name: validatedFields.data.name,
- isActive: validatedFields.data.isActive,
- };
-
- const permissionIds = validatedFields.data.permissions.map(
- (permission) => ({ code: permission })
- );
-
- // Database operation
- if (isInsert) {
- if (
- await db.role.findFirst({
- where: {
- code: roleData.code,
- },
- })
- ) {
- throw new DashboardError({
- errorCode: "INVALID_FORM_DATA",
- formErrors: {
- code: "The code is already exists",
- },
- });
- }
- await db.role.create({
- data: {
- ...roleData,
- permissions: {
- connect: permissionIds,
- },
- },
- });
- } else {
- await db.role.update({
- where: { id: validatedFields.data.id! },
- data: { ...roleData, permissions: { connect: permissionIds } },
- });
- }
-
- // Revalidate the cache
- revalidatePath(".");
-
- // Return success message
- return {
- success: true,
- message: `Role ${validatedFields.data.name} has been successfully ${
- isInsert ? "created" : "updated"
- }.`,
- };
- } catch (error) {
- return handleCatch(error);
- }
-}
diff --git a/src/modules/role/actions/upsertRoleAction.ts b/src/modules/role/actions/upsertRoleAction.ts
new file mode 100644
index 0000000..e2c51e1
--- /dev/null
+++ b/src/modules/role/actions/upsertRoleAction.ts
@@ -0,0 +1,50 @@
+"use server";
+
+import roleFormDataSchema, { RoleFormData } from "../formSchemas/RoleFormData";
+import mapObjectToFirstValue from "@/utils/mapObjectToFirstValue";
+import { revalidatePath } from "next/cache";
+import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
+import unauthorized from "@/modules/dashboard/utils/unauthorized";
+import DashboardError from "@/modules/dashboard/errors/DashboardError";
+import handleCatch from "@/modules/dashboard/utils/handleCatch";
+import db from "@/core/db";
+import checkPermission from "@/modules/auth/utils/checkPermission";
+import upsertRole from "../services/upsertRole";
+
+/**
+ * Upserts a role based on the provided RoleFormData.
+ * If the role already exists (determined by `id`), it updates the role; otherwise, it creates a new role.
+ * Authorization checks are performed based on whether it's a create or update operation.
+ *
+ * @param data - The data for creating or updating the role.
+ * @returns An object containing the success status, message, and any errors.
+ */
+export default async function upsertRoleAction(
+ data: RoleFormData
+): Promise {
+ try {
+ const isInsert = !data.id;
+
+ // Authorization check
+ const permissionType = isInsert ? "roles.create" : "roles.update";
+ if (!(await checkPermission(permissionType))) {
+ return unauthorized();
+ }
+
+ // Validate form data
+ const result = await upsertRole(data);
+
+ // Revalidate the cache
+ revalidatePath(".");
+
+ // Return success message
+ return {
+ success: true,
+ message: `Role ${result.name} has been successfully ${
+ isInsert ? "created" : "updated"
+ }.`,
+ };
+ } catch (error) {
+ return handleCatch(error);
+ }
+}
diff --git a/src/modules/role/modals/DeleteModal.tsx b/src/modules/role/modals/DeleteModal.tsx
index 82a0dea..872b3f7 100644
--- a/src/modules/role/modals/DeleteModal.tsx
+++ b/src/modules/role/modals/DeleteModal.tsx
@@ -9,7 +9,7 @@ import {
} from "@mantine/core";
import { showNotification } from "@/utils/notifications";
import withServerAction from "@/modules/dashboard/utils/withServerAction";
-import deleteRole from "../actions/deleteRole";
+import deleteRoleAction from "../actions/deleteRoleAction";
import ClientError from "@/core/error/ClientError";
export interface DeleteModalProps {
@@ -38,7 +38,7 @@ export default function DeleteModal(props: DeleteModalProps) {
if (!props.data?.id) return;
setSubmitting(true);
- withServerAction(deleteRole, props.data!.id)
+ withServerAction(deleteRoleAction, props.data!.id)
.then((response) => {
showNotification(
response.message ?? "Role deleted successfully"
diff --git a/src/modules/role/modals/FormModal.tsx b/src/modules/role/modals/FormModal.tsx
index 49b57b2..4dc5202 100644
--- a/src/modules/role/modals/FormModal.tsx
+++ b/src/modules/role/modals/FormModal.tsx
@@ -21,8 +21,8 @@ import { TbDeviceFloppy } from "react-icons/tb";
import roleFormDataSchema, { RoleFormData } from "../formSchemas/RoleFormData";
import getAllPermissions from "@/modules/permission/actions/getAllPermissions";
import withServerAction from "@/modules/dashboard/utils/withServerAction";
-import getRoleById from "../actions/getRoleById";
-import upsertRole from "../actions/upsertRole";
+import getRoleByIdAction from "../actions/getRoleByIdAction";
+import upsertRoleAction from "../actions/upsertRoleAction";
import ClientError from "@/core/error/ClientError";
export interface ModalProps {
@@ -96,7 +96,7 @@ export default function FormModal(props: ModalProps) {
}
setFetching(true);
- withServerAction(getRoleById, props.id)
+ withServerAction(getRoleByIdAction, props.id)
.then((response) => {
const data = response.data;
form.setValues({
@@ -133,7 +133,7 @@ export default function FormModal(props: ModalProps) {
const handleSubmit = (values: RoleFormData) => {
setSubmitting(true);
- withServerAction(upsertRole, values)
+ withServerAction(upsertRoleAction, values)
.then((response) => {
showNotification(response.message!, "success");
closeModal();
diff --git a/src/modules/role/services/deleteRole.ts b/src/modules/role/services/deleteRole.ts
new file mode 100644
index 0000000..104df52
--- /dev/null
+++ b/src/modules/role/services/deleteRole.ts
@@ -0,0 +1,12 @@
+import db from "@/core/db";
+import notFound from "@/modules/dashboard/utils/notFound";
+
+export default async function deleteRole(id: string) {
+ const role = await db.role.delete({
+ where: { id },
+ });
+
+ if (!role) notFound({message: "The role doesn't exists"})
+
+ return true as const;
+}
\ No newline at end of file
diff --git a/src/modules/role/services/getAllRoles.ts b/src/modules/role/services/getAllRoles.ts
new file mode 100644
index 0000000..0a96a66
--- /dev/null
+++ b/src/modules/role/services/getAllRoles.ts
@@ -0,0 +1,32 @@
+import db from "@/core/db";
+import "server-only"
+import Role from "../types/Role";
+
+export default async function getAllRoles(): Promise{
+
+ const roles = await db.role.findMany({
+ include: {
+ _count: {
+ select: {
+ permissions: true,
+ users: true,
+ },
+ },
+ },
+ });
+
+ //data transformation
+ const result = roles.map(
+ ({ id, code, name, description, isActive, _count }) => ({
+ id,
+ code,
+ name,
+ description,
+ isActive,
+ permissionCount: _count.permissions,
+ userCount: _count.users,
+ })
+ );
+
+ return result;
+}
\ No newline at end of file
diff --git a/src/modules/role/services/getRoleById.ts b/src/modules/role/services/getRoleById.ts
new file mode 100644
index 0000000..753cd38
--- /dev/null
+++ b/src/modules/role/services/getRoleById.ts
@@ -0,0 +1,40 @@
+import "server-only";
+import db from "@/core/db";
+import notFound from "@/modules/dashboard/utils/notFound";
+
+type RoleData = {
+ id: string;
+ code: string;
+ name: string;
+ description: string;
+ isActive: boolean;
+ permissions: {
+ id: string;
+ code: string;
+ name: string;
+ }[];
+};
+
+export default async function getRoleById(id: string): Promise {
+ const role = await db.role.findFirst({
+ where: { id },
+ select: {
+ code: true,
+ description: true,
+ id: true,
+ isActive: true,
+ name: true,
+ permissions: {
+ select: {
+ id: true,
+ code: true,
+ name: true,
+ },
+ },
+ },
+ });
+
+ if (!role) return notFound({ message: "Role doesn't exists" });
+
+ return role;
+}
diff --git a/src/modules/role/services/upsertRole.ts b/src/modules/role/services/upsertRole.ts
new file mode 100644
index 0000000..7a737cd
--- /dev/null
+++ b/src/modules/role/services/upsertRole.ts
@@ -0,0 +1,59 @@
+import DashboardError from "@/modules/dashboard/errors/DashboardError";
+import roleFormDataSchema, { RoleFormData } from "../formSchemas/RoleFormData";
+import mapObjectToFirstValue from "@/utils/mapObjectToFirstValue";
+import db from "@/core/db";
+
+export default async function upsertRole(data: RoleFormData) {
+ const isInsert = !data.id;
+
+ const validatedFields = roleFormDataSchema.safeParse(data);
+ if (!validatedFields.success) {
+ throw new DashboardError({
+ errorCode: "INVALID_FORM_DATA",
+ formErrors: mapObjectToFirstValue(
+ validatedFields.error.flatten().fieldErrors
+ ),
+ });
+ }
+ const roleData = {
+ code: validatedFields.data.code,
+ description: validatedFields.data.description,
+ name: validatedFields.data.name,
+ isActive: validatedFields.data.isActive,
+ };
+
+ const permissionIds = validatedFields.data.permissions.map(
+ (permission) => ({ code: permission })
+ );
+
+ // Database operation
+ if (isInsert) {
+ if (
+ await db.role.findFirst({
+ where: {
+ code: roleData.code,
+ },
+ })
+ ) {
+ throw new DashboardError({
+ errorCode: "INVALID_FORM_DATA",
+ formErrors: {
+ code: "The code is already exists",
+ },
+ });
+ }
+ return await db.role.create({
+ data: {
+ ...roleData,
+ permissions: {
+ connect: permissionIds,
+ },
+ },
+ });
+ } else {
+ return await db.role.update({
+ where: { id: validatedFields.data.id! },
+ data: { ...roleData, permissions: { connect: permissionIds } },
+ });
+ }
+}
diff --git a/src/modules/role/tables/RolesTable/RolesTable.tsx b/src/modules/role/tables/RolesTable/RolesTable.tsx
index 45883f8..6131cca 100644
--- a/src/modules/role/tables/RolesTable/RolesTable.tsx
+++ b/src/modules/role/tables/RolesTable/RolesTable.tsx
@@ -12,7 +12,7 @@ import Role from "../../types/Role";
interface Props {
permissions: Partial;
- roles: Role[];
+ data: Role[];
}
export default function RolesTable(props: Props) {
@@ -28,7 +28,7 @@ export default function RolesTable(props: Props) {
});
const table = useReactTable({
- data: props.roles,
+ data: props.data,
columns: createColumns({
permissions: props.permissions,
actions: {