Skip to content

Commit b42eb58

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

File tree

9 files changed

+288
-3
lines changed

9 files changed

+288
-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+
};

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: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
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+
// import messages from "constants/messages";
21+
22+
// Title
23+
import Title from "components/Title";
24+
25+
// Widgets
26+
import { Alert, InputContainer } from "components/Widgets";
27+
28+
// Required functions for calling APIs
29+
import {
30+
changeUserPermission,
31+
fetchAllGroupMembers,
32+
fetchAllGroups,
33+
} from "services/groups";
34+
35+
import PropTypes from "prop-types";
36+
import { userPermissions } from "../../../../constants/constants";
37+
38+
const ChangePermissionContainer = ({
39+
perm,
40+
setShowMessage,
41+
setMessage,
42+
currGroup,
43+
member,
44+
handleFetchGroupMembers,
45+
}) => {
46+
const [selectedPerm, setSelectedPerm] = useState(perm);
47+
48+
useEffect(() => {
49+
setSelectedPerm(perm);
50+
}, [perm]);
51+
52+
const handleSetNewPermission = async (newPerm) => {
53+
setSelectedPerm(newPerm);
54+
try {
55+
const res = await changeUserPermission(
56+
currGroup,
57+
member?.user.id,
58+
newPerm
59+
);
60+
setShowMessage(true);
61+
setMessage({
62+
type: "success",
63+
text: res.message,
64+
});
65+
handleFetchGroupMembers(currGroup);
66+
} catch (e) {
67+
setMessage({
68+
type: "danger",
69+
text: e.message,
70+
});
71+
} finally {
72+
setTimeout(() => {
73+
setShowMessage(false);
74+
}, [3000]);
75+
}
76+
};
77+
return (
78+
<tr>
79+
<td>{member?.user.name}</td>
80+
<td>
81+
<InputContainer
82+
type="select"
83+
name="name"
84+
options={userPermissions}
85+
id="select-tag"
86+
value={selectedPerm}
87+
property="name"
88+
onChange={(e) => handleSetNewPermission(e.target.value)}
89+
/>
90+
</td>
91+
</tr>
92+
);
93+
};
94+
95+
ChangePermissionContainer.propTypes = {
96+
perm: PropTypes.number,
97+
setMessage: PropTypes.func,
98+
currGroup: PropTypes.number,
99+
member: PropTypes.node,
100+
handleFetchGroupMembers: PropTypes.func,
101+
setShowMessage: PropTypes.func,
102+
};
103+
104+
const GroupCreate = () => {
105+
const initialMessage = {
106+
type: "success",
107+
text: "",
108+
};
109+
110+
const [currGroup, setCurrentGroup] = useState(null);
111+
const [groupMembers, setGroupMembers] = useState([]);
112+
const [groups, setGroups] = useState([]);
113+
114+
const [showMessage, setShowMessage] = useState(false);
115+
const [message, setMessage] = useState(initialMessage);
116+
117+
useEffect(async () => {
118+
try {
119+
const res = await fetchAllGroups();
120+
const resGrpMembers = await fetchAllGroupMembers(res[0].id);
121+
setCurrentGroup(res[0].id);
122+
setGroups(res);
123+
setGroupMembers(resGrpMembers);
124+
} catch (e) {
125+
setMessage({
126+
type: "danger",
127+
text: e.message,
128+
});
129+
}
130+
}, []);
131+
132+
const handleFetchGroupMembers = async (groupId) => {
133+
try {
134+
const res = await fetchAllGroupMembers(groupId);
135+
setGroupMembers(res);
136+
} catch (error) {
137+
setMessage({
138+
type: "danger",
139+
text: error.message,
140+
});
141+
}
142+
};
143+
144+
const handleGroupChange = async (e) => {
145+
setCurrentGroup(e.target.value);
146+
await handleFetchGroupMembers(e.target.value);
147+
};
148+
149+
return (
150+
<>
151+
<Title title="Manage Group Users" />
152+
<div className="main-container my-3">
153+
{showMessage && (
154+
<Alert
155+
type={message.type}
156+
setShow={setShowMessage}
157+
message={message.text}
158+
/>
159+
)}
160+
<h1 className="font-size-main-heading">Manage Group Users</h1>
161+
<br />
162+
<div className="row">
163+
<div className="col-12 col-lg-8">
164+
<form>
165+
<InputContainer
166+
type="select"
167+
name="name"
168+
options={groups}
169+
id="select-tag"
170+
property="name"
171+
onChange={(e) => handleGroupChange(e)}
172+
value={currGroup}
173+
>
174+
Select group to manage:
175+
</InputContainer>
176+
</form>
177+
178+
<table className="table table-striped table-bordered rounded mt-5">
179+
<thead className="bg-dark text-light font-weight-bold">
180+
<tr>
181+
<th>User</th>
182+
<th>Permission</th>
183+
</tr>
184+
</thead>
185+
<tbody>
186+
{groupMembers?.map((member) => (
187+
<ChangePermissionContainer
188+
currGroup={currGroup}
189+
member={member}
190+
handleFetchGroupMembers={handleFetchGroupMembers}
191+
perm={member.group_perm}
192+
setShowMessage={setShowMessage}
193+
setMessage={setMessage}
194+
key={member.user.id}
195+
/>
196+
))}
197+
</tbody>
198+
</table>
199+
</div>
200+
</div>
201+
</div>
202+
</>
203+
);
204+
};
205+
206+
export default GroupCreate;

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)