|
| 1 | +import React, { useEffect, useContext, useState } from "react"; |
| 2 | + |
| 3 | +import { getPermissionsList } from "../api/permissions"; |
| 4 | +import { |
| 5 | + getRolePermissionsList, |
| 6 | + postRolePermissionsList, |
| 7 | + deleteRolePermissionsList, |
| 8 | +} from "../api/rolepermissions"; |
| 9 | +import { Checkbox } from "@mui/material"; |
| 10 | +import { UPDATE_TOAST } from "../context/actions"; |
| 11 | +import { AppContext } from "../context/AppContext"; |
| 12 | +import { selectRoles, selectHasPermissionAssignmentPermission } from "../context/selectors"; |
| 13 | + |
| 14 | +import "./PermissionsPage.css"; |
| 15 | + |
| 16 | +const groupPermissionsByCategory = (permissions) => permissions.reduce((categories, permission) => { |
| 17 | + const category = permission.category; |
| 18 | + const existingCategory = categories.find(cat => cat.category === category); |
| 19 | + |
| 20 | + // If category exists, add permission to its permissions array |
| 21 | + if (existingCategory) { |
| 22 | + existingCategory.permissions.push(permission); |
| 23 | + } else { |
| 24 | + // Create a new category object and add it to categories |
| 25 | + categories.push({ |
| 26 | + category, |
| 27 | + permissions: [permission], |
| 28 | + }); |
| 29 | + } |
| 30 | + |
| 31 | + return categories.sort((a,b) => a.category.localeCompare(b.category)); |
| 32 | +}, []); |
| 33 | + |
| 34 | +const PermissionEditor = ({ |
| 35 | + permission, |
| 36 | + title, |
| 37 | + enabled, |
| 38 | + onChange |
| 39 | +}) => { |
| 40 | + return ( |
| 41 | + <div className="permissions"> |
| 42 | + <Checkbox |
| 43 | + checked={enabled} |
| 44 | + id={`permission-field-${permission}`} |
| 45 | + onChange={onChange} |
| 46 | + inputProps={{ "aria-label": `checkbox ${title}` }} |
| 47 | + /> |
| 48 | + <label htmlFor={`permission-field-${permission}`}>{title}</label> |
| 49 | + </div> |
| 50 | + ); |
| 51 | +}; |
| 52 | + |
| 53 | +const isPermissionEnabled = (rolePermissions, permission) => rolePermissions.some((current) => current.id === permission.id); |
| 54 | + |
| 55 | +const EditPermissionsPage = () => { |
| 56 | + const { state } = useContext(AppContext); |
| 57 | + const { csrf } = state; |
| 58 | + const roles = selectRoles(state); |
| 59 | + const hasPermission = selectHasPermissionAssignmentPermission(state); |
| 60 | + const [selectedRole, setSelectedRole] = useState(roles && roles.find(()=>true)); |
| 61 | + const [categoriesList, setCategoriesList] = useState([]); |
| 62 | + const [rolePermissionsList, setRolePermissionsList] = useState([]); |
| 63 | + const [rolePermissions, setRolePermissions] = useState([]); |
| 64 | + const [refresh, setRefresh] = useState(true); |
| 65 | + |
| 66 | + useEffect(() => { |
| 67 | + const getRolePermissions = async () => { |
| 68 | + let res = await getRolePermissionsList(csrf); |
| 69 | + let data = |
| 70 | + res.payload && res.payload.data && !res.error ? res.payload.data : null; |
| 71 | + if (data) { |
| 72 | + setRolePermissionsList(data); |
| 73 | + } |
| 74 | + }; |
| 75 | + const getPermissions = async () => { |
| 76 | + let res = await getPermissionsList(csrf); |
| 77 | + let data = |
| 78 | + res.payload && res.payload.data && !res.error ? res.payload.data : null; |
| 79 | + if (data) { |
| 80 | + setCategoriesList(groupPermissionsByCategory(data)); |
| 81 | + } |
| 82 | + }; |
| 83 | + |
| 84 | + if (csrf) { |
| 85 | + getPermissions(); |
| 86 | + getRolePermissions(); |
| 87 | + } |
| 88 | + }, [csrf, refresh]); |
| 89 | + |
| 90 | + useEffect(() => { |
| 91 | + if(selectedRole && rolePermissionsList) { |
| 92 | + const rolePermissions = rolePermissionsList.find((rolePermission) => rolePermission.roleId === selectedRole.id); |
| 93 | + rolePermissions && setRolePermissions(rolePermissions?.permissions); |
| 94 | + } |
| 95 | + |
| 96 | + }, [selectedRole, rolePermissionsList]); |
| 97 | + |
| 98 | + const handleRoleChange = (event) => { |
| 99 | + setSelectedRole(roles.find((role) => role.id === event.target.value)); |
| 100 | + }; |
| 101 | + |
| 102 | + const addRolePermission = async (roleId, permissionId) => { |
| 103 | + let newSchema = { roleId: roleId, permissionId: permissionId }; |
| 104 | + let res = await postRolePermissionsList(newSchema, csrf); |
| 105 | + let data = |
| 106 | + res.payload && res.payload.data && !res.error ? res.payload.data : null; |
| 107 | + if (data) { |
| 108 | + window.snackDispatch({ |
| 109 | + type: UPDATE_TOAST, |
| 110 | + payload: { |
| 111 | + severity: "success", |
| 112 | + toast: `Permission added to Role`, |
| 113 | + }, |
| 114 | + }); |
| 115 | + } else { |
| 116 | + window.snackDispatch({ |
| 117 | + type: UPDATE_TOAST, |
| 118 | + payload: { |
| 119 | + severity: "warning", |
| 120 | + toast: `Problem changing permission for that role`, |
| 121 | + }, |
| 122 | + }); |
| 123 | + } |
| 124 | + }; |
| 125 | + |
| 126 | + const deleteRolePermission = async (roleId, permissionId) => { |
| 127 | + let newSchema = { roleId: roleId, permissionId: permissionId }; |
| 128 | + let res = await deleteRolePermissionsList(newSchema, csrf); |
| 129 | + let data = !res.error ? "Success" : null; |
| 130 | + if (data) { |
| 131 | + window.snackDispatch({ |
| 132 | + type: UPDATE_TOAST, |
| 133 | + payload: { |
| 134 | + severity: "success", |
| 135 | + toast: `Permission removed from Role`, |
| 136 | + }, |
| 137 | + }); |
| 138 | + } else { |
| 139 | + window.snackDispatch({ |
| 140 | + type: UPDATE_TOAST, |
| 141 | + payload: { |
| 142 | + severity: "warning", |
| 143 | + toast: `Problem deleting permission for that role`, |
| 144 | + }, |
| 145 | + }); |
| 146 | + } |
| 147 | + }; |
| 148 | + |
| 149 | + const handleChange = async (event, roleId, permissionId) => { |
| 150 | + if (event?.target?.checked) { |
| 151 | + await addRolePermission(roleId, permissionId); |
| 152 | + setRefresh(!refresh); |
| 153 | + } else { |
| 154 | + await deleteRolePermission(roleId, permissionId); |
| 155 | + setRefresh(!refresh); |
| 156 | + } |
| 157 | + }; |
| 158 | + |
| 159 | + return ( |
| 160 | + <div className="permissions-page"> |
| 161 | + { hasPermission ? |
| 162 | + ( |
| 163 | + <> |
| 164 | + <div> |
| 165 | + <label htmlFor="role">Select Role:</label> |
| 166 | + <select id="role" value={selectedRole?.id || ''} onChange={handleRoleChange}> |
| 167 | + <option value="">-- Please Select --</option> |
| 168 | + {roles?.map((role) => ( |
| 169 | + <option key={role.id} value={role.id}> |
| 170 | + {role.role} - {role.description} |
| 171 | + </option> |
| 172 | + ))} |
| 173 | + </select> |
| 174 | + </div> |
| 175 | + |
| 176 | + { selectedRole && rolePermissions && categoriesList?.map((category) => ( |
| 177 | + <div key={category.category} className="permissions-list"> |
| 178 | + <h3>{category?.category}:</h3> |
| 179 | + { category?.permissions?.map((permission)=> ( |
| 180 | + <PermissionEditor |
| 181 | + key={permission.id} |
| 182 | + permission={permission.permission} |
| 183 | + title={permission.description} |
| 184 | + enabled={isPermissionEnabled(rolePermissions, permission)} |
| 185 | + onChange={(event) => handleChange(event, selectedRole?.id, permission.id, csrf)} /> |
| 186 | + )) |
| 187 | + } |
| 188 | + </div> |
| 189 | + )) |
| 190 | + } |
| 191 | + </> |
| 192 | + ) : ( |
| 193 | + <h3>You do not have permission to view this page.</h3> |
| 194 | + )} |
| 195 | + </div> |
| 196 | + ); |
| 197 | +}; |
| 198 | + |
| 199 | +export default EditPermissionsPage; |
0 commit comments