role
Wed Sep 04 2024 10:10:10 GMT+0000 (Coordinated Universal Time)
Saved by @2018331055
import * as React from "react";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import {
ColumnDef,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
import { BsTrash } from "react-icons/bs";
import {
Dialog,
DialogClose,
DialogContent,
DialogTrigger,
} from "@/components/ui/dialog";
import { TbCaretUpDownFilled } from "react-icons/tb";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import {
Pagination,
PaginationContent,
PaginationItem,
PaginationLink,
} from "@/components/ui/pagination";
import { FaXmark } from "react-icons/fa6";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { FaEdit } from "react-icons/fa";
import { Button } from "@/components/ui/button";
import { BsThreeDots } from "react-icons/bs";
import { useNavigate } from "react-router-dom";
import { useState } from "react";
import {
Sheet,
SheetContent,
SheetHeader,
SheetTrigger,
} from "@/components/ui/sheet";
import PermissonDrawer from "./PermissonDrawer";
import { useRef } from "react";
import { Input } from "../ui/input";
import { IoSearchOutline } from "react-icons/io5";
export type Permission = {
permission: string;
};
export type RoleData = {
role_id: string;
role: string;
permissions: Permission[];
};
const data: RoleData[] = [
{
role_id: "1",
role: "Internal Admin",
permissions: [
{ permission: "View Homepage" },
{ permission: "View Manage Service" },
{ permission: "View Add a Service" },
{ permission: "View Quote a Service" },
{ permission: "Support Desk" },
{ permission: "Profile" },
],
},
{
role_id: "2",
role: "Internal Admin",
permissions: [
{ permission: "View Homepage" },
{ permission: "View Manage Service" },
{ permission: "View Add a Service" },
{ permission: "View Quote a Service" },
{ permission: "Support Desk" },
{ permission: "Profile" },
],
},
{
role_id: "3",
role: "Internal Admin",
permissions: [
{ permission: "View Homepage" },
{ permission: "View Manage Service" },
{ permission: "View Add a Service" },
{ permission: "View Quote a Service" },
{ permission: "Support Desk" },
{ permission: "Profile" },
],
},
{
role_id: "4",
role: "Internal Admin",
permissions: [
{ permission: "View Homepage" },
{ permission: "View Manage Service" },
{ permission: "View Add a Service" },
{ permission: "View Quote a Service" },
{ permission: "Support Desk" },
{ permission: "Profile" },
],
},
{
role_id: "5",
role: "Internal Admin",
permissions: [
{ permission: "View Homepage" },
{ permission: "View Manage Service" },
{ permission: "View Add a Service" },
{ permission: "View Quote a Service" },
{ permission: "Support Desk" },
{ permission: "Profile" },
],
},
{
role_id: "6",
role: "Customer Admin",
permissions: [
{ permission: "View Homepage" },
{ permission: "View Manage Service" },
{ permission: "View Add a Service" },
{ permission: "View Quote a Service" },
{ permission: "Support Desk" },
{ permission: "Profile" },
],
},
];
export const columns: ColumnDef<RoleData>[] = [
{
accessorKey: "role",
header: ({ column }: any) => {
return (
<div className="py-1.5">
<Button
className="text-[13px] px-0 text-[#5E6E82] dark:text-[#D8E2EF] whitespace-nowrap font-medium"
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Role
<TbCaretUpDownFilled className="h-2.5 w-2.5 text-[#5E6E82] dark:text-[#D8E2EF]" />
</Button>
</div>
);
},
cell: ({ row }: any) => {
return (
<div className="text-[13px] px-0 text-[#5E6E82] dark:text-[#D8E2EF] py-2 flex gap-2 items-center whitespace-nowrap">
<span className=" px-3 py-2 text-[13px] border rounded-md">
{row.getValue("role")}
</span>
</div>
);
},
},
{
accessorKey: "permissions",
header: ({ column }: any) => {
return (
<div className="py-1.5">
<Button
className="text-[13px] px-0 text-[#5E6E82] dark:text-[#D8E2EF]"
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Permissions
<TbCaretUpDownFilled className="h-2.5 w-2.5 text-[#5E6E82] dark:text-[#D8E2EF]" />
</Button>
</div>
);
},
cell: ({ row }: { row: any }) => {
const permissions = row.original.permissions as Permission[];
return (
<div className="text-[13px] px-0 text-[#5E6E82] dark:text-[#D8E2EF] py-2 flex gap-2 items-center whitespace-nowrap">
<span className=" px-3 py-2 text-[13px] border rounded-md">
{permissions.map((permission, index) => (
<span key={index}>
{permission.permission}
{index < permissions.length - 1 && ", "}
</span>
))}
</span>
</div>
);
},
},
{
accessorKey: "Action",
header: ({ column }) => {
return (
<div className="py-1.5 flex justify-end pr-6 md:pr-6">
<Button
className="text-[13px] px-0 text-[#5E6E82] dark:text-[#D8E2EF] text-right"
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Action
<TbCaretUpDownFilled className="h-2.5 w-2.5 text-[#5E6E82] dark:text-[#D8E2EF]" />
</Button>
</div>
);
},
cell: () => {
const [isEditing, setIsEditing] = useState(false);
const [RoleName, setRoleName] = useState("John Doe");
const inputRef = useRef<HTMLInputElement>(null);
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setRoleName(event.target.value);
};
return (
<span
onClick={(event) => {
event.stopPropagation(); // Prevents row click event
}}
className={`rounded-md py-1 text-[11px] font-semibold flex justify-end px-4`}
>
<DropdownMenu>
<DropdownMenuTrigger className="outline-0 ring-0 text-[#5E6E82] dark:text-[#F5F7FA] ml-auto pr-4 md:pr-4 mb-auto">
<BsThreeDots
className="text-[#138CF7] dark:text-[#D8E2EF] "
size={16}
/>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem className="text-sm ">
<Sheet>
<SheetTrigger
onClick={(e) => {
e.stopPropagation();
}}
asChild
>
<button className="hover:dark:text-[#138CF7] hover:text-[#1062AB] flex items-center">
<FaEdit className="mr-2" /> Edit Role
</button>
</SheetTrigger>
<SheetContent
onClick={(e) => {
e.stopPropagation();
}}
>
<SheetHeader className="bg-[#F6F7FA] dark:bg-[#1F2A3B] px-6 py-4">
<div className="flex justify-between mr-5 items-center">
<div>
{isEditing ? (
<input
ref={inputRef}
type="text"
value={RoleName}
onChange={handleChange}
className="dark:bg-background bg-white rounded p-1 text-base md:text-[22px] font-semibold text-[#1062AB] dark:text-[#F6F7FA] border w-[220px] md:w-[300px]"
/>
) : (
<span
// onClick={handleNameClick}
className="cursor-pointer text-base md:text-[22px] font-semibold text-[#1062AB] dark:text-[#F6F7FA]"
>
{RoleName}
</span>
)}
</div>
<Button
variant="default"
onClick={() => setIsEditing(!isEditing)}
className="text-[13px] h-[35px] flex items-center gap-1.5 bg-[#1062AB]"
>
Update Role
</Button>
</div>
</SheetHeader>
<div
className="p-6"
// onClick={() => setIsEditing(!isEditing)}
>
<PermissonDrawer />
</div>
</SheetContent>
</Sheet>
</DropdownMenuItem>
<DropdownMenuItem className="text-xs">
<Dialog>
<DialogTrigger asChild>
<button
onClick={(e) => {
e.stopPropagation();
}}
className=" text-sm flex items-center gap-2 hover:text-[#C42F4A]"
>
<BsTrash />
Delete
</button>
</DialogTrigger>
<DialogContent className="md:max-w-lg">
<div className="">
<div className="bg-[#1062AB] dark:bg-[#138CF7] rounded-t-md p-4 md:p-6 flex justify-between items-center text-white">
<h1 className="text-base md:text-[19px] font-semibold leading-6">
Delete Role
</h1>
<DialogClose asChild>
<button type="button">
<FaXmark className="h-5 w-5" />
</button>
</DialogClose>
</div>
<div className="p-6">
<p>Are you sure you want to delete this Role?</p>
</div>
<div className="flex justify-end p-4 md:p-6">
<DialogClose asChild>
<Button
variant={"outline"}
className="text-[#1062AB] hover:text-[#1062AB] dark:text-[#F5F7FA] shadow px-7 h-[29px] "
>
Cancel
</Button>
</DialogClose>
<Button className="bg-[#E63757] dark:bg-[#FBDBE1] ml-2 text-[#fff] dark:text-[#E63757] shadow px-5 h-[29px] rounded">
Delete
</Button>
</div>
</div>
</DialogContent>
</Dialog>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</span>
);
},
},
];
export default function RoleTable() {
const navigate = useNavigate();
const [isDone, setisDone] = useState(false);
const [RoleName, setRoleName] = useState("");
const inputRef = useRef<HTMLInputElement>(null);
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setRoleName(event.target.value);
};
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [pageSize, setPageSize] = React.useState(5);
const table = useReactTable({
data,
columns,
onSortingChange: setSorting,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
state: {
sorting,
columnVisibility,
},
});
// Update page size dynamically
React.useEffect(() => {
table.setPageSize(pageSize);
table.setPageIndex(0);
}, [pageSize, table]);
// Handle pagination
const pageCount = table.getPageCount();
const pageIndex = table.getState().pagination.pageIndex;
const handleRowClick = (rowId: string) => {
navigate(`/dashboard/permission/role/${rowId}`);
};
return (
<div className="border rounded-md mt-6 overflow-hidden">
<div className="px-5 py-4 flex justify-between flex-wrap items-center border-b dark:text-[#F5F7FA] bg-[#F5F7FA] dark:bg-[#232E3C]">
<div className="flex justify-between md:justify-start gap-2 items-center w-full md:w-1/2">
<h4 className="text-sm md:text-base font-semibold text-[#232E3C] dark:text-[#D9E7FA]">
Roles & Permissions ({data?.length})
</h4>
<div className="relative">
<Input
placeholder="Search by Role..."
value={
(table.getColumn("role")?.getFilterValue() as string) ?? ""
}
onChange={(event) =>
table.getColumn("role")?.setFilterValue(event.target.value)
}
className="lg:w-[270px] placeholder:text-[13px] font-light pl-3 bg-white dark:bg-background"
/>
<IoSearchOutline className="absolute top-1/2 -translate-y-1/2 right-4 " />
</div>
</div>
<Sheet>
<SheetTrigger
onClick={(e) => {
e.stopPropagation();
}}
asChild
>
<Button className="hover:dark:text-[#138CF7] hover:text-[#1062AB] flex items-center">
Add New Role
</Button>
</SheetTrigger>
<SheetContent
onClick={(e) => {
e.stopPropagation();
}}
>
<SheetHeader className="bg-[#F6F7FA] dark:bg-[#1F2A3B] px-6 py-4">
<div className="flex justify-between mr-5 items-center">
<div>
{isDone === false ? (
<input
ref={inputRef}
type="text"
value={RoleName}
placeholder="Enter role name"
onChange={handleChange}
className="dark:bg-background bg-white h-10 rounded pl-2
text-base md:text-[20px] font-semibold text-[#1062AB] dark:text-[#F6F7FA] border w-[220px] md:w-[300px]"
/>
) : (
<span
// onClick={handleNameClick}
className="cursor-pointer text-base md:text-[22px] font-semibold text-[#1062AB] dark:text-[#F6F7FA]"
>
{RoleName}
</span>
)}
</div>
<Button
variant="default"
onClick={() => setisDone(true)}
className="text-[13px] h-[35px] flex items-center gap-1.5 bg-[#1062AB]"
>
Add Role
</Button>
</div>
</SheetHeader>
<div className="p-6">
<PermissonDrawer />
</div>
</SheetContent>
</Sheet>
</div>
<div className="border-b">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id} className="pl-6">
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
);
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
onClick={() => handleRowClick(row.original?.role_id)}
className="cursor-pointer"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id} className="pl-6">
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell
colSpan={columns.length}
className="h-24 text-center"
>
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
<div className="flex items-center flex-wrap justify-center md:justify-between md:space-x-2 py-4 px-6">
<div className="flex gap-4 items-center mb-4 md:mb-0">
<div className="flex items-center space-x-2">
<span className="text-sm whitespace-nowrap text-[#5E6E82] dark:text-[#F5F7FA]">
Rows per page:
</span>
<Select onValueChange={(value) => setPageSize(Number(value))}>
<SelectTrigger>
<SelectValue placeholder={`${pageSize}`} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel className="text-[#5E6E82] dark:text-[#F5F7FA]">
Rows per page
</SelectLabel>
{[5, 10, 15].map((size) => (
<SelectItem key={size} value={String(size)}>
<span className="text-[#5E6E82] dark:text-[#F5F7FA]">
{" "}
{size}
</span>
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</div>
<div className="md:space-x-2 flex items-center">
<span className="text-sm whitespace-nowrap text-[#5E6E82] dark:text-[#F5F7FA]">
Page {table.getState().pagination.pageIndex + 1} of{" "}
{table.getPageCount()}
</span>
</div>
</div>
<div>
<Pagination>
<PaginationContent>
<PaginationItem>
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
<ChevronLeftIcon className="h-4 w-4" />
</Button>
</PaginationItem>
{[...Array(pageCount)].map((_, index) => (
<PaginationItem key={index}>
<PaginationLink
className={`${
pageIndex === index
? "border rounded-md border-[#1062AB] text-[#1062AB]"
: "text-[#5E6E82] dark:text-[#F5F7FA]"
}`}
href="#"
isActive={index === pageIndex}
onClick={() => table.setPageIndex(index)}
>
{index + 1}
</PaginationLink>
</PaginationItem>
))}
<PaginationItem>
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
<ChevronRightIcon className="h-4 w-4" />
</Button>
</PaginationItem>
</PaginationContent>
</Pagination>
</div>
</div>
</div>
);
}



Comments