Skip to content

Commit 0385420

Browse files
committed
feat: add tost for error feedback
1 parent 95af7f8 commit 0385420

6 files changed

Lines changed: 62 additions & 31 deletions

File tree

src/authz-module/components/RoleCard/index.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe('RoleCard', () => {
2020
title: 'Admin',
2121
objectName: 'Test Library',
2222
description: 'Can manage everything',
23-
showDelete: true,
23+
handleDelete: jest.fn(),
2424
userCounter: 2,
2525
permissions: [
2626
{
@@ -71,8 +71,8 @@ describe('RoleCard', () => {
7171
expect(screen.getByTestId('manage-icon')).toBeInTheDocument();
7272
});
7373

74-
it('does not show delete button when showDelete is false', () => {
75-
renderWrapper(<RoleCard {...defaultProps} showDelete={false} />);
74+
it('does not show delete button when handleDelete is not passed', () => {
75+
renderWrapper(<RoleCard {...defaultProps} handleDelete={undefined} />);
7676
expect(screen.queryByRole('button', { name: /delete role action/i })).not.toBeInTheDocument();
7777
});
7878

src/authz-module/data/hooks.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ export const useAssignTeamMembersRole = () => {
8787
});
8888
};
8989

90-
9190
/**
9291
* React Query hook to remove roles for a specific team member within a scope.
9392
*

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { renderWrapper } from '@src/setupTest';
44
import LibrariesUserManager from './LibrariesUserManager';
55
import { useLibraryAuthZ } from './context';
66
import { useLibrary, useTeamMembers } from '../data/hooks';
7+
import { ToastManagerProvider } from './ToastManagerContext';
78

89
jest.mock('react-router-dom', () => ({
910
...jest.requireActual('react-router-dom'),
@@ -17,6 +18,11 @@ jest.mock('./context', () => ({
1718
jest.mock('../data/hooks', () => ({
1819
useLibrary: jest.fn(),
1920
useTeamMembers: jest.fn(),
21+
useRevokeUserRoles: jest.fn(() => ({
22+
isPending: false,
23+
mutation: jest.fn(),
24+
25+
})),
2026
}));
2127
jest.mock('../components/RoleCard', () => ({
2228
__esModule: true,
@@ -73,7 +79,7 @@ describe('LibrariesUserManager', () => {
7379
});
7480

7581
it('renders the user roles correctly', () => {
76-
renderWrapper(<LibrariesUserManager />);
82+
renderWrapper(<ToastManagerProvider><LibrariesUserManager /></ToastManagerProvider>);
7783

7884
// Breadcrumb check
7985
expect(screen.getByText('Manage Access')).toBeInTheDocument();

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

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import { useEffect, useMemo, useState } from 'react';
22
import { useNavigate, useParams } from 'react-router-dom';
33
import { useIntl } from '@edx/frontend-platform/i18n';
4+
import { logError } from '@edx/frontend-platform/logging';
45
import { Container } from '@openedx/paragon';
56
import { ROUTES } from '@src/authz-module/constants';
67
import { Role } from 'types';
7-
import { useToastManager } from 'authz-module/libraries-manager/ToastManagerContext';
8+
import { useToastManager } from '@src/authz-module/libraries-manager/ToastManagerContext';
89
import AuthZLayout from '../components/AuthZLayout';
910
import { useLibraryAuthZ } from './context';
1011
import RoleCard from '../components/RoleCard';
1112
import { AssignNewRoleTrigger } from './components/AssignNewRoleModal';
13+
import ConfirmDeletionModal from './components/ConfirmDeletionModal';
1214
import { useLibrary, useRevokeUserRoles, useTeamMembers } from '../data/hooks';
1315
import { buildPermissionsByRoleMatrix } from './utils';
1416

1517
import messages from './messages';
16-
import ConfirmDeletionModal from './components/ConfirmDeletionModal';
1718

1819
const LibrariesUserManager = () => {
1920
const intl = useIntl();
@@ -22,18 +23,26 @@ const LibrariesUserManager = () => {
2223
const {
2324
libraryId, permissions, roles, resources, canManageTeam,
2425
} = useLibraryAuthZ();
26+
const teamMembersPath = `/authz/${ROUTES.LIBRARIES_TEAM_PATH.replace(':libraryId', libraryId)}`;
27+
28+
useEffect(() => {
29+
if (!canManageTeam) {
30+
navigate(teamMembersPath);
31+
}
32+
// eslint-disable-next-line react-hooks/exhaustive-deps
33+
}, [canManageTeam]);
34+
2535
const { data: library } = useLibrary(libraryId);
2636
const { mutate: revokeUserRoles, isPending: isRevokingUserRole } = useRevokeUserRoles();
2737
const rootBreadcrumb = intl.formatMessage(messages['library.authz.breadcrumb.root']) || '';
2838
const pageManageTitle = intl.formatMessage(messages['library.authz.manage.page.title']);
29-
const teamMembersPath = `/authz/${ROUTES.LIBRARIES_TEAM_PATH.replace(':libraryId', libraryId)}`;
3039

3140
const [roleToDelete, setRoleToDelete] = useState<Role | null>(null);
3241
const [showConfirmDeletionModal, setShowConfirmDeletionModal] = useState(false);
3342
const { handleShowToast, handleDiscardToast } = useToastManager();
3443

35-
const { data: teamMembers, isLoading: isLoadingTeamMembers } = useTeamMembers(libraryId);
36-
const user = teamMembers?.find(member => member.username === username);
44+
const { data: teamMember, isLoading: isLoadingTeamMember, isFetching: isFetchingMember } = useTeamMembers(libraryId);
45+
const user = teamMember?.find(member => member.username === username);
3746
const userRoles = useMemo(() => {
3847
const assignedRoles = roles.filter(role => user?.roles.includes(role.role))
3948
.map(role => ({
@@ -45,6 +54,15 @@ const LibrariesUserManager = () => {
4554
return assignedRoles;
4655
}, [roles, user?.roles, permissions, resources, intl]);
4756

57+
useEffect(() => {
58+
if (!isFetchingMember) {
59+
if (!isLoadingTeamMember && !user?.username) {
60+
navigate(teamMembersPath);
61+
}
62+
}
63+
// eslint-disable-next-line react-hooks/exhaustive-deps
64+
}, [isFetchingMember, isLoadingTeamMember, user?.username]);
65+
4866
const handleCloseConfirmDeletionModal = () => {
4967
setRoleToDelete(null);
5068
setShowConfirmDeletionModal(false);
@@ -80,21 +98,14 @@ const LibrariesUserManager = () => {
8098
handleCloseConfirmDeletionModal();
8199
},
82100
onError: (error) => {
83-
// eslint-disable-next-line no-console
84-
console.error('Failed to revoke user role:', error);
101+
logError(error);
102+
// eslint-disable-next-line react/no-unstable-nested-components
103+
handleShowToast(intl.formatMessage(messages['library.authz.team.default.error.toast.message'], { b: chunk => <b>{chunk}</b>, br: () => <br /> }));
85104
handleCloseConfirmDeletionModal();
86-
// Could add error toast here if needed
87105
},
88106
});
89107
};
90108

91-
useEffect(() => {
92-
if (!isLoadingTeamMembers && !userRoles.length) {
93-
navigate(teamMembersPath);
94-
}
95-
// eslint-disable-next-line react-hooks/exhaustive-deps
96-
}, [userRoles.length]);
97-
98109
return (
99110
<div className="authz-libraries">
100111
<ConfirmDeletionModal
@@ -127,7 +138,7 @@ const LibrariesUserManager = () => {
127138
<Container className="bg-light-200 p-5">
128139
{userRoles && userRoles.map(role => (
129140
<RoleCard
130-
key={`${role}-${username}`}
141+
key={`${role.role}-${username}`}
131142
title={role.name}
132143
objectName={library.title}
133144
description={role.description}

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

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,26 @@ const messages = defineMessages({
3636
defaultMessage: 'Add New Role',
3737
description: 'Libraries AuthZ assign a new role to a user button title',
3838
},
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+
},
54+
'libraries.authz.manage.assign.role.success': {
55+
id: 'libraries.authz.manage.assign.role.success',
56+
defaultMessage: 'Role added successfully.',
57+
description: 'Libraries AuthZ assign role success message',
58+
},
3959
'library.authz.team.remove.user.modal.title': {
4060
id: 'library.authz.team.remove.user.modal.title',
4161
defaultMessage: 'Remove role?',
@@ -56,11 +76,6 @@ const messages = defineMessages({
5676
defaultMessage: 'Are you sure you want to proceed?',
5777
description: 'Libraries team management remove user modal body',
5878
},
59-
'libraries.authz.manage.cancel.button': {
60-
id: 'libraries.authz.manage.cancel.button',
61-
defaultMessage: 'Cancel',
62-
description: 'Libraries AuthZ cancel button title',
63-
},
6479
'libraries.authz.manage.removing.button': {
6580
id: 'libraries.authz.manage.removing.button',
6681
defaultMessage: 'Removing...',
@@ -71,11 +86,6 @@ const messages = defineMessages({
7186
defaultMessage: 'Remove',
7287
description: 'Libraries AuthZ remove button title',
7388
},
74-
'libraries.authz.manage.assign.role.success': {
75-
id: 'libraries.authz.manage.assign.role.success',
76-
defaultMessage: 'Role added successfully.',
77-
description: 'Libraries AuthZ assign role success message',
78-
},
7989
});
8090

8191
export default messages;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ const messages = defineMessages({
3131
defaultMessage: 'The {role} role has been successfully removed.{rolesCount, plural, =0 { The user no longer has access to this library and has been removed from the member list.} other {}}',
3232
description: 'Libraries team management remove user toast success',
3333
},
34+
'library.authz.team.default.error.toast.message': {
35+
id: 'library.authz.team.default.error.toast.message',
36+
defaultMessage: '<b>Something went wrong on our end</b> <br></br> Please try again later.',
37+
description: 'Libraries team management remove user toast success',
38+
},
3439
});
3540

3641
export default messages;

0 commit comments

Comments
 (0)