Skip to content

Commit bf5ebaa

Browse files
bra-i-amdcoa
authored andcommitted
feat: add ConfirmDeletionModal for role removal confirmation in LibrariesUserManager
1 parent 4d958e1 commit bf5ebaa

3 files changed

Lines changed: 140 additions & 5 deletions

File tree

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

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { useEffect, useMemo } from 'react';
1+
import { useEffect, useMemo, useState } from 'react';
22
import { useNavigate, useParams } from 'react-router-dom';
33
import { useIntl } from '@edx/frontend-platform/i18n';
44
import { Container } from '@openedx/paragon';
55
import { ROUTES } from '@src/authz-module/constants';
6+
import { Role } from 'types';
67
import AuthZLayout from '../components/AuthZLayout';
78
import { useLibraryAuthZ } from './context';
89
import RoleCard from '../components/RoleCard';
@@ -11,6 +12,7 @@ import { useLibrary, useRevokeUserRoles, useTeamMembers } from '../data/hooks';
1112
import { buildPermissionsByRoleMatrix } from './utils';
1213

1314
import messages from './messages';
15+
import ConfirmDeletionModal from './components/ConfirmDeletionModal';
1416

1517
const LibrariesUserManager = () => {
1618
const intl = useIntl();
@@ -20,11 +22,14 @@ const LibrariesUserManager = () => {
2022
libraryId, permissions, roles, resources, canManageTeam,
2123
} = useLibraryAuthZ();
2224
const { data: library } = useLibrary(libraryId);
23-
const { mutate: revokeUserRoles } = useRevokeUserRoles();
25+
const { mutate: revokeUserRoles, isPending: isRevokingUserRole } = useRevokeUserRoles();
2426
const rootBreadcrumb = intl.formatMessage(messages['library.authz.breadcrumb.root']) || '';
2527
const pageManageTitle = intl.formatMessage(messages['library.authz.manage.page.title']);
2628
const teamMembersPath = `/authz/${ROUTES.LIBRARIES_TEAM_PATH.replace(':libraryId', libraryId)}`;
2729

30+
const [roleToDelete, setRoleToDelete] = useState('');
31+
const [showConfirmDeletionModal, setShowConfirmDeletionModal] = useState(false);
32+
2833
const { data: teamMembers, isLoading: isLoadingTeamMembers } = useTeamMembers(libraryId);
2934
const user = teamMembers?.find(member => member.username === username);
3035
const userRoles = useMemo(() => {
@@ -38,15 +43,29 @@ const LibrariesUserManager = () => {
3843
return assignedRoles;
3944
}, [roles, user?.roles, permissions, resources, intl]);
4045

46+
const handleCloseConfirmDeletionModal = () => {
47+
setShowConfirmDeletionModal(false);
48+
setRoleToDelete('');
49+
};
50+
51+
const handleShowConfirmDeletionModal = (role: Pick<Role, 'name' | 'role'>) => {
52+
setRoleToDelete(role.name);
53+
setShowConfirmDeletionModal(true);
54+
};
55+
4156
const handleRevokeUserRole = (role: string) => {
4257
if (user) {
4358
const data = {
4459
users: user.username,
45-
role,
60+
role: roles.find(r => r.name === role)!.role,
4661
scope: libraryId,
4762
};
4863

49-
revokeUserRoles({ data });
64+
revokeUserRoles({ data }, {
65+
onSuccess: () => {
66+
handleCloseConfirmDeletionModal();
67+
},
68+
});
5069
}
5170
};
5271

@@ -59,6 +78,19 @@ const LibrariesUserManager = () => {
5978

6079
return (
6180
<div className="authz-libraries">
81+
<ConfirmDeletionModal
82+
isOpen={showConfirmDeletionModal}
83+
close={handleCloseConfirmDeletionModal}
84+
onSave={() => handleRevokeUserRole(roleToDelete)}
85+
isDeleting={isRevokingUserRole}
86+
context={{
87+
userName: user?.username || '',
88+
scope: library.title,
89+
role: roleToDelete,
90+
rolesCount: userRoles.length,
91+
}}
92+
/>
93+
6294
<AuthZLayout
6395
context={{ id: libraryId, title: library.title, org: library.org }}
6496
navLinks={[{ label: rootBreadcrumb }, { label: pageManageTitle, to: teamMembersPath }]}
@@ -80,7 +112,7 @@ const LibrariesUserManager = () => {
80112
title={role.name}
81113
objectName={library.title}
82114
description={role.description}
83-
handleDelete={() => handleRevokeUserRole(role.role)}
115+
handleDelete={() => handleShowConfirmDeletionModal(role)}
84116
permissions={role.permissions as any[]}
85117
/>
86118
))}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { FC } from 'react';
2+
import {
3+
ActionRow, Icon, ModalDialog, Stack,
4+
StatefulButton,
5+
} from '@openedx/paragon';
6+
import { useIntl } from '@edx/frontend-platform/i18n';
7+
8+
import { SpinnerSimple } from '@openedx/paragon/icons';
9+
import messages from './messages';
10+
11+
interface ConfirmDeletionModalProps {
12+
isOpen: boolean;
13+
close: () => void;
14+
onSave: () => void;
15+
isDeleting?: boolean;
16+
context: {
17+
userName: string;
18+
scope: string;
19+
role: string;
20+
rolesCount: number;
21+
}
22+
}
23+
24+
const ConfirmDeletionModal: FC<ConfirmDeletionModalProps> = ({
25+
isOpen, close, onSave, isDeleting, context,
26+
}) => {
27+
const intl = useIntl();
28+
return (
29+
<ModalDialog
30+
title={intl.formatMessage(messages['library.authz.team.remove.user.modal.title'])}
31+
isOpen={isOpen}
32+
onClose={close}
33+
size="lg"
34+
hasCloseButton
35+
isFullscreenOnMobile
36+
isOverflowVisible={false}
37+
>
38+
<ModalDialog.Header>
39+
<ModalDialog.Title className="text-primary-500">
40+
{intl.formatMessage(messages['library.authz.team.remove.user.modal.title'])}
41+
</ModalDialog.Title>
42+
</ModalDialog.Header>
43+
44+
<ModalDialog.Body>
45+
<Stack gap={3}>
46+
<p>{intl.formatMessage(messages['library.authz.team.remove.user.modal.body.1'], {
47+
userName: context.userName,
48+
scope: context.scope,
49+
role: context.role,
50+
})}
51+
</p>
52+
{context.rolesCount === 1 && (
53+
<p>{intl.formatMessage(messages['library.authz.team.remove.user.modal.body.2'])}</p>
54+
)}
55+
<p>{intl.formatMessage(messages['library.authz.team.remove.user.modal.body.3'])}</p>
56+
</Stack>
57+
</ModalDialog.Body>
58+
59+
<ModalDialog.Footer>
60+
<ActionRow>
61+
<ModalDialog.CloseButton variant="tertiary">
62+
{intl.formatMessage(messages['libraries.authz.manage.cancel.button'])}
63+
</ModalDialog.CloseButton>
64+
<StatefulButton
65+
className="px-4"
66+
variant="danger"
67+
labels={{
68+
default: intl.formatMessage(messages['libraries.authz.manage.save.button']),
69+
pending: intl.formatMessage(messages['libraries.authz.manage.saving.button']),
70+
}}
71+
icons={{
72+
pending: <Icon src={SpinnerSimple} />,
73+
}}
74+
state={isDeleting ? 'pending' : 'default'}
75+
onClick={() => onSave()}
76+
disabledStates={['pending']}
77+
/>
78+
</ActionRow>
79+
</ModalDialog.Footer>
80+
</ModalDialog>
81+
);
82+
};
83+
84+
export default ConfirmDeletionModal;

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,25 @@ const messages = defineMessages({
3535
id: 'libraries.authz.manage.assign.new.role.title',
3636
defaultMessage: 'Add New Role',
3737
description: 'Libraries AuthZ assign a new role to a user button title',
38+
'library.authz.team.remove.user.modal.title': {
39+
id: 'library.authz.team.remove.user.modal.title',
40+
defaultMessage: 'Remove role?',
41+
description: 'Libraries team management remove user modal title',
42+
},
43+
'library.authz.team.remove.user.modal.body.1': {
44+
id: 'library.authz.team.remove.user.modal.body',
45+
defaultMessage: 'Are you sure you want to remove the {role} role from the user “{userName}” in the library {scope}?',
46+
description: 'Libraries team management remove user modal body',
47+
},
48+
'library.authz.team.remove.user.modal.body.2': {
49+
id: 'library.authz.team.remove.user.modal.body',
50+
defaultMessage: "This is the user's only role in this library. Removing it will revoke their access completely, and they will no longer appear in the library's member List.",
51+
description: 'Libraries team management remove user modal body',
52+
},
53+
'library.authz.team.remove.user.modal.body.3': {
54+
id: 'library.authz.team.remove.user.modal.body',
55+
defaultMessage: 'Are you sure you want to proceed?',
56+
description: 'Libraries team management remove user modal body',
3857
},
3958
'libraries.authz.manage.cancel.button': {
4059
id: 'libraries.authz.manage.cancel.button',

0 commit comments

Comments
 (0)