diff --git a/src/authz-module/data/api.ts b/src/authz-module/data/api.ts index 2ff3724..1821956 100644 --- a/src/authz-module/data/api.ts +++ b/src/authz-module/data/api.ts @@ -40,7 +40,7 @@ export type PermissionsByRole = { userCount: number; }; export interface PutAssignTeamMembersRoleResponse { - completed: { user: string; status: string }[]; + completed: { userIdentifier: string; status: string }[]; errors: { userIdentifier: string; error: string }[]; } diff --git a/src/authz-module/libraries-manager/ToastManagerContext.test.tsx b/src/authz-module/libraries-manager/ToastManagerContext.test.tsx index fe67c41..23bfc9a 100644 --- a/src/authz-module/libraries-manager/ToastManagerContext.test.tsx +++ b/src/authz-module/libraries-manager/ToastManagerContext.test.tsx @@ -137,4 +137,80 @@ describe('ToastManagerContext', () => { expect(logError).toHaveBeenCalled(); expect(retryFn).toHaveBeenCalled(); }); + + it('respects custom delay when provided', async () => { + const user = userEvent.setup(); + + const DelayTestComponent = () => { + const { showToast } = useToastManager(); + + const handleShowToastWithDelay = () => showToast({ + message: 'Custom delay toast', + type: 'success', + delay: 1000, // Custom 1 second delay + }); + + return ( + + ); + }; + + renderWrapper( + + + , + ); + + const showButton = screen.getByText('Show Toast With Custom Delay'); + await user.click(showButton); + + await waitFor(() => { + expect(screen.getByText('Custom delay toast')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getByText('Custom delay toast')).toBeInTheDocument(); + }, { timeout: 600 }); + + // Toast should disappear after the custom delay (1000ms) + await waitFor(() => { + expect(screen.queryByText('Custom delay toast')).not.toBeInTheDocument(); + }, { timeout: 1200 }); + }); + + it('uses default delay when delay prop is not provided', async () => { + const user = userEvent.setup(); + + const DefaultDelayTestComponent = () => { + const { showToast } = useToastManager(); + + const handleShowToastWithoutDelay = () => showToast({ + message: 'Default delay toast', + type: 'success', + // No delay prop provided + }); + + return ( + + ); + }; + + renderWrapper( + + + , + ); + + const showButton = screen.getByText('Show Toast With Default Delay'); + await user.click(showButton); + + await waitFor(() => { + expect(screen.getByText('Default delay toast')).toBeInTheDocument(); + }); + + // DEFAULT_TOAST_DELAY is 5000ms + await waitFor(() => { + expect(screen.queryByText('Default delay toast')).not.toBeInTheDocument(); + }, { timeout: 5050 }); + }, 5100); }); diff --git a/src/authz-module/libraries-manager/ToastManagerContext.tsx b/src/authz-module/libraries-manager/ToastManagerContext.tsx index 12089f4..7f0d9b1 100644 --- a/src/authz-module/libraries-manager/ToastManagerContext.tsx +++ b/src/authz-module/libraries-manager/ToastManagerContext.tsx @@ -5,6 +5,7 @@ import { logError } from '@edx/frontend-platform/logging'; import { useIntl } from '@edx/frontend-platform/i18n'; import { Toast } from '@openedx/paragon'; import messages from './messages'; +import { DEFAULT_TOAST_DELAY } from './constants'; type ToastType = 'success' | 'error' | 'error-retry'; @@ -19,11 +20,12 @@ export const ERROR_TOAST_MAP: Record void; + delay?: number; } const Bold = (chunk: string) => {chunk}; @@ -47,7 +49,7 @@ export const ToastManagerProvider = ({ children }: ToastManagerProviderProps) => const [toasts, setToasts] = useState<(AppToast & { visible: boolean })[]>([]); const showToast = (toast: Omit) => { - const id = `toast-notification-${Date.now()}`; + const id = `toast-notification-${Date.now()}-${Math.floor(Math.random() * 1000000)}`; const newToast = { ...toast, id, visible: true }; setToasts(prev => [...prev, newToast]); }; @@ -92,6 +94,7 @@ export const ToastManagerProvider = ({ children }: ToastManagerProviderProps) => key={toast.id} show={toast.visible} onClose={() => discardToast(toast.id)} + delay={toast.delay ?? DEFAULT_TOAST_DELAY} action={toast.onRetry ? { onClick: () => { discardToast(toast.id); diff --git a/src/authz-module/libraries-manager/components/AddNewTeamMemberModal/AddNewTeamMemberTrigger.test.tsx b/src/authz-module/libraries-manager/components/AddNewTeamMemberModal/AddNewTeamMemberTrigger.test.tsx index 0939eb4..5ddb309 100644 --- a/src/authz-module/libraries-manager/components/AddNewTeamMemberModal/AddNewTeamMemberTrigger.test.tsx +++ b/src/authz-module/libraries-manager/components/AddNewTeamMemberModal/AddNewTeamMemberTrigger.test.tsx @@ -21,20 +21,23 @@ jest.mock('./AddNewTeamMemberModal', () => { isOpen, close, onSave, isLoading, formValues, handleChangeForm, }) => ( isOpen ? ( -
- - +
+ +