Merged in ENCOA-82_Permissions (pull request #69)
Updated permissions to have a key to group them
This commit is contained in:
@@ -1,62 +1,105 @@
|
|||||||
import {Permission} from "@/interfaces/permissions";
|
import React from "react";
|
||||||
import {createColumnHelper, flexRender, getCoreRowModel, useReactTable} from "@tanstack/react-table";
|
import { Permission } from "@/interfaces/permissions";
|
||||||
|
import {
|
||||||
|
createColumnHelper,
|
||||||
|
flexRender,
|
||||||
|
getCoreRowModel,
|
||||||
|
useReactTable,
|
||||||
|
Row,
|
||||||
|
} from "@tanstack/react-table";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import {convertCamelCaseToReadable} from "@/utils/string";
|
import { convertCamelCaseToReadable } from "@/utils/string";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
permissions: Permission[];
|
permissions: Permission[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<Permission>();
|
const columnHelper = createColumnHelper<Permission>();
|
||||||
|
|
||||||
const defaultColumns = [
|
const defaultColumns = [
|
||||||
columnHelper.accessor("type", {
|
columnHelper.accessor("type", {
|
||||||
header: () => <span>Type</span>,
|
header: () => <span>Type</span>,
|
||||||
cell: ({row, getValue}) => (
|
cell: ({ row, getValue }) => (
|
||||||
<Link
|
<Link
|
||||||
href={`/permissions/${row.original.id}`}
|
href={`/permissions/${row.original.id}`}
|
||||||
key={row.id}
|
key={row.id}
|
||||||
className="underline text-mti-purple-light hover:text-mti-purple-dark transition ease-in-out duration-300 cursor-pointer">
|
className="underline text-mti-purple-light hover:text-mti-purple-dark transition ease-in-out duration-300 cursor-pointer"
|
||||||
{convertCamelCaseToReadable(getValue() as string)}
|
>
|
||||||
</Link>
|
{convertCamelCaseToReadable(getValue() as string)}
|
||||||
),
|
</Link>
|
||||||
}),
|
),
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function PermissionList({permissions}: Props) {
|
export default function PermissionList({ permissions }: Props) {
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: permissions,
|
data: permissions,
|
||||||
columns: defaultColumns,
|
columns: defaultColumns,
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
});
|
});
|
||||||
return (
|
|
||||||
<div className="w-full">
|
const groupedData: { [key: string]: Row<Permission>[] } = table
|
||||||
<div className="w-full flex flex-col gap-2">
|
.getRowModel()
|
||||||
<table className="rounded-xl bg-mti-purple-ultralight/40 w-full">
|
.rows.reduce((groups: { [key: string]: Row<Permission>[] }, row) => {
|
||||||
<thead>
|
const parent = row.original.topic;
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
if (!groups[parent]) {
|
||||||
<tr key={headerGroup.id}>
|
groups[parent] = [];
|
||||||
{headerGroup.headers.map((header) => (
|
}
|
||||||
<th className="py-4 px-4 text-left" key={header.id}>
|
groups[parent].push(row);
|
||||||
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
|
return groups;
|
||||||
</th>
|
}, {});
|
||||||
))}
|
|
||||||
</tr>
|
return (
|
||||||
))}
|
<div className="w-full">
|
||||||
</thead>
|
<div className="w-full flex flex-col gap-2">
|
||||||
<tbody className="px-2">
|
<table className="rounded-xl bg-mti-purple-ultralight/40 w-full">
|
||||||
{table.getRowModel().rows.map((row) => (
|
<thead>
|
||||||
<tr className="odd:bg-white even:bg-mti-purple-ultralight/40 rounded-lg py-2" key={row.id}>
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
{row.getVisibleCells().map((cell) => (
|
<tr key={headerGroup.id}>
|
||||||
<td className="px-4 py-2 items-center w-fit" key={cell.id}>
|
{headerGroup.headers.map((header) => (
|
||||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
<th className="py-4 px-4 text-left" key={header.id}>
|
||||||
</td>
|
{header.isPlaceholder
|
||||||
))}
|
? null
|
||||||
</tr>
|
: flexRender(
|
||||||
))}
|
header.column.columnDef.header,
|
||||||
</tbody>
|
header.getContext()
|
||||||
</table>
|
)}
|
||||||
</div>
|
</th>
|
||||||
</div>
|
))}
|
||||||
);
|
</tr>
|
||||||
|
))}
|
||||||
|
</thead>
|
||||||
|
<tbody className="px-2">
|
||||||
|
{Object.keys(groupedData).map((parent) => (
|
||||||
|
<React.Fragment key={parent}>
|
||||||
|
<tr>
|
||||||
|
<td className="px-2 py-2 items-center w-fit">
|
||||||
|
<strong>{parent}</strong>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{groupedData[parent].map((row, i) => (
|
||||||
|
<tr
|
||||||
|
className="odd:bg-white even:bg-mti-purple-ultralight/40 rounded-lg py-2"
|
||||||
|
key={row.id}
|
||||||
|
>
|
||||||
|
{row.getVisibleCells().map((cell) => (
|
||||||
|
<td
|
||||||
|
className="px-4 py-2 items-center w-fit"
|
||||||
|
key={cell.id}
|
||||||
|
>
|
||||||
|
{flexRender(
|
||||||
|
cell.column.columnDef.cell,
|
||||||
|
cell.getContext()
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +1,89 @@
|
|||||||
export const markets = ["au", "br", "de"] as const;
|
export interface PermissionTopic {
|
||||||
|
topic: string;
|
||||||
|
list: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export const permissions = [
|
export const permissions = [
|
||||||
// generate codes are basicly invites
|
{
|
||||||
"createCodeStudent",
|
topic: "Manage Corporate",
|
||||||
"createCodeTeacher",
|
list: [
|
||||||
"createCodeCorporate",
|
"viewCorporate",
|
||||||
"createCodeCountryManager",
|
"editCorporate",
|
||||||
"createCodeAdmin",
|
"deleteCorporate",
|
||||||
// exams
|
"createCodeCorporate",
|
||||||
"createReadingExam",
|
],
|
||||||
"createListeningExam",
|
},
|
||||||
"createWritingExam",
|
{
|
||||||
"createSpeakingExam",
|
topic: "Manage Admin",
|
||||||
"createLevelExam",
|
list: ["viewAdmin", "editAdmin", "deleteAdmin", "createCodeAdmin"],
|
||||||
// view pages
|
},
|
||||||
"viewExams",
|
{
|
||||||
"viewExercises",
|
topic: "Manage Student",
|
||||||
"viewRecords",
|
list: ["viewStudent", "editStudent", "deleteStudent", "createCodeStudent"],
|
||||||
"viewStats",
|
},
|
||||||
"viewTickets",
|
{
|
||||||
"viewPaymentRecords",
|
topic: "Manage Teacher",
|
||||||
// view data
|
list: ["viewTeacher", "editTeacher", "deleteTeacher", "createCodeTeacher"],
|
||||||
"viewStudent",
|
},
|
||||||
"viewTeacher",
|
{
|
||||||
"viewCorporate",
|
topic: "Manage Country Manager",
|
||||||
"viewCountryManager",
|
list: [
|
||||||
"viewAdmin",
|
"viewCountryManager",
|
||||||
"viewGroup",
|
"editCountryManager",
|
||||||
"viewCodes",
|
"deleteCountryManager",
|
||||||
// edit data
|
"createCodeCountryManager",
|
||||||
"editStudent",
|
],
|
||||||
"editTeacher",
|
},
|
||||||
"editCorporate",
|
{
|
||||||
"editCountryManager",
|
topic: "Manage Exams",
|
||||||
"editAdmin",
|
list: [
|
||||||
"editGroup",
|
"createReadingExam",
|
||||||
// delete data
|
"createListeningExam",
|
||||||
"deleteStudent",
|
"createWritingExam",
|
||||||
"deleteTeacher",
|
"createSpeakingExam",
|
||||||
"deleteCorporate",
|
"createLevelExam",
|
||||||
"deleteCountryManager",
|
],
|
||||||
"deleteAdmin",
|
},
|
||||||
"deleteGroup",
|
{
|
||||||
"deleteCodes",
|
topic: "View Pages",
|
||||||
// create options
|
list: [
|
||||||
"createGroup",
|
"viewExams",
|
||||||
"createCodes",
|
"viewExercises",
|
||||||
"all",
|
"viewRecords",
|
||||||
|
"viewStats",
|
||||||
|
"viewTickets",
|
||||||
|
"viewPaymentRecords",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topic: "Manage Group",
|
||||||
|
list: ["viewGroup", "editGroup", "deleteGroup", "createGroup"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topic: "Manage Codes",
|
||||||
|
list: ["viewCodes", "deleteCodes", "createCodes"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topic: "Others",
|
||||||
|
list: ["all"],
|
||||||
|
},
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type PermissionType = (typeof permissions)[keyof typeof permissions];
|
const permissionsList = [
|
||||||
|
...new Set(
|
||||||
|
permissions.reduce(
|
||||||
|
(accm: string[], permission) => [...accm, ...permission.list],
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
export type PermissionType =
|
||||||
|
(typeof permissionsList)[keyof typeof permissionsList];
|
||||||
|
|
||||||
export interface Permission {
|
export interface Permission {
|
||||||
id: string;
|
id: string;
|
||||||
type: PermissionType;
|
type: PermissionType;
|
||||||
users: string[];
|
topic: string;
|
||||||
|
users: string[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,9 +55,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Page(props: Props) {
|
export default function Page(props: Props) {
|
||||||
|
|
||||||
const { permissions, user } = props;
|
const { permissions, user } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
|
|||||||
@@ -16,12 +16,13 @@ import {
|
|||||||
Permission,
|
Permission,
|
||||||
PermissionType,
|
PermissionType,
|
||||||
permissions,
|
permissions,
|
||||||
|
PermissionTopic,
|
||||||
} from "@/interfaces/permissions";
|
} from "@/interfaces/permissions";
|
||||||
import {v4} from "uuid";
|
import { v4 } from "uuid";
|
||||||
|
|
||||||
const db = getFirestore(app);
|
const db = getFirestore(app);
|
||||||
|
|
||||||
async function createPermission(type: string) {
|
async function createPermission(topic: string, type: string) {
|
||||||
const permData = doc(db, "permissions", v4());
|
const permData = doc(db, "permissions", v4());
|
||||||
const permDoc = await getDoc(permData);
|
const permDoc = await getDoc(permData);
|
||||||
if (permDoc.exists()) {
|
if (permDoc.exists()) {
|
||||||
@@ -30,9 +31,14 @@ async function createPermission(type: string) {
|
|||||||
|
|
||||||
await setDoc(permData, {
|
await setDoc(permData, {
|
||||||
type,
|
type,
|
||||||
|
topic,
|
||||||
users: [],
|
users: [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
interface PermissionsHelperList {
|
||||||
|
topic: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
export function getPermissions(userId: string | undefined, docs: Permission[]) {
|
export function getPermissions(userId: string | undefined, docs: Permission[]) {
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
return [];
|
return [];
|
||||||
@@ -52,9 +58,19 @@ export function getPermissions(userId: string | undefined, docs: Permission[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function bootstrap() {
|
export async function bootstrap() {
|
||||||
await permissions.forEach(async (type) => {
|
await permissions
|
||||||
await createPermission(type);
|
.reduce((accm: PermissionsHelperList[], permissionData) => {
|
||||||
});
|
return [
|
||||||
|
...accm,
|
||||||
|
...permissionData.list.map((type) => ({
|
||||||
|
topic: permissionData.topic,
|
||||||
|
type,
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
}, [])
|
||||||
|
.forEach(async ({ topic, type }) => {
|
||||||
|
await createPermission(topic, type);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getPermissionDoc(id: string) {
|
export async function getPermissionDoc(id: string) {
|
||||||
|
|||||||
Reference in New Issue
Block a user