diff --git a/src/app/dashboard/(auth)/permissions/page.tsx b/src/app/dashboard/(auth)/permissions/page.tsx
new file mode 100644
index 0000000..3b76d8a
--- /dev/null
+++ b/src/app/dashboard/(auth)/permissions/page.tsx
@@ -0,0 +1,42 @@
+import { Card, Stack, Title } from "@mantine/core";
+import { Metadata } from "next";
+import React from "react";
+// import RolesTable from "./_tables/RolesTable/RolesTable";
+// import getRoles from "@/features/dashboard/roles/data/getRoles";
+import checkMultiplePermissions from "@/features/auth/tools/checkMultiplePermissions";
+import { PermissionTable } from "@/features/dashboard/permissions/tables";
+import getPermissions from "@/features/dashboard/permissions/data/getPermissions";
+
+interface Props {
+ searchParams: {
+ detail?: string;
+ edit?: string;
+ delete?: string;
+ create?: string;
+ };
+}
+
+export const metadata: Metadata = {
+ title: "Permissions - Dashboard",
+};
+
+export default async function RolesPage({ searchParams }: Props) {
+ const permissions = await checkMultiplePermissions({
+ create: "permission.create",
+ readAll: "permission.readAll",
+ read: "permission.read",
+ update: "permission.update",
+ delete: "permission.delete",
+ });
+
+ const permissionData = await getPermissions()
+
+ return (
+
+ Permissions
+
+
+
+
+ );
+}
diff --git a/src/app/dashboard/(auth)/roles/_tables/RolesTable/RolesTable.tsx b/src/app/dashboard/(auth)/roles/_tables/RolesTable/RolesTable.tsx
index fcd444c..0513d11 100644
--- a/src/app/dashboard/(auth)/roles/_tables/RolesTable/RolesTable.tsx
+++ b/src/app/dashboard/(auth)/roles/_tables/RolesTable/RolesTable.tsx
@@ -16,6 +16,7 @@ import { RoleFormData } from "@/features/dashboard/roles/formSchemas/RoleFormDat
import { string } from "zod";
import { DeleteModal } from "../../_modals";
import { DeleteModalProps } from "../../_modals/DeleteModal/DeleteModal";
+import { DashboardTable } from "@/features/dashboard/components";
interface Props {
permissions: Partial;
@@ -114,60 +115,8 @@ export default function RolesTable(props: Props) {
)}
-
- {/* Thead */}
-
- {table.getHeaderGroups().map((headerGroup) => (
-
- {headerGroup.headers.map((header) => (
-
- {header.isPlaceholder
- ? null
- : flexRender(
- header.column.columnDef.header,
- header.getContext()
- )}
-
- ))}
-
- ))}
-
-
- {/* Tbody */}
-
- {table.getRowModel().rows.length > 0 ? (
- table.getRowModel().rows.map((row) => (
-
- {row.getVisibleCells().map((cell) => (
-
- {flexRender(
- cell.column.columnDef.cell,
- cell.getContext()
- )}
-
- ))}
-
- ))
- ) : (
-
-
- - No Data -
-
-
- )}
-
-
+
+
{
+ table: ReactTable
+}
+
+export default function DashboardTable({table}: Props) {
+ return (
+
+ {/* Thead */}
+
+ {table.getHeaderGroups().map((headerGroup) => (
+
+ {headerGroup.headers.map((header) => (
+
+ {header.isPlaceholder
+ ? null
+ : flexRender(
+ header.column.columnDef.header,
+ header.getContext()
+ )}
+
+ ))}
+
+ ))}
+
+
+ {/* Tbody */}
+
+ {table.getRowModel().rows.length > 0 ? (
+ table.getRowModel().rows.map((row) => (
+
+ {row.getVisibleCells().map((cell) => (
+
+ {flexRender(
+ cell.column.columnDef.cell,
+ cell.getContext()
+ )}
+
+ ))}
+
+ ))
+ ) : (
+
+
+ - No Data -
+
+
+ )}
+
+
+ );
+}
diff --git a/src/features/dashboard/components/DashboardTable/index.ts b/src/features/dashboard/components/DashboardTable/index.ts
new file mode 100644
index 0000000..6a3b717
--- /dev/null
+++ b/src/features/dashboard/components/DashboardTable/index.ts
@@ -0,0 +1 @@
+export { default } from "./DashboardTable";
diff --git a/src/features/dashboard/components/index.ts b/src/features/dashboard/components/index.ts
new file mode 100644
index 0000000..248077e
--- /dev/null
+++ b/src/features/dashboard/components/index.ts
@@ -0,0 +1,3 @@
+import DashboardTable from "./DashboardTable";
+
+export { DashboardTable };
diff --git a/src/features/dashboard/permissions/actions/deletePermission.ts b/src/features/dashboard/permissions/actions/deletePermission.ts
new file mode 100644
index 0000000..881b1ae
--- /dev/null
+++ b/src/features/dashboard/permissions/actions/deletePermission.ts
@@ -0,0 +1,26 @@
+"use server";
+
+import prisma from "@/db";
+import checkPermission from "@/features/auth/tools/checkPermission";
+import { handleCatch, unauthorized } from "../../errors/DashboardError";
+import ServerResponse from "@/types/Action";
+import { revalidatePath } from "next/cache";
+
+export default async function deletePermission(id: string): Promise {
+ try {
+ if (!(await checkPermission("permission.delete"))) return unauthorized();
+ const permission = await prisma.permission.delete({
+ where: { id },
+ });
+
+
+ revalidatePath(".")
+
+ return {
+ success: true,
+ message: "The permission has been deleted successfully",
+ };
+ } catch (e: unknown) {
+ return handleCatch(e)
+ }
+}
diff --git a/src/features/dashboard/permissions/actions/getPermissionById.ts b/src/features/dashboard/permissions/actions/getPermissionById.ts
new file mode 100644
index 0000000..37543c9
--- /dev/null
+++ b/src/features/dashboard/permissions/actions/getPermissionById.ts
@@ -0,0 +1,33 @@
+"use server";
+
+import { unauthorized } from "@/BaseError";
+import prisma from "@/db";
+import checkPermission from "@/features/auth/tools/checkPermission";
+
+export default async function getPermissionById(id: string) {
+ if (!(await checkPermission("permission.read"))) unauthorized();
+
+ const permission = await prisma.permission.findFirst({
+ where: { id },
+ select: {
+ code: true,
+ description: true,
+ id: true,
+ isActive: true,
+ name: true,
+ },
+ });
+
+ if (!permission) {
+ return {
+ success: false,
+ message: "Permission not found",
+ } as const;
+ }
+
+ return {
+ success: true,
+ message: "Permission fetched successfully",
+ data: permission,
+ } as const;
+}
diff --git a/src/features/dashboard/permissions/actions/upsertPermission.ts b/src/features/dashboard/permissions/actions/upsertPermission.ts
new file mode 100644
index 0000000..4a92f7e
--- /dev/null
+++ b/src/features/dashboard/permissions/actions/upsertPermission.ts
@@ -0,0 +1,81 @@
+"use server";
+
+import checkPermission from "@/features/auth/tools/checkPermission";
+import permissionFormDataSchema, { PermissionFormData } from "../formSchemas/PermissionFormData";
+import mapObjectToFirstValue from "@/utils/mapObjectToFirstValue";
+import prisma from "@/db";
+import { revalidatePath } from "next/cache";
+import ServerResponse from "@/types/Action";
+import DashboardError, { handleCatch, unauthorized } from "../../errors/DashboardError";
+
+/**
+ * Upserts a permission based on the provided PermissionFormData.
+ * If the permission already exists (determined by `id`), it updates the permission; otherwise, it creates a new permission.
+ * Authorization checks are performed based on whether it's a create or update operation.
+ *
+ * @param data - The data for creating or updating the permission.
+ * @returns An object containing the success status, message, and any errors.
+ */
+export default async function upsertPermission(
+ data: PermissionFormData
+): Promise {
+ try {
+ const isInsert = !data.id;
+
+ // Authorization check
+ const permissionType = isInsert ? "permission.create" : "permission.update";
+ if (!(await checkPermission(permissionType))) {
+ return unauthorized();
+ }
+
+ // Validate form data
+ const validatedFields = permissionFormDataSchema.safeParse(data);
+ if (!validatedFields.success) {
+ throw new DashboardError({
+ errorCode: "INVALID_FORM_DATA",
+ formErrors: mapObjectToFirstValue(validatedFields.error.flatten().fieldErrors)
+ })
+ }
+ const permissionData = {
+ code: validatedFields.data.code,
+ description: validatedFields.data.description,
+ name: validatedFields.data.name,
+ isActive: validatedFields.data.isActive,
+ };
+
+ // Database operation
+ if (isInsert) {
+ if (await prisma.permission.findFirst({
+ where: {
+ code: permissionData.code
+ }
+ })){
+ throw new DashboardError({
+ errorCode: "INVALID_FORM_DATA",
+ formErrors: {
+ code: "The code is already exists"
+ }
+ })
+ }
+ await prisma.permission.create({ data: permissionData });
+ } else {
+ await prisma.permission.update({
+ where: { id: validatedFields.data.id! },
+ data: permissionData,
+ });
+ }
+
+ // Revalidate the cache
+ revalidatePath(".");
+
+ // Return success message
+ return {
+ success: true,
+ message: `Permission ${validatedFields.data.name} has been successfully ${
+ isInsert ? "created" : "updated"
+ }.`,
+ };
+ } catch (error) {
+ return handleCatch(error)
+ }
+}
diff --git a/src/features/dashboard/permissions/data/getPermissions.ts b/src/features/dashboard/permissions/data/getPermissions.ts
new file mode 100644
index 0000000..ad743d7
--- /dev/null
+++ b/src/features/dashboard/permissions/data/getPermissions.ts
@@ -0,0 +1,48 @@
+import { unauthorized } from "@/BaseError";
+import prisma from "@/db";
+import checkPermission from "@/features/auth/tools/checkPermission";
+import "server-only";
+
+/**
+ * Retrieves all permissions along with the count of associated permissions and users.
+ * Authorization check is performed for the operation.
+ *
+ * @returns An array of permission objects each including details and counts of related permissions and users.
+ */
+export default async function getPermissions() {
+ // Authorization check
+ if (!(await checkPermission("permissions.getAll"))) {
+ return unauthorized();
+ }
+
+ try {
+ // Fetch permissions from the database
+ const permissions = await prisma.permission.findMany({
+ include: {
+ _count: {
+ select: {
+ roles: true,
+ directUsers: true,
+ },
+ },
+ },
+ });
+
+ // Transform the data into the desired format
+ return permissions.map(
+ ({ id, code, name, description, isActive, _count }) => ({
+ id,
+ code,
+ name,
+ description,
+ isActive,
+ roleCount: _count.roles,
+ //User count counts only direct user
+ userCount: _count.directUsers,
+ })
+ );
+ } catch (error) {
+ console.error("Error retrieving permissions", error);
+ throw error;
+ }
+}
diff --git a/src/features/dashboard/permissions/formSchemas/PermissionFormData.ts b/src/features/dashboard/permissions/formSchemas/PermissionFormData.ts
new file mode 100644
index 0000000..2e7941b
--- /dev/null
+++ b/src/features/dashboard/permissions/formSchemas/PermissionFormData.ts
@@ -0,0 +1,19 @@
+import { z } from "zod"
+
+export interface PermissionFormData {
+ id: string;
+ name: string;
+ code: string;
+ description: string;
+ isActive: boolean;
+}
+
+const permissionFormDataSchema = z.object({
+ id: z.string().nullable(),
+ name: z.string().min(1),
+ code: z.string().min(1),
+ description: z.string(),
+ isActive: z.boolean(),
+})
+
+export default permissionFormDataSchema;
diff --git a/src/features/dashboard/permissions/modals/DeleteModal/DeleteModal.tsx b/src/features/dashboard/permissions/modals/DeleteModal/DeleteModal.tsx
new file mode 100644
index 0000000..c2dd4ec
--- /dev/null
+++ b/src/features/dashboard/permissions/modals/DeleteModal/DeleteModal.tsx
@@ -0,0 +1,111 @@
+"use client";
+import { useRouter } from "next/navigation";
+import React, { useState } from "react";
+import {
+ Avatar,
+ Button,
+ Center,
+ Flex,
+ Modal,
+ ScrollArea,
+ Text,
+ Stack,
+ TextInput,
+ Title,
+ Alert,
+} from "@mantine/core";
+import { showNotification } from "@/utils/notifications";
+import deletePermission from "@/features/dashboard/permissions/actions/deletePermission";
+import withErrorHandling from "@/features/dashboard/utils/withServerAction";
+import { error } from "console";
+import DashboardError from "@/features/dashboard/errors/DashboardError";
+import { revalidatePath } from "next/cache";
+
+export interface DeleteModalProps {
+ data?: {
+ id: string;
+ name: string;
+ };
+ onClose: () => void;
+}
+
+export default function DeleteModal(props: DeleteModalProps) {
+ const router = useRouter();
+
+ const [isSubmitting, setSubmitting] = useState(false);
+ const [errorMessage, setErrorMessage] = useState("");
+
+ /**
+ * Closes the modal. It won't close if a submission is in progress.
+ */
+ const closeModal = () => {
+ if (isSubmitting) return;
+ setErrorMessage("")
+ props.onClose();
+ };
+
+ const confirmAction = () => {
+ if (!props.data?.id) return;
+ setSubmitting(true);
+
+ withErrorHandling(() => deletePermission(props.data!.id))
+ .then((response) => {
+ showNotification(
+ response.message ?? "Permission deleted successfully"
+ );
+ setSubmitting(false);
+ props.onClose()
+ })
+ .catch((e) => {
+ if (e instanceof DashboardError){
+ setErrorMessage(`ERROR: ${e.message} (${e.errorCode})`)
+ }
+ else if (e instanceof Error) {
+ setErrorMessage(`ERROR: ${e.message}`)
+ } else {
+ setErrorMessage(`Unkown error is occured. Please contact administrator`)
+ }
+ })
+ .finally(() => {
+ setSubmitting(false)
+ });
+ };
+
+ return (
+
+
+ Are you sure you want to delete permission{" "}
+
+ {props.data?.name}
+
+ ? This action is irreversible.
+
+
+ {errorMessage && {errorMessage}}
+ {/* Buttons */}
+
+
+ }
+ type="submit"
+ color="red"
+ loading={isSubmitting}
+ onClick={confirmAction}
+ >
+ Delete Permission
+
+
+
+ );
+}
diff --git a/src/features/dashboard/permissions/modals/DeleteModal/index.ts b/src/features/dashboard/permissions/modals/DeleteModal/index.ts
new file mode 100644
index 0000000..34d6794
--- /dev/null
+++ b/src/features/dashboard/permissions/modals/DeleteModal/index.ts
@@ -0,0 +1 @@
+export { default } from "./DeleteModal";
diff --git a/src/features/dashboard/permissions/modals/FormModal/FormModal.tsx b/src/features/dashboard/permissions/modals/FormModal/FormModal.tsx
new file mode 100644
index 0000000..d3d09a2
--- /dev/null
+++ b/src/features/dashboard/permissions/modals/FormModal/FormModal.tsx
@@ -0,0 +1,214 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import DashboardError from "@/features/dashboard/errors/DashboardError";
+import getPermissionById from "@/features/dashboard/permissions/actions/getPermissionById";
+import upsertPermission from "@/features/dashboard/permissions/actions/upsertPermission";
+import permissionFormDataSchema, {
+ PermissionFormData,
+} from "@/features/dashboard/permissions/formSchemas/PermissionFormData";
+import withErrorHandling from "@/features/dashboard/utils/withServerAction";
+import { showNotification } from "@/utils/notifications";
+import {
+ Flex,
+ Modal,
+ Stack,
+ Switch,
+ TextInput,
+ Textarea,
+ Button,
+ ScrollArea,
+ Checkbox,
+ Skeleton,
+ Fieldset,
+ Alert,
+} from "@mantine/core";
+import { useForm, zodResolver } from "@mantine/form";
+import { useRouter } from "next/navigation";
+import React, { useCallback, useEffect, useState } from "react";
+import { TbDeviceFloppy } from "react-icons/tb";
+
+export interface ModalProps {
+ title: string;
+ readonly?: boolean;
+ id?: string;
+ opened: boolean;
+ onClose?: () => void;
+}
+
+/**
+ * A component for rendering a modal with a form to create or edit a permission.
+ *
+ * @param props - The props for the component.
+ * @returns The rendered element.
+ */
+export default function FormModal(props: ModalProps) {
+ const router = useRouter();
+ const [isSubmitting, setSubmitting] = useState(false);
+ const [isFetching, setFetching] = useState(false);
+ const [errorMessage, setErrorMessage] = useState("");
+
+ const form = useForm({
+ initialValues: {
+ code: "",
+ description: "",
+ id: "",
+ isActive: false,
+ name: "",
+ },
+ validate: zodResolver(permissionFormDataSchema),
+ validateInputOnChange: false,
+ onValuesChange: (values) => {
+ console.log(values);
+ },
+ });
+
+ /**
+ * Fetches permission data by ID and populates the form if the modal is opened and an ID is provided.
+ */
+ useEffect(() => {
+ if (!props.opened || !props.id) {
+ return;
+ }
+
+ setFetching(true);
+ getPermissionById(props.id)
+ .then((response) => {
+ if (response.success) {
+ const data = response.data;
+ form.setValues({
+ code: data.code,
+ description: data.description,
+ id: data.id,
+ isActive: data.isActive,
+ name: data.name,
+ });
+ }
+ })
+ .catch((e) => {
+ //TODO: Handle error
+ console.log(e);
+ })
+ .finally(() => {
+ setFetching(false);
+ });
+ }, [props.opened, props.id]);
+
+ const closeModal = () => {
+ props.onClose ? props.onClose() : router.replace("?");
+ };
+
+ const handleSubmit = (values: PermissionFormData) => {
+ setSubmitting(true);
+ withErrorHandling(() => upsertPermission(values))
+ .then((response) => {
+ showNotification(response.message!, "success");
+ closeModal();
+ })
+ .catch((e) => {
+ if (e instanceof DashboardError) {
+ if (e.errorCode === "INVALID_FORM_DATA") {
+ form.setErrors(e.formErrors ?? {});
+ } else {
+ setErrorMessage(`ERROR: ${e.message} (${e.errorCode})`);
+ }
+ } else if (e instanceof Error) {
+ setErrorMessage(`ERROR: ${e.message}`);
+ } else {
+ setErrorMessage(
+ `Unkown error is occured. Please contact administrator`
+ );
+ }
+ })
+ .finally(() => {
+ setSubmitting(false);
+ });
+ };
+
+ return (
+
+
+
+ );
+}
diff --git a/src/features/dashboard/permissions/modals/FormModal/index.ts b/src/features/dashboard/permissions/modals/FormModal/index.ts
new file mode 100644
index 0000000..fb63e6d
--- /dev/null
+++ b/src/features/dashboard/permissions/modals/FormModal/index.ts
@@ -0,0 +1 @@
+export { default } from "./FormModal";
diff --git a/src/features/dashboard/permissions/modals/index.ts b/src/features/dashboard/permissions/modals/index.ts
new file mode 100644
index 0000000..e0102b0
--- /dev/null
+++ b/src/features/dashboard/permissions/modals/index.ts
@@ -0,0 +1,4 @@
+import DeleteModal from "./DeleteModal";
+import FormModal from "./FormModal";
+
+export { FormModal, DeleteModal };
diff --git a/src/features/dashboard/permissions/tables/PermissionTable/PermissionTable.tsx b/src/features/dashboard/permissions/tables/PermissionTable/PermissionTable.tsx
new file mode 100644
index 0000000..2054df8
--- /dev/null
+++ b/src/features/dashboard/permissions/tables/PermissionTable/PermissionTable.tsx
@@ -0,0 +1,126 @@
+"use client";
+import { Table, Text, Flex, Button, Center } from "@mantine/core";
+import {
+ flexRender,
+ getCoreRowModel,
+ useReactTable,
+} from "@tanstack/react-table";
+import React, { useState } from "react";
+import CrudPermissions from "@/features/auth/types/CrudPermissions";
+import { TbPlus } from "react-icons/tb";
+import { PermissionFormData } from "@/features/dashboard/permissions/formSchemas/PermissionFormData";
+import { string } from "zod";
+import { DashboardTable } from "@/features/dashboard/components";
+import getPermissions from "../../data/getPermissions";
+import FormModal, { ModalProps } from "../../modals/FormModal/FormModal";
+import DeleteModal, { DeleteModalProps } from "../../modals/DeleteModal/DeleteModal";
+import createColumns from "./_columns";
+
+interface Props {
+ permissions: Partial;
+ permissionData: Awaited>;
+}
+
+export default function PermissionsTable(props: Props) {
+ const [modalProps, setModalProps] = useState({
+ opened: false,
+ title: "",
+ });
+
+ const [deleteModalProps, setDeleteModalProps] = useState<
+ Omit
+ >({
+ data: undefined,
+ });
+
+ const table = useReactTable({
+ data: props.permissionData,
+ columns: createColumns({
+ permissions: props.permissions,
+ actions: {
+ detail: (id: string) => openFormModal("detail", id),
+ edit: (id: string) => openFormModal("edit", id),
+ delete: (id: string, name: string) => openDeleteModal(id, name),
+ },
+ }),
+ getCoreRowModel: getCoreRowModel(),
+ defaultColumn: {
+ cell: (props) => {props.getValue() as React.ReactNode},
+ },
+ });
+
+ const openFormModal = (type: "create" | "edit" | "detail", id?: string) => {
+ const openCreateModal = () => {
+ setModalProps({
+ id,
+ opened: true,
+ title: "Create new permission",
+ });
+ };
+
+ const openDetailModal = () => {
+ setModalProps({
+ id,
+ opened: true,
+ title: "Permission detail",
+ readonly: true,
+ });
+ };
+
+ const openEditModal = () => {
+ setModalProps({
+ id,
+ opened: true,
+ title: "Edit permission",
+ });
+ };
+
+ type === "create"
+ ? openCreateModal()
+ : type === "detail"
+ ? openDetailModal()
+ : openEditModal();
+ };
+
+ const openDeleteModal = (id: string, name: string) => {
+ setDeleteModalProps({
+ data: {
+ id,
+ name,
+ },
+ });
+ };
+
+ const closeModal = () => {
+ setModalProps({
+ id: "",
+ opened: false,
+ title: "",
+ });
+ };
+
+ // TODO: Add view when data is empty
+
+ return (
+ <>
+
+ {props.permissions.create && (
+ }
+ onClick={() => openFormModal("create")}
+ >
+ New Permission
+
+ )}
+
+
+
+
+
+ setDeleteModalProps({})}
+ />
+ >
+ );
+}
diff --git a/src/features/dashboard/permissions/tables/PermissionTable/_columns.tsx b/src/features/dashboard/permissions/tables/PermissionTable/_columns.tsx
new file mode 100644
index 0000000..7f4fcd3
--- /dev/null
+++ b/src/features/dashboard/permissions/tables/PermissionTable/_columns.tsx
@@ -0,0 +1,105 @@
+import { createColumnHelper } from "@tanstack/react-table";
+import { Badge, Flex } from "@mantine/core";
+import createActionButtons from "@/features/dashboard/utils/createActionButtons";
+import CrudPermissions from "@/features/auth/types/CrudPermissions";
+import { TbEye, TbPencil, TbTrash } from "react-icons/tb";
+
+export interface PermissionRow {
+ id: string;
+ code: string;
+ name: string;
+ description: string;
+ isActive: boolean;
+ roleCount: number;
+ userCount: number;
+}
+
+interface ColumnOptions {
+ permissions: Partial;
+ actions: {
+ detail: (id: string) => void;
+ edit: (id: string) => void;
+ delete: (id: string, name: string) => void;
+ };
+}
+
+const createColumns = (options: ColumnOptions) => {
+ const columnHelper = createColumnHelper();
+
+ const columns = [
+ columnHelper.accessor("id", {
+ id: "sequence",
+ header: "#",
+ cell: (props) => props.row.index + 1,
+ }),
+
+ columnHelper.accessor("code", {
+ header: "Code",
+ }),
+
+ columnHelper.accessor("name", {
+ header: "Name",
+ }),
+
+ columnHelper.accessor("isActive", {
+ header: "Status",
+ cell: (props) => {
+ props.getValue() ? (
+ Enabled
+ ) : (
+ Disabled
+ );
+ },
+ }),
+
+ columnHelper.accessor("roleCount", {
+ header: "Roles",
+ }),
+
+ columnHelper.accessor("userCount", {
+ header: "Users",
+ }),
+
+ columnHelper.display({
+ id: "Actions",
+ header: "Actions",
+ cell: (props) => (
+
+ {createActionButtons([
+ {
+ label: "Detail",
+ permission: options.permissions.read,
+ action: () =>
+ options.actions.detail(props.row.original.id),
+ color: "green",
+ icon: ,
+ },
+ {
+ label: "Edit",
+ permission: options.permissions.update,
+ action: () =>
+ options.actions.edit(props.row.original.id),
+ color: "yellow",
+ icon: ,
+ },
+ {
+ label: "Delete",
+ permission: options.permissions.delete,
+ action: () =>
+ options.actions.delete(
+ props.row.original.id,
+ props.row.original.name
+ ),
+ color: "red",
+ icon: ,
+ },
+ ])}
+
+ ),
+ }),
+ ];
+
+ return columns;
+};
+
+export default createColumns;
diff --git a/src/features/dashboard/permissions/tables/PermissionTable/index.ts b/src/features/dashboard/permissions/tables/PermissionTable/index.ts
new file mode 100644
index 0000000..8830e7f
--- /dev/null
+++ b/src/features/dashboard/permissions/tables/PermissionTable/index.ts
@@ -0,0 +1 @@
+export { default } from "./PermissionTable"
\ No newline at end of file
diff --git a/src/features/dashboard/permissions/tables/index.ts b/src/features/dashboard/permissions/tables/index.ts
new file mode 100644
index 0000000..9a70ce3
--- /dev/null
+++ b/src/features/dashboard/permissions/tables/index.ts
@@ -0,0 +1,3 @@
+import PermissionTable from "./PermissionTable";
+
+export { PermissionTable };