From a7ac631c36cf7eaef8d3f6df9a97b48d89d328a3 Mon Sep 17 00:00:00 2001 From: Jameson Date: Fri, 1 May 2026 14:47:21 -0600 Subject: [PATCH 1/2] refactor: remove support handling from ActionableError and related tests Co-authored-by: Copilot --- src/views/actionableError/ActionableError.tsx | 45 ++++++------------- .../__tests__/ActionableError-test.tsx | 32 ++++++++++++- .../__tests__/useActionableErrorMap-test.tsx | 41 +++++------------ .../actionableError/useActionableErrorMap.tsx | 11 ++--- 4 files changed, 59 insertions(+), 70 deletions(-) diff --git a/src/views/actionableError/ActionableError.tsx b/src/views/actionableError/ActionableError.tsx index 45e2fc8c18..5a2239f198 100644 --- a/src/views/actionableError/ActionableError.tsx +++ b/src/views/actionableError/ActionableError.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useRef } from 'react' +import React, { useContext, useEffect } from 'react' import { useSelector } from 'react-redux' import { InstitutionLogo, Text } from '@mxenabled/mxui' import { useTokens } from '@kyper/tokenprovider' @@ -7,7 +7,6 @@ import { Button, Badge } from '@mui/material' import { SlideDown } from 'src/components/SlideDown' import { PostMessageContext } from 'src/ConnectWidget' import { useActionableErrorMap } from 'src/views/actionableError/useActionableErrorMap' -import { Support as UntypedSupport, VIEWS as SUPPORT_VIEWS } from 'src/components/support/Support' import { ACTIONABLE_ERROR_CODES_READABLE } from 'src/views/actionableError/consts' import { PageviewInfo } from 'src/const/Analytics' @@ -17,18 +16,7 @@ import { useAnalyticsPath } from 'src/hooks/useAnalyticsPath' import { RootState } from 'src/redux/Store' import { getCurrentMember } from 'src/redux/selectors/Connect' -// This is due to trying to forwardRef a component written in JS -const Support = UntypedSupport as React.ForwardRefExoticComponent< - React.PropsWithoutRef<{ - loadToView: (typeof SUPPORT_VIEWS)[keyof typeof SUPPORT_VIEWS] - onClose: () => void - }> & - // eslint-disable-next-line @typescript-eslint/no-explicit-any - React.RefAttributes -> - export const ActionableError = () => { - const supportNavRef = useRef(null) const postMessageFunctions = useContext(PostMessageContext) const institution = useSelector((state: RootState) => state.connect.selectedInstitution) const currentMember = useSelector(getCurrentMember) @@ -41,8 +29,7 @@ export const ActionableError = () => { const tokens = useTokens() const styles = getStyles(tokens) const getNextDelay = getDelay() - const [showSupport, setShowSupport] = React.useState(false) - const errorDetails = useActionableErrorMap(jobDetailCode, setShowSupport) + const errorDetails = useActionableErrorMap(jobDetailCode) useEffect(() => { // Legacy postMessage for backwards compatibility @@ -54,13 +41,7 @@ export const ActionableError = () => { }) }, [jobDetailCode]) - return showSupport ? ( - setShowSupport(false)} - ref={supportNavRef} - /> - ) : ( + return ( <>
@@ -105,15 +86,17 @@ export const ActionableError = () => { > {errorDetails?.primaryAction.label} - + {errorDetails?.secondaryActions && ( + + )} ) diff --git a/src/views/actionableError/__tests__/ActionableError-test.tsx b/src/views/actionableError/__tests__/ActionableError-test.tsx index 9eb27cb32a..89a5bed32f 100644 --- a/src/views/actionableError/__tests__/ActionableError-test.tsx +++ b/src/views/actionableError/__tests__/ActionableError-test.tsx @@ -92,7 +92,7 @@ describe('ActionableError', () => { expect(primaryButton).toHaveClass('MuiButton-contained') }) - it('should render secondary action buttons', () => { + it('should render secondary action buttons if they exist', () => { render(, { preloadedState: initialState, }) @@ -100,4 +100,34 @@ describe('ActionableError', () => { expect(secondaryButton).toBeInTheDocument() expect(secondaryButton).toHaveClass('MuiButton-text') }) + + it('should not render secondary action if it does not exist in the mapping', () => { + const modifiedInitialState = { + ...initialState, + connect: { + ...initialState.connect, + selectedInstitution: institutionMock, + currentMemberGuid: membersMock[0].guid, + members: [ + { + guid: 'MEM-123', + error: { + error_code: ACTIONABLE_ERROR_CODES.NO_ACCOUNTS, + error_message: 'No accounts found.', + error_type: 'MEMBER', + locale: 'en', + user_message: + 'This may be due to closed accounts, revoked access, or a connection issue. Please try again later or connect a different institution.', + }, + name: 'Member', + }, + ], + }, + } + render(, { + preloadedState: modifiedInitialState, + }) + const secondaryButton = screen.queryByTestId('actionable-error-secondary-button') + expect(secondaryButton).not.toBeInTheDocument() + }) }) diff --git a/src/views/actionableError/__tests__/useActionableErrorMap-test.tsx b/src/views/actionableError/__tests__/useActionableErrorMap-test.tsx index e3a3f907d6..fc237cd501 100644 --- a/src/views/actionableError/__tests__/useActionableErrorMap-test.tsx +++ b/src/views/actionableError/__tests__/useActionableErrorMap-test.tsx @@ -8,7 +8,6 @@ import { AGG_MODE, VERIFY_MODE } from 'src/const/Connect' import { initialState as configInitialState } from 'src/redux/reducers/configSlice' // Setup Mocks -const setShowSupport = vitest.fn() export const dispatch = vitest.fn() vitest.mock('react-redux', async (importActual) => { const actual = (await importActual()) as object @@ -36,7 +35,7 @@ const aggregationPreloadedState = { // Test Component to utilize the hook const TestComponent = ({ errorCode }: { errorCode: number }) => { - const errorDetails = useActionableErrorMap(errorCode, setShowSupport) + const errorDetails = useActionableErrorMap(errorCode) return (
@@ -44,9 +43,11 @@ const TestComponent = ({ errorCode }: { errorCode: number }) => { - + {errorDetails.secondaryActions && ( + + )}
) } @@ -83,19 +84,15 @@ describe('useActionableErrorMap', () => { }) expect(screen.getByText('No accounts found')).toBeInTheDocument() expect(screen.getByText('Return to institution selection')).toBeInTheDocument() - expect(screen.getByText('Get help')).toBeInTheDocument() + expect(screen.queryByText('Get help')).not.toBeInTheDocument() const primaryButton = screen.getByText('Return to institution selection') - const secondaryButton = screen.getByText('Get help') primaryButton.click() expect(dispatch).toHaveBeenCalledWith({ type: ActionTypes.ACTIONABLE_ERROR_CONNECT_DIFFERENT_INSTITUTION, payload: AGG_MODE, }) - - secondaryButton.click() - expect(setShowSupport).toHaveBeenCalledTimes(1) }) it('should return correct mapping and actions for ACCESS_DENIED', () => { @@ -104,18 +101,14 @@ describe('useActionableErrorMap', () => { }) expect(screen.getByText('Additional permissions needed')).toBeInTheDocument() expect(screen.getByText('Review instructions')).toBeInTheDocument() - expect(screen.getByText('Get help')).toBeInTheDocument() + expect(screen.queryByText('Get help')).not.toBeInTheDocument() const primaryButton = screen.getByText('Review instructions') - const secondaryButton = screen.getByText('Get help') primaryButton.click() expect(dispatch).toHaveBeenCalledWith({ type: ActionTypes.ACTIONABLE_ERROR_LOG_IN_AGAIN, }) - - secondaryButton.click() - expect(setShowSupport).toHaveBeenCalledTimes(1) }) it('should return correct mapping and actions for INSTITUTION_DOWN', () => { @@ -124,19 +117,15 @@ describe('useActionableErrorMap', () => { }) expect(screen.getByText('Unable to connect')).toBeInTheDocument() expect(screen.getByText('Return to institution selection')).toBeInTheDocument() - expect(screen.getByText('Get help')).toBeInTheDocument() + expect(screen.queryByText('Get help')).not.toBeInTheDocument() const primaryButton = screen.getByText('Return to institution selection') - const secondaryButton = screen.getByText('Get help') primaryButton.click() expect(dispatch).toHaveBeenCalledWith({ type: ActionTypes.ACTIONABLE_ERROR_CONNECT_DIFFERENT_INSTITUTION, payload: AGG_MODE, }) - - secondaryButton.click() - expect(setShowSupport).toHaveBeenCalledTimes(1) }) it('should return correct mapping and actions for INSTITUTION_MAINTENANCE', () => { @@ -145,19 +134,15 @@ describe('useActionableErrorMap', () => { }) expect(screen.getByText('Maintenance in progress')).toBeInTheDocument() expect(screen.getByText('Return to institution selection')).toBeInTheDocument() - expect(screen.getByText('Get help')).toBeInTheDocument() + expect(screen.queryByText('Get help')).not.toBeInTheDocument() const primaryButton = screen.getByText('Return to institution selection') - const secondaryButton = screen.getByText('Get help') primaryButton.click() expect(dispatch).toHaveBeenCalledWith({ type: ActionTypes.ACTIONABLE_ERROR_CONNECT_DIFFERENT_INSTITUTION, payload: AGG_MODE, }) - - secondaryButton.click() - expect(setShowSupport).toHaveBeenCalledTimes(1) }) it('should return correct mapping and actions for INSTITUTION_UNAVAILABLE', () => { @@ -166,18 +151,14 @@ describe('useActionableErrorMap', () => { }) expect(screen.getByText('Unable to connect')).toBeInTheDocument() expect(screen.getByText('Return to institution selection')).toBeInTheDocument() - expect(screen.getByText('Get help')).toBeInTheDocument() + expect(screen.queryByText('Get help')).not.toBeInTheDocument() const primaryButton = screen.getByText('Return to institution selection') - const secondaryButton = screen.getByText('Get help') primaryButton.click() expect(dispatch).toHaveBeenCalledWith({ type: ActionTypes.ACTIONABLE_ERROR_CONNECT_DIFFERENT_INSTITUTION, payload: AGG_MODE, }) - - secondaryButton.click() - expect(setShowSupport).toHaveBeenCalledTimes(1) }) }) diff --git a/src/views/actionableError/useActionableErrorMap.tsx b/src/views/actionableError/useActionableErrorMap.tsx index 6ee686db39..fb05dc4b89 100644 --- a/src/views/actionableError/useActionableErrorMap.tsx +++ b/src/views/actionableError/useActionableErrorMap.tsx @@ -14,12 +14,12 @@ type ActionableErrorAction = { type ActionableErrorMapEntry = { title: string primaryAction: ActionableErrorAction - secondaryActions: ActionableErrorAction + secondaryActions?: ActionableErrorAction } export const useActionableErrorMap = ( jobDetailCode: number, - setShowSupport: React.Dispatch>, + // setShowSupport: React.Dispatch>, ) => { const postMessageFunctions = useContext(PostMessageContext) const initialConfig = useSelector(selectInitialConfig) @@ -33,7 +33,7 @@ export const useActionableErrorMap = ( payload: initialConfig.mode || AGG_MODE, }) } - const goToSupport = () => setShowSupport(true) + // const goToSupport = () => setShowSupport(true) const goToCredentials = () => dispatch({ type: ActionTypes.ACTIONABLE_ERROR_LOG_IN_AGAIN }) // AED Step 3: Add code mapping for new codes here @@ -47,27 +47,22 @@ export const useActionableErrorMap = ( [ACTIONABLE_ERROR_CODES.NO_ACCOUNTS]: { title: __('No accounts found'), primaryAction: { label: __('Return to institution selection'), action: goToSearch }, - secondaryActions: { label: __('Get help'), action: goToSupport }, }, [ACTIONABLE_ERROR_CODES.ACCESS_DENIED]: { title: __('Additional permissions needed'), primaryAction: { label: __('Review instructions'), action: goToCredentials }, - secondaryActions: { label: __('Get help'), action: goToSupport }, }, [ACTIONABLE_ERROR_CODES.INSTITUTION_DOWN]: { title: __('Unable to connect'), primaryAction: { label: __('Return to institution selection'), action: goToSearch }, - secondaryActions: { label: __('Get help'), action: goToSupport }, }, [ACTIONABLE_ERROR_CODES.INSTITUTION_MAINTENANCE]: { title: __('Maintenance in progress'), primaryAction: { label: __('Return to institution selection'), action: goToSearch }, - secondaryActions: { label: __('Get help'), action: goToSupport }, }, [ACTIONABLE_ERROR_CODES.INSTITUTION_UNAVAILABLE]: { title: __('Unable to connect'), primaryAction: { label: __('Return to institution selection'), action: goToSearch }, - secondaryActions: { label: __('Get help'), action: goToSupport }, }, }), [dispatch], From be2c211ba0b72ad0b3501e8c21bdc1a4644412c5 Mon Sep 17 00:00:00 2001 From: Jameson Date: Fri, 1 May 2026 15:10:42 -0600 Subject: [PATCH 2/2] remove unused support handling from useActionableErrorMap --- src/views/actionableError/useActionableErrorMap.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/views/actionableError/useActionableErrorMap.tsx b/src/views/actionableError/useActionableErrorMap.tsx index fb05dc4b89..22a86f7f7f 100644 --- a/src/views/actionableError/useActionableErrorMap.tsx +++ b/src/views/actionableError/useActionableErrorMap.tsx @@ -17,10 +17,7 @@ type ActionableErrorMapEntry = { secondaryActions?: ActionableErrorAction } -export const useActionableErrorMap = ( - jobDetailCode: number, - // setShowSupport: React.Dispatch>, -) => { +export const useActionableErrorMap = (jobDetailCode: number) => { const postMessageFunctions = useContext(PostMessageContext) const initialConfig = useSelector(selectInitialConfig) const dispatch = useDispatch() @@ -33,7 +30,6 @@ export const useActionableErrorMap = ( payload: initialConfig.mode || AGG_MODE, }) } - // const goToSupport = () => setShowSupport(true) const goToCredentials = () => dispatch({ type: ActionTypes.ACTIONABLE_ERROR_LOG_IN_AGAIN }) // AED Step 3: Add code mapping for new codes here