Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions src/components/InstitutionTile.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import { ChevronRight } from '@kyper/icon/ChevronRight'
import { InstitutionLogo } from '@mxenabled/mxui'

import { formatUrl } from 'src/utilities/FormatUrl'
import { InstitutionStatus, useInstitutionStatus } from 'src/utilities/institutionStatus'
import {
institutionStatusIsUnavailable,
useInstitutionStatus,
} from 'src/utilities/institutionStatus'

export const InstitutionTile = (props) => {
const { institution, selectInstitution, size } = props
Expand All @@ -19,6 +22,13 @@ export const InstitutionTile = (props) => {
const tokens = useTokens()
const styles = getStyles(tokens)

let statusChip = null
if (institution.is_disabled_by_client) {
statusChip = <Chip color="secondary" label={__('DISABLED')} size="small" sx={styles.chip} />
} else if (institutionStatusIsUnavailable(status)) {
statusChip = <Chip color="error" label={__('UNAVAILABLE')} size="small" sx={styles.chip} />
}

return (
<Button
aria-label={__('Add account with %1', institution.name)}
Expand Down Expand Up @@ -73,12 +83,7 @@ export const InstitutionTile = (props) => {
<div style={styles.name}>{institution.name}</div>
<div style={styles.url}>{formatUrl(institution.url)}</div>
</div>
{institution.is_disabled_by_client && (
<Chip color="secondary" label={__('DISABLED')} size="small" sx={styles.chip} />
)}
{!institution.is_disabled_by_client && status === InstitutionStatus.UNAVAILABLE && (
<Chip color="secondary" label={__('UNAVAILABLE')} size="small" sx={styles.chip} />
)}
{statusChip}
</Button>
)
}
Expand Down Expand Up @@ -138,8 +143,6 @@ const getStyles = (tokens) => {
},
chip: {
padding: `${tokens.Spacing.XTiny}px 0`,
background: '#ECECEC',
color: '#494949',
height: tokens.Spacing.Medium,
fontSize: '9px',
},
Expand Down
53 changes: 36 additions & 17 deletions src/components/__tests__/InstitutionTile-test.jsx
Original file line number Diff line number Diff line change
@@ -1,65 +1,84 @@
import React from 'react'
import { render, screen } from 'src/utilities/testingLibrary'
import { act } from 'react'
import { InstitutionTile } from '../InstitutionTile'
import { InstitutionStatusField } from 'src/utilities/institutionStatus'

describe('<InstitutionTile />', () => {
it('renders the logoUrl in the src if there is one', async () => {
it('renders the logoUrl in the src if there is one', () => {
const institution = {
name: 'testName',
logo_url: 'testLogoUrl',
}

await act(async () => {
render(<InstitutionTile institution={institution} selectInstitution={() => {}} />)
})
render(<InstitutionTile institution={institution} selectInstitution={() => {}} />)

expect(screen.getByAltText(`${institution.name} logo`)).toHaveAttribute(
'src',
institution.logo_url,
)
})

it('renders a generated url with the guid if there is no logoUrl', async () => {
it('renders a generated url with the guid if there is no logoUrl', () => {
const institution = {
guid: 'testGuid',
name: 'testName',
}

await act(async () => {
render(<InstitutionTile institution={institution} selectInstitution={() => {}} />)
})
render(<InstitutionTile institution={institution} selectInstitution={() => {}} />)

expect(screen.getByAltText(`${institution.name} logo`).src.includes(institution.guid)).toBe(
true,
)
})

it('renders a disabled Chip if the institution is disabled', async () => {
it('renders a disabled Chip if the institution is disabled', () => {
const institution = {
guid: 'testGuid',
name: 'testName',
is_disabled_by_client: true,
}

await act(async () => {
render(<InstitutionTile institution={institution} selectInstitution={() => {}} />)
})
render(<InstitutionTile institution={institution} selectInstitution={() => {}} />)

expect(screen.getByText('DISABLED')).toBeInTheDocument()
})

it('does not render a disabled Chip if the institution is not disabled', async () => {
it('does not render a disabled Chip if the institution is not disabled', () => {
const institution = {
guid: 'testGuid',
name: 'testName',
is_disabled_by_client: false,
}

await act(async () => {
render(<InstitutionTile institution={institution} selectInstitution={() => {}} />)
})
render(<InstitutionTile institution={institution} selectInstitution={() => {}} />)

expect(screen.queryByText('DISABLED')).not.toBeInTheDocument()
})

it('renders an UNAVAILABLE Chip if the institution is unavailable by experiment values', () => {
const institution = { guid: 'testGuid', name: 'testName' }
const preloadedState = {
experimentalFeatures: {
unavailableInstitutions: [institution],
},
}

render(<InstitutionTile institution={institution} selectInstitution={() => {}} />, {
preloadedState,
})

expect(screen.getByText('UNAVAILABLE')).toBeInTheDocument()
})

it('renders an UNAVAILABLE Chip if the institution is unavailable by API', () => {
const institution = {
guid: 'testGuid',
name: 'testName',
status: InstitutionStatusField.UNAVAILABLE,
}

render(<InstitutionTile institution={institution} selectInstitution={() => {}} />)

expect(screen.getByText('UNAVAILABLE')).toBeInTheDocument()
})
})
23 changes: 20 additions & 3 deletions src/const/language/es.po
Original file line number Diff line number Diff line change
Expand Up @@ -1881,7 +1881,6 @@ msgstr ""
msgid "Log in again"
msgstr "Inicie sesión nuevamente"

#: src/views/institutionStatusDetails/InstitutionStatusDetails.tsx
#: src/views/actionableError/useActionableErrorMap.tsx
msgid "Connect a different institution"
msgstr "Conecte una institución diferente"
Expand Down Expand Up @@ -2071,7 +2070,25 @@ msgid "Demo mode active"
msgstr "Modo de demostración activo"

#: src/views/demoConnectGuard/DemoConnectGuard.tsx
msgid "Live institutions are not available in the demo environment. Please select "
msgid ""
"Live institutions are not available in the demo environment. Please select "
"*MX Bank* to test the connection process."
msgstr "Las instituciones en vivo no están disponibles en el entorno de "
msgstr ""
"Las instituciones en vivo no están disponibles en el entorno de "
"demostración. Seleccione *MX Bank* para probar el proceso de conexión."

#: src/utilities/institutionStatus.ts
msgid "Connection unavailable"
msgstr "Conexión no disponible"

#: src/utilities/institutionStatus.ts
msgid ""
"This institution is experiencing issues that prevent successful "
"connections. It's unclear when this will be resolved."
msgstr ""
"Esta institución está experimentando problemas que impiden establecer "
"conexiones exitosas. No está claro cuándo se resolverá esta situación."

#: src/views/institutionStatusDetails/InstitutionStatusDetails.tsx
msgid "Back"
msgstr "Retroceder"
23 changes: 20 additions & 3 deletions src/const/language/frCa.po
Original file line number Diff line number Diff line change
Expand Up @@ -1957,7 +1957,6 @@ msgstr ""
msgid "Log in again"
msgstr "Connectez-vous à nouveau"

#: src/views/institutionStatusDetails/InstitutionStatusDetails.tsx
#: src/views/actionableError/useActionableErrorMap.tsx
msgid "Connect a different institution"
msgstr "Mettre en relation un autre établissement"
Expand Down Expand Up @@ -2149,8 +2148,26 @@ msgid "Demo mode active"
msgstr "Mode démo actif"

#: src/views/demoConnectGuard/DemoConnectGuard.tsx
msgid "Live institutions are not available in the demo environment. Please select "
msgid ""
"Live institutions are not available in the demo environment. Please select "
"*MX Bank* to test the connection process."
msgstr "Les établissements réels ne sont pas disponibles dans l'environnement de "
msgstr ""
"Les établissements réels ne sont pas disponibles dans l'environnement de "
"démonstration. Veuillez sélectionner *MX Bank* pour tester la procédure de "
"connexion."

#: src/utilities/institutionStatus.ts
msgid "Connection unavailable"
msgstr "Connexion indisponible"

#: src/utilities/institutionStatus.ts
msgid ""
"This institution is experiencing issues that prevent successful "
"connections. It's unclear when this will be resolved."
msgstr ""
"Cet établissement rencontre des problèmes qui empêchent d'établir des "
"connexions. Il est difficile de déterminer quand la situation sera résolue."

#: src/views/institutionStatusDetails/InstitutionStatusDetails.tsx
msgid "Back"
msgstr "Reculer"
28 changes: 27 additions & 1 deletion src/hooks/__tests__/useLoadConnect-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { apiValue } from 'src/const/apiProviderMock'
import { ConfigError } from 'src/components/ConfigError'
import { COMBO_JOB_DATA_TYPES } from 'src/const/comboJobDataTypes'
import { loadExperimentalFeatures } from 'src/redux/reducers/experimentalFeaturesSlice'
import { InstitutionStatusField } from 'src/utilities/institutionStatus'

const TestLoadConnectComponent: React.FC<{
clientConfig: ClientConfigType
Expand Down Expand Up @@ -309,7 +310,7 @@ describe('useLoadConnect', () => {
).toBeInTheDocument()
})

it('will return the INSTITUTION_STATUS_DETAILS step if the state contains a configured unavailable institution', async () => {
it('will return the INSTITUTION_STATUS_DETAILS step if the state contains a configured unavailable institution, via the experimental props', async () => {
const mockApi = {
...apiValue,
loadInstitutionByGuid: vi.fn().mockResolvedValue(
Expand Down Expand Up @@ -337,4 +338,29 @@ describe('useLoadConnect', () => {
)
expect(await screen.findByText(/Institution status details/i)).toBeInTheDocument()
})

it('will return the INSTITUTION_STATUS_DETAILS step if the state contains a configured unavailable institution, via the api', async () => {
const mockApi = {
...apiValue,
loadInstitutionByGuid: vi.fn().mockResolvedValue(
Promise.resolve({
...institutionData.institution,
guid: 'INS-unavailable',
name: 'Unavailable Bank',
status: InstitutionStatusField.UNAVAILABLE, // This status triggers the UNAVAILABLE_PER_MX status
}),
),
}
render(
<ApiProvider apiValue={mockApi}>
<TestLoadConnectComponent
clientConfig={{
...initialState.config,
current_institution_guid: 'INS-unavailable',
}}
/>
</ApiProvider>,
)
expect(await screen.findByText(/Institution status details/i)).toBeInTheDocument()
})
})
14 changes: 7 additions & 7 deletions src/redux/reducers/Connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ import {
institutionIsBlockedForCostReasons,
memberIsBlockedForCostReasons,
} from 'src/utilities/institutionBlocks'
import { InstitutionStatus } from 'src/utilities/institutionStatus'
import {
getInstitutionStatus,
institutionStatusIsUnavailable,
} from 'src/utilities/institutionStatus'

export const defaultState = {
error: null, // The most recent job request error, if any
Expand Down Expand Up @@ -290,7 +293,7 @@ const selectInstitutionSuccess = (state, action) => {
if (
action.payload.institution &&
(institutionIsBlockedForCostReasons(action.payload.institution) ||
action.payload.institutionStatus === InstitutionStatus.UNAVAILABLE)
institutionStatusIsUnavailable(action.payload.institutionStatus))
) {
nextStep = STEPS.INSTITUTION_STATUS_DETAILS
} else if (action.payload.user?.is_demo && !action.payload.institution?.is_demo) {
Expand Down Expand Up @@ -544,11 +547,8 @@ function getStartingStep(
// Unavailable institutions experimental feature: Make sure we don't load a user
// directly to an institution that should be unavailable.
const unavailableInstitutions = experimentalFeatures?.unavailableInstitutions || []
const institutionIsAvailable =
institution &&
unavailableInstitutions.find(
(ins) => ins.guid === institution?.guid || ins.name === institution?.name,
) === undefined
const institutionStatus = getInstitutionStatus(institution, unavailableInstitutions)
const institutionIsAvailable = institution && !institutionStatusIsUnavailable(institutionStatus)

const shouldStepToMFA =
member && config.update_credentials && member.connection_status === ReadableStatuses.CHALLENGED
Expand Down
Loading
Loading