Skip to content

Commit e22b654

Browse files
author
dushimsam
committed
feat(UI): added manage group-users page
Signed-off-by: dushimsam <[email protected]>
1 parent 133c1af commit e22b654

File tree

10 files changed

+314
-3
lines changed

10 files changed

+314
-3
lines changed

src/Routes.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ const UploadDelete = React.lazy(() => import("pages/Organize/Uploads/Delete"));
9191
// Admin Pages
9292
const GroupCreate = React.lazy(() => import("pages/Admin/Group/Create"));
9393
const DeleteUser = React.lazy(() => import("pages/Admin/Users/Delete"));
94+
const ManageGroup = React.lazy(() => import("pages/Admin/Group/Manage"));
9495
const AddLicense = React.lazy(() => import("pages/Admin/License/Create"));
9596
const SelectLicense = React.lazy(() =>
9697
import("pages/Admin/License/SelectLicense")
@@ -284,6 +285,11 @@ const Routes = () => {
284285
path={routes.admin.group.create}
285286
component={GroupCreate}
286287
/>
288+
<AdminLayout
289+
exact
290+
path={routes.admin.group.manageGroup}
291+
component={ManageGroup}
292+
/>
287293
<AdminLayout
288294
exact
289295
path={routes.admin.license.create}

src/api/groups.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,30 @@ export const createGroupApi = (name) => {
5050
addGroupName: false,
5151
});
5252
};
53+
54+
// Get all group members
55+
export const getAllGroupMembersApi = (groupId) => {
56+
const url = endpoints.admin.groups.getAllGroupMembers(groupId);
57+
return sendRequest({
58+
url,
59+
method: "GET",
60+
headers: {
61+
Authorization: getToken(),
62+
},
63+
});
64+
};
65+
66+
// Change user permission
67+
export const changeUserPermissionApi = (groupId, userId, permission) => {
68+
const url = endpoints.admin.groups.changeUserPermission(groupId, userId);
69+
return sendRequest({
70+
url,
71+
method: "PUT",
72+
headers: {
73+
Authorization: getToken(),
74+
},
75+
body: {
76+
perm: permission,
77+
},
78+
});
79+
};
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
Copyright (C) 2022 Samuel Dushimimana ([email protected])
3+
4+
SPDX-License-Identifier: GPL-2.0
5+
6+
This program is free software; you can redistribute it and/or
7+
modify it under the terms of the GNU General Public License
8+
version 2 as published by the Free Software Foundation.
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License along
15+
with this program; if not, write to the Free Software Foundation, Inc.,
16+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*/
18+
19+
import React, { useEffect, useState } from "react";
20+
21+
import { InputContainer } from "components/Widgets";
22+
23+
// Required functions for calling APIs
24+
import { changeUserPermission } from "services/groups";
25+
26+
import PropTypes from "prop-types";
27+
28+
// Required constants
29+
import { userPermissions } from "constants/constants";
30+
31+
const ChangePermissionContainer = ({
32+
perm,
33+
setShowMessage,
34+
setMessage,
35+
currGroup,
36+
member,
37+
handleFetchGroupMembers,
38+
}) => {
39+
const [selectedPerm, setSelectedPerm] = useState(perm);
40+
41+
useEffect(() => {
42+
setSelectedPerm(perm);
43+
}, [perm]);
44+
45+
const handleSetNewPermission = async (newPerm) => {
46+
setSelectedPerm(newPerm);
47+
try {
48+
const res = await changeUserPermission(
49+
currGroup,
50+
member?.user.id,
51+
newPerm
52+
);
53+
setShowMessage(true);
54+
setMessage({
55+
type: "success",
56+
text: res.message,
57+
});
58+
handleFetchGroupMembers(currGroup);
59+
} catch (e) {
60+
setMessage({
61+
type: "danger",
62+
text: e.message,
63+
});
64+
} finally {
65+
setTimeout(() => {
66+
setShowMessage(false);
67+
}, [3000]);
68+
}
69+
};
70+
return (
71+
<tr>
72+
<td>{member?.user.name}</td>
73+
<td>
74+
<InputContainer
75+
type="select"
76+
name="name"
77+
options={userPermissions}
78+
id="select-tag"
79+
value={selectedPerm}
80+
property="name"
81+
onChange={(e) => handleSetNewPermission(e.target.value)}
82+
/>
83+
</td>
84+
</tr>
85+
);
86+
};
87+
88+
ChangePermissionContainer.propTypes = {
89+
perm: PropTypes.number,
90+
setMessage: PropTypes.func,
91+
currGroup: PropTypes.number,
92+
member: PropTypes.node,
93+
handleFetchGroupMembers: PropTypes.func,
94+
setShowMessage: PropTypes.func,
95+
};
96+
97+
export default ChangePermissionContainer;

src/components/Header/index.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,9 +255,9 @@ const Header = () => {
255255
</NavDropdown.Item>
256256
<NavDropdown.Item
257257
as={Link}
258-
to={routes.admin.group.delete}
258+
to={routes.admin.group.manageGroup}
259259
>
260-
Delete Group
260+
Manage Group Users
261261
</NavDropdown.Item>
262262
</div>
263263
</DropdownButton>

src/components/Widgets/Input/index.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const InputContainer = ({
2626
id,
2727
className,
2828
onChange,
29+
defaultValue = null,
2930
children,
3031
checked = false,
3132
placeholder = null,
@@ -70,6 +71,7 @@ const InputContainer = ({
7071
className ? `mr-2 form-control ${className}` : `mr-2 form-control`
7172
}
7273
value={value}
74+
defaultValue={defaultValue}
7375
onChange={onChange}
7476
multiple={multiple && multiple}
7577
size={multiple ? "15" : ""}
@@ -125,6 +127,7 @@ InputContainer.propTypes = {
125127
onChange: PropTypes.func,
126128
checked: PropTypes.bool,
127129
disabled: PropTypes.bool,
130+
defaultValue: PropTypes.string,
128131
children: PropTypes.node,
129132
options: PropTypes.arrayOf(
130133
PropTypes.shape({

src/constants/constants.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,23 @@ export const initialMantainanceFields = {
260260
rmvRepoOldFiles1: false,
261261
rmvRepoOldFiles2: false,
262262
};
263+
264+
// eslint-disable-next-line camelcase
265+
export const userPermissions = [
266+
{
267+
id: -1,
268+
name: "None",
269+
},
270+
{
271+
id: 0,
272+
name: "User",
273+
},
274+
{
275+
id: 1,
276+
name: "Admin",
277+
},
278+
{
279+
id: 2,
280+
name: "Advisor",
281+
},
282+
];

src/constants/endpoints.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ const endpoints = {
7171
groups: {
7272
create: () => `${apiUrl}/groups`,
7373
getAll: () => `${apiUrl}/groups`,
74+
getAllGroupMembers: (groupId) => `${apiUrl}/groups/${groupId}/members`,
75+
changeUserPermission: (groupId, userId) =>
76+
`${apiUrl}/groups/${groupId}/user/${userId}`,
7477
},
7578
},
7679
license: {

src/constants/routes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ const routes = {
6767
group: {
6868
create: "/admin/group/create",
6969
delete: "/admin/group/delete",
70+
manageGroup: "/admin/group/manage",
7071
},
7172
users: {
7273
delete: "/admin/users/delete",
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
Copyright (C) 2022 Samuel Dushimimana ([email protected])
3+
4+
SPDX-License-Identifier: GPL-2.0
5+
6+
This program is free software; you can redistribute it and/or
7+
modify it under the terms of the GNU General Public License
8+
version 2 as published by the Free Software Foundation.
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License along
15+
with this program; if not, write to the Free Software Foundation, Inc.,
16+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*/
18+
19+
import React, { useEffect, useState } from "react";
20+
21+
// Title
22+
import Title from "components/Title";
23+
24+
// Widgets
25+
import { Alert, InputContainer } from "components/Widgets";
26+
27+
// Required functions for calling APIs
28+
import { fetchAllGroupMembers, fetchAllGroups } from "services/groups";
29+
30+
// Required page components
31+
import ChangePermissionContainer from "components/Admin/ChangePermission";
32+
33+
const ManageGroup = () => {
34+
const initialMessage = {
35+
type: "success",
36+
text: "",
37+
};
38+
39+
const [currGroup, setCurrentGroup] = useState(null);
40+
const [groupMembers, setGroupMembers] = useState([]);
41+
const [groups, setGroups] = useState([]);
42+
43+
const [showMessage, setShowMessage] = useState(false);
44+
const [message, setMessage] = useState(initialMessage);
45+
46+
useEffect(async () => {
47+
try {
48+
const res = await fetchAllGroups();
49+
const resGrpMembers = await fetchAllGroupMembers(res[0].id);
50+
setCurrentGroup(res[0].id);
51+
setGroups(res);
52+
setGroupMembers(resGrpMembers);
53+
} catch (e) {
54+
setMessage({
55+
type: "danger",
56+
text: e.message,
57+
});
58+
}
59+
}, []);
60+
61+
const handleFetchGroupMembers = async (groupId) => {
62+
try {
63+
const res = await fetchAllGroupMembers(groupId);
64+
setGroupMembers(res);
65+
} catch (error) {
66+
setMessage({
67+
type: "danger",
68+
text: error.message,
69+
});
70+
}
71+
};
72+
73+
const handleGroupChange = async (e) => {
74+
setCurrentGroup(e.target.value);
75+
await handleFetchGroupMembers(e.target.value);
76+
};
77+
78+
return (
79+
<>
80+
<Title title="Manage Group Users" />
81+
<div className="main-container my-3">
82+
{showMessage && (
83+
<Alert
84+
type={message.type}
85+
setShow={setShowMessage}
86+
message={message.text}
87+
/>
88+
)}
89+
<h1 className="font-size-main-heading">Manage Group Users</h1>
90+
<br />
91+
<div className="row">
92+
<div className="col-12 col-lg-8">
93+
<form>
94+
<InputContainer
95+
type="select"
96+
name="name"
97+
options={groups}
98+
id="select-tag"
99+
property="name"
100+
onChange={(e) => handleGroupChange(e)}
101+
value={currGroup}
102+
>
103+
Select group to manage:
104+
</InputContainer>
105+
</form>
106+
107+
<table className="table table-striped table-bordered rounded mt-5">
108+
<thead className="bg-dark text-light font-weight-bold">
109+
<tr>
110+
<th>User</th>
111+
<th>Permission</th>
112+
</tr>
113+
</thead>
114+
<tbody>
115+
{groupMembers?.map((member) => (
116+
<ChangePermissionContainer
117+
currGroup={currGroup}
118+
member={member}
119+
handleFetchGroupMembers={handleFetchGroupMembers}
120+
perm={member.group_perm}
121+
setShowMessage={setShowMessage}
122+
setMessage={setMessage}
123+
key={member.user.id}
124+
/>
125+
))}
126+
</tbody>
127+
</table>
128+
</div>
129+
</div>
130+
</div>
131+
</>
132+
);
133+
};
134+
135+
export default ManageGroup;

src/services/groups.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@
1616
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1717
*/
1818

19-
import { getAllGroupsApi, createGroupApi } from "api/groups";
19+
import {
20+
getAllGroupsApi,
21+
createGroupApi,
22+
getAllGroupMembersApi,
23+
changeUserPermissionApi,
24+
} from "api/groups";
2025
import { setLocalStorage, getLocalStorage } from "shared/storageHelper";
2126

2227
// Fetching all the groups
@@ -37,3 +42,17 @@ export const createGroup = (name) => {
3742
return res;
3843
});
3944
};
45+
46+
// Get all group members
47+
export const fetchAllGroupMembers = (groupId) => {
48+
return getAllGroupMembersApi(groupId).then((res) => {
49+
return res;
50+
});
51+
};
52+
53+
// Change user permission
54+
export const changeUserPermission = (groupId, userId, permission) => {
55+
return changeUserPermissionApi(groupId, userId, permission).then((res) => {
56+
return res;
57+
});
58+
};

0 commit comments

Comments
 (0)