From 8c4eeb2c09a9c322c2d557585aa1bd6ccfb2aeff Mon Sep 17 00:00:00 2001 From: Jacobo Dominguez Date: Wed, 18 Feb 2026 15:37:28 -0600 Subject: [PATCH] feat: extending delay time for error toasts with retry fn (#67) --- src/authz-module/data/hooks.ts | 8 ++-- .../ToastManagerContext.test.tsx | 40 +++++++++++++++++++ .../libraries-manager/ToastManagerContext.tsx | 10 ++++- .../libraries-manager/constants.ts | 1 + 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/authz-module/data/hooks.ts b/src/authz-module/data/hooks.ts index 2dc6427..7f50bea 100644 --- a/src/authz-module/data/hooks.ts +++ b/src/authz-module/data/hooks.ts @@ -83,9 +83,11 @@ export const useAssignTeamMembersRole = () => { mutationFn: async ({ data }: { data: AssignTeamMembersRoleRequest }) => assignTeamMembersRole(data), - onSettled: (_data, _error, { data: { scope } }) => { - queryClient.invalidateQueries({ queryKey: authzQueryKeys.teamMembersAll(scope) }); - queryClient.invalidateQueries({ queryKey: authzQueryKeys.permissionsByRole(scope) }); + onSettled: (_data, error, { data: { scope } }) => { + if (!error) { + queryClient.invalidateQueries({ queryKey: authzQueryKeys.teamMembersAll(scope) }); + queryClient.invalidateQueries({ queryKey: authzQueryKeys.permissionsByRole(scope) }); + } }, }); }; diff --git a/src/authz-module/libraries-manager/ToastManagerContext.test.tsx b/src/authz-module/libraries-manager/ToastManagerContext.test.tsx index 23bfc9a..42e3480 100644 --- a/src/authz-module/libraries-manager/ToastManagerContext.test.tsx +++ b/src/authz-module/libraries-manager/ToastManagerContext.test.tsx @@ -213,4 +213,44 @@ describe('ToastManagerContext', () => { expect(screen.queryByText('Default delay toast')).not.toBeInTheDocument(); }, { timeout: 5050 }); }, 5100); + + it('uses longer delay for error toasts with retry functionality', async () => { + const user = userEvent.setup(); + const retryFn = jest.fn(); + + const RetryErrorDelayTestComponent = () => { + const { showErrorToast } = useToastManager(); + + const handleShowRetryErrorToast = () => showErrorToast( + { customAttributes: { httpErrorStatus: 500 } }, + retryFn, + ); + + return ( + + ); + }; + + renderWrapper( + + + , + ); + + const showButton = screen.getByText('Show Retry Error Toast'); + await user.click(showButton); + + await waitFor(() => { + expect(screen.getByRole('alert')).toBeInTheDocument(); + expect(screen.getByText('Retry')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getByRole('alert')).toBeInTheDocument(); + }, { timeout: 5050 }); + + expect(logError).toHaveBeenCalled(); + }); }); diff --git a/src/authz-module/libraries-manager/ToastManagerContext.tsx b/src/authz-module/libraries-manager/ToastManagerContext.tsx index 7f0d9b1..55be67a 100644 --- a/src/authz-module/libraries-manager/ToastManagerContext.tsx +++ b/src/authz-module/libraries-manager/ToastManagerContext.tsx @@ -5,7 +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'; +import { DEFAULT_TOAST_DELAY, RETRY_TOAST_DELAY } from './constants'; type ToastType = 'success' | 'error' | 'error-retry'; @@ -68,11 +68,19 @@ export const ToastManagerProvider = ({ children }: ToastManagerProviderProps) => const errorStatus = error?.customAttributes?.httpErrorStatus; const toastConfig = ERROR_TOAST_MAP[errorStatus] || ERROR_TOAST_MAP.DEFAULT; const message = intl.formatMessage(messages[toastConfig.messageId], { Bold, Br }); + /** + * For retryable errors, we set a longer delay to give users more time to read the message + * and decide to retry, while for non-retryable errors we use the default delay. + * Since current toast implementation does not allow disabling the autohide prop, + * we use a longer delay for retryable errors to give users more time to read the message. + */ + const delay = toastConfig.type === 'error-retry' && retryFn ? RETRY_TOAST_DELAY : DEFAULT_TOAST_DELAY; showToast({ message, type: toastConfig.type, onRetry: toastConfig.type === 'error-retry' && retryFn ? retryFn : undefined, + delay, }); }; diff --git a/src/authz-module/libraries-manager/constants.ts b/src/authz-module/libraries-manager/constants.ts index c89be35..d136896 100644 --- a/src/authz-module/libraries-manager/constants.ts +++ b/src/authz-module/libraries-manager/constants.ts @@ -51,6 +51,7 @@ export const libraryPermissions: PermissionMetadata[] = [ ]; export const DEFAULT_TOAST_DELAY = 5000; +export const RETRY_TOAST_DELAY = 120_000; // 2 minutes export const SKELETON_ROWS = Array.from({ length: 10 }).map(() => ({ username: 'skeleton', name: '',