Skip to content

Commit c3097b9

Browse files
bra-i-amdcoa
authored andcommitted
feat: add role assignment functionality with modal and trigger components
1 parent 93aebcd commit c3097b9

4 files changed

Lines changed: 168 additions & 1 deletion

File tree

src/authz-module/libraries-manager/LibrariesUserManager.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { useLibrary, useTeamMembers } from '../data/hooks';
1010
import { buildPermissionsByRoleMatrix } from './utils';
1111

1212
import messages from './messages';
13+
import AddNewMemberRoleTrigger from './components/AssignNewRoleTrigger';
1314

1415
const LibrariesUserManager = () => {
1516
const intl = useIntl();
@@ -42,7 +43,13 @@ const LibrariesUserManager = () => {
4243
activeLabel={user?.username || ''}
4344
pageTitle={user?.username || ''}
4445
pageSubtitle={<p>{user?.email}</p>}
45-
actions={[]}
46+
actions={user
47+
? [<AddNewMemberRoleTrigger
48+
username={user.username}
49+
libraryId={libraryId}
50+
currentUserRoles={userRoles.map(role => role.role)}
51+
/>]
52+
: []}
4653
>
4754
<Container className="bg-light-200 p-5">
4855
{isLoading ? <Skeleton count={2} height={200} /> : null}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { FC } from 'react';
2+
import { useIntl } from '@edx/frontend-platform/i18n';
3+
import {
4+
ActionRow, Button, Form, ModalDialog,
5+
} from '@openedx/paragon';
6+
import { Role } from 'types';
7+
import messages from './messages';
8+
9+
interface AssignNewRoleModalProps {
10+
isOpen: boolean;
11+
isLoading: boolean;
12+
roleOptions: Role[];
13+
selectedRole: string;
14+
close: () => void;
15+
onSave: () => void;
16+
handleChangeSelectedRole: (e: React.ChangeEvent<HTMLTextAreaElement | HTMLSelectElement>) => void;
17+
}
18+
19+
const AssignNewRoleModal: FC<AssignNewRoleModalProps> = ({
20+
isOpen, isLoading, selectedRole, roleOptions, close, onSave, handleChangeSelectedRole,
21+
}) => {
22+
const intl = useIntl();
23+
return (
24+
<ModalDialog
25+
title={intl.formatMessage(messages['libraries.authz.manage.assign.new.role.title'])}
26+
isOpen={isOpen}
27+
onClose={isLoading ? () => {} : close}
28+
size="lg"
29+
variant="dark"
30+
hasCloseButton
31+
isOverflowVisible={false}
32+
zIndex={5}
33+
>
34+
<ModalDialog.Header className="bg-primary-500 text-light-100">
35+
<ModalDialog.Title>
36+
{intl.formatMessage(messages['libraries.authz.manage.assign.new.role.title'])}
37+
</ModalDialog.Title>
38+
</ModalDialog.Header>
39+
40+
<ModalDialog.Body className="my-4">
41+
<Form.Group controlId="role_options">
42+
<Form.Label>{intl.formatMessage(messages['library.authz.team.table.roles'])}</Form.Label>
43+
<Form.Control as="select" name="role" value={selectedRole} onChange={handleChangeSelectedRole}>
44+
<option value="" disabled>Select a role</option>
45+
{roleOptions.map((role) => <option key={role.role} value={role.role}>{role.name}</option>)}
46+
</Form.Control>
47+
</Form.Group>
48+
</ModalDialog.Body>
49+
50+
<ModalDialog.Footer>
51+
<ActionRow>
52+
<ModalDialog.CloseButton variant="tertiary" disabled={isLoading}>
53+
{intl.formatMessage(messages['libraries.authz.manage.cancel.button'])}
54+
</ModalDialog.CloseButton>
55+
<Button
56+
className="px-4"
57+
onClick={() => onSave()}
58+
disabled={!selectedRole || isLoading}
59+
>
60+
{isLoading
61+
? intl.formatMessage(messages['libraries.authz.manage.saving.button'])
62+
: intl.formatMessage(messages['libraries.authz.manage.save.button'])}
63+
</Button>
64+
</ActionRow>
65+
</ModalDialog.Footer>
66+
</ModalDialog>
67+
);
68+
};
69+
70+
export default AssignNewRoleModal;
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import React, { FC, useState } from 'react';
2+
import { useIntl } from '@edx/frontend-platform/i18n';
3+
import { Button, useToggle } from '@openedx/paragon';
4+
import { Plus } from '@openedx/paragon/icons';
5+
6+
import { useLibraryAuthZ } from '@src/authz-module/libraries-manager/context';
7+
import { useAssignTeamMembersRole } from 'authz-module/data/hooks';
8+
import messages from './messages';
9+
import AssignNewRoleModal from './AssignNewRoleModal';
10+
11+
interface AssignNewRoleTriggerProps {
12+
username: string;
13+
libraryId: string;
14+
currentUserRoles: string[];
15+
}
16+
17+
const AssignNewRoleTrigger: FC<AssignNewRoleTriggerProps> = ({
18+
username,
19+
libraryId,
20+
currentUserRoles,
21+
}) => {
22+
const intl = useIntl();
23+
const [isOpen, open, close] = useToggle(false);
24+
const { roles } = useLibraryAuthZ();
25+
26+
const [newRole, setNewRole] = useState<string>('');
27+
28+
const { mutate: assignTeamMembersRole, isPending: isAssignTeamMembersRolePending } = useAssignTeamMembersRole();
29+
30+
const handleAddTeamMember = () => {
31+
const data = {
32+
users: [username],
33+
role: newRole,
34+
scope: libraryId,
35+
};
36+
37+
assignTeamMembersRole({ data }, {
38+
onSuccess: () => {
39+
close();
40+
setNewRole('');
41+
},
42+
});
43+
};
44+
45+
return (
46+
<>
47+
<Button
48+
key="authz-header-action-new-team-member"
49+
iconBefore={Plus}
50+
onClick={open}
51+
>
52+
{intl.formatMessage(messages['libraries.authz.manage.assign.new.role.title'])}
53+
</Button>
54+
55+
{isOpen && (
56+
<AssignNewRoleModal
57+
isOpen={isOpen}
58+
close={close}
59+
onSave={handleAddTeamMember}
60+
isLoading={isAssignTeamMembersRolePending}
61+
roleOptions={roles.filter(role => !currentUserRoles.includes(role.role))}
62+
selectedRole={newRole}
63+
handleChangeSelectedRole={(e) => setNewRole(e.target.value)}
64+
/>
65+
)}
66+
</>
67+
);
68+
};
69+
70+
export default AssignNewRoleTrigger;

src/authz-module/libraries-manager/components/messages.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,26 @@ const messages = defineMessages({
3131
defaultMessage: 'Edit',
3232
description: 'Edit action',
3333
},
34+
'libraries.authz.manage.assign.new.role.title': {
35+
id: 'libraries.authz.manage.assign.new.role.title',
36+
defaultMessage: 'Add New Role',
37+
description: 'Libraries AuthZ assign a new role to a user button title',
38+
},
39+
'libraries.authz.manage.cancel.button': {
40+
id: 'libraries.authz.manage.cancel.button',
41+
defaultMessage: 'Cancel',
42+
description: 'Libraries AuthZ cancel button title',
43+
},
44+
'libraries.authz.manage.saving.button': {
45+
id: 'libraries.authz.manage.saving.button',
46+
defaultMessage: 'Saving...',
47+
description: 'Libraries AuthZ saving button title',
48+
},
49+
'libraries.authz.manage.save.button': {
50+
id: 'libraries.authz.manage.save.button',
51+
defaultMessage: 'Save',
52+
description: 'Libraries AuthZ save button title',
53+
},
3454
});
3555

3656
export default messages;

0 commit comments

Comments
 (0)