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
35 changes: 21 additions & 14 deletions docs/APIDOCUMENTATION.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/components/RenderConnectStep.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,8 @@ const RenderConnectStep = (props) => {
)
} else if (step === STEPS.ACTIONABLE_ERROR) {
// We are slowly adding codes and statuses to use ActionableError instead of LoginError.
const jobDetailCode = currentMember?.most_recent_job_detail_code ?? null
connectStepView = canHandleActionableError(jobDetailCode) ? (
const errorCode = currentMember?.error?.error_code ?? null
connectStepView = canHandleActionableError(errorCode) ? (
<ActionableError />
) : (
<LoginError
Expand Down
1 change: 0 additions & 1 deletion src/const/language/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,6 @@
"Log in again": "Inicie sesión nuevamente",
"Connect a different institution": "Conecte una institución diferente",
"No eligible accounts": "No hay cuentas elegibles",
"Only checking or savings accounts can be used for transfers. If you have one at %1, make sure to select it when connecting. Otherwise, try connecting a different institution.": "Solo se pueden usar cuentas de control o ahorro para transferencias. Si tiene uno en %1, asegúrese de seleccionarlo al conectarlo. De lo contrario, intente conectar una institución diferente.",
"Required": "Requerido",
"Add financial management?": "¿Añadir gestión financiera?",
"Yes, add financial management": "Sí, añadir gestión financiera",
Expand Down
10 changes: 0 additions & 10 deletions src/const/language/es.po
Original file line number Diff line number Diff line change
Expand Up @@ -1964,16 +1964,6 @@ msgstr "Conecte una institución diferente"
msgid "No eligible accounts"
msgstr "No hay cuentas elegibles"

#: src/views/actionableError/ActionableError.tsx
msgid ""
"Only checking or savings accounts can be used for transfers. If you have one "
"at %1, make sure to select it when connecting. Otherwise, try connecting a "
"different institution."
msgstr ""
"Solo se pueden usar cuentas de control o ahorro para transferencias. Si "
"tiene uno en %1, asegúrese de seleccionarlo al conectarlo. De lo contrario, "
"intente conectar una institución diferente."

#: src/components/DeleteMemberSurvey.js src/components/RequiredFieldNote.tsx
#: src/views/mfa/MFAOptions.js
msgid "Required"
Expand Down
2 changes: 0 additions & 2 deletions src/const/language/frCa.json
Original file line number Diff line number Diff line change
Expand Up @@ -395,11 +395,9 @@
"Log in again": "Connectez-vous à nouveau",
"Connect a different institution": "Mettre en relation un autre établissement",
"No eligible accounts": "Aucun compte admissible",
"Only checking or savings accounts can be used for transfers. If you have one at %1, make sure to select it when connecting. Otherwise, try connecting a different institution.": "Seuls les comptes chèques ou d’épargne peuvent être utilisés pour les transferts. Si vous en avez un à %1, assurez-vous de le sélectionner lors de la connexion. Sinon, essayez de connecter une autre institution.",
"Required": "Requis",
"Add financial management?": "Ajouter la gestion financière ?",
"Yes, add financial management": "Oui, ajoutez la gestion financière",
"No, just transfers and payment": "Non, juste des virements et des paiements",
"Add transfers and payments?": "Ajouter des transferts et des paiements ?",
"Yes, add transfers and payments": "Oui, ajouter des transferts et des paiements",
"Select an account to connect": "Sélectionnez un compte pour vous connecter",
Expand Down
13 changes: 0 additions & 13 deletions src/const/language/frCa.po
Original file line number Diff line number Diff line change
Expand Up @@ -2040,16 +2040,6 @@ msgstr "Mettre en relation un autre établissement"
msgid "No eligible accounts"
msgstr "Aucun compte admissible"

#: src/views/actionableError/ActionableError.tsx
msgid ""
"Only checking or savings accounts can be used for transfers. If you have one "
"at %1, make sure to select it when connecting. Otherwise, try connecting a "
"different institution."
msgstr ""
"Seuls les comptes chèques ou d’épargne peuvent être utilisés pour les "
"transferts. Si vous en avez un à %1, assurez-vous de le sélectionner lors de "
"la connexion. Sinon, essayez de connecter une autre institution."

#: src/components/DeleteMemberSurvey.js src/components/RequiredFieldNote.tsx
#: src/views/mfa/MFAOptions.js
msgid "Required"
Expand All @@ -2063,9 +2053,6 @@ msgstr "Ajouter la gestion financière ?"
msgid "Yes, add financial management"
msgstr "Oui, ajoutez la gestion financière"

msgid "No, just transfers and payment"
msgstr "Non, juste des virements et des paiements"

#: src/views/additionalProduct/AdditionalProductStep.tsx
msgid "Add transfers and payments?"
msgstr "Ajouter des transferts et des paiements ?"
Expand Down
4 changes: 2 additions & 2 deletions src/context/ApiContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export type ApiContextTypes = {
) => Promise<{ member: MemberResponseType }>
deleteMember: (member: MemberDeleteType) => Promise<void>
getMemberCredentials: (memberGuid: string) => Promise<CredentialResponseType[]>
loadMemberByGuid?: (guid: string) => Promise<MemberResponseType>
loadMembers: () => Promise<MemberResponseType[]>
loadMemberByGuid?: (guid: string, clientLocale?: string) => Promise<MemberResponseType>
loadMembers: (clientLocale?: string) => Promise<MemberResponseType[]>
updateMember: (
member: object,
config: ClientConfigType,
Expand Down
19 changes: 13 additions & 6 deletions src/hooks/useLoadConnect.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { useEffect, useState, useCallback } from 'react'
import { useEffect, useState, useCallback, useMemo } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { from, of, defer } from 'rxjs'
import { catchError, mergeMap, map } from 'rxjs/operators'
Expand Down Expand Up @@ -47,6 +47,9 @@ export const getErrorResource = (err: { config: { url: string | string[] } }) =>
const useLoadConnect = () => {
const { api } = useApi()
const profiles = useSelector((state: RootState) => state.profiles)
const clientLocale = useMemo(() => {
return document.querySelector('html')?.getAttribute('lang') || 'en'
}, [document.querySelector('html')?.getAttribute('lang')])
const [config, setConfig] = useState<ClientConfigType>({} as ClientConfigType)
const dispatch = useDispatch()

Expand All @@ -58,7 +61,7 @@ const useLoadConnect = () => {

let request$
if (config.current_member_guid) {
request$ = loadConnectFromMemberConfig(config, api)
request$ = loadConnectFromMemberConfig(config, api, clientLocale)
} else if (config.current_institution_guid || config.current_institution_code) {
request$ = loadConnectFromInstitutionConfig(config, api)
} else if (config.mode === VERIFY_MODE && config.current_microdeposit_guid) {
Expand All @@ -71,8 +74,8 @@ const useLoadConnect = () => {
.pipe(
mergeMap((dependencies) => {
if (clientSupportRequestedProducts(config, profiles.clientProfile)) {
return from(api.loadMembers()).pipe(
map((members) =>
return from(api.loadMembers(clientLocale)).pipe(
map((members = []) =>
loadConnectSuccess({
members,
widgetProfile: profiles.widgetProfile,
Expand Down Expand Up @@ -139,8 +142,12 @@ export default useLoadConnect
* Load the data for the configured member. Dispatch an error if
* member's institution does not support the requested products
*/
function loadConnectFromMemberConfig(config: ClientConfigType, api: ApiContextTypes) {
return from(api.loadMemberByGuid!(config.current_member_guid as string)).pipe(
function loadConnectFromMemberConfig(
config: ClientConfigType,
api: ApiContextTypes,
clientLocale: string,
) {
return from(api.loadMemberByGuid!(config.current_member_guid as string, clientLocale)).pipe(
mergeMap((member: any) => {
return defer(() => api.loadInstitutionByGuid(member.institution_guid)).pipe(
map((institution) => {
Expand Down
5 changes: 2 additions & 3 deletions src/redux/reducers/Connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const loadConnect = (state, { payload }) => {

const loadConnectSuccess = (state, action) => {
const {
members,
members = [],
member,
microdeposit,
config = {},
Expand Down Expand Up @@ -518,8 +518,7 @@ function getStepFromMember(member) {
const connection_status = member.connection_status

if (
(member?.most_recent_job_detail_code &&
canHandleActionableError(member?.most_recent_job_detail_code)) ||
(member?.error?.error_code && canHandleActionableError(member?.error?.error_code)) ||
hasNoSingleAccountSelectOptions(member)
)
// They configured connect with a member in error or missing SAS options.
Expand Down
8 changes: 7 additions & 1 deletion src/redux/reducers/__tests__/Connect-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -408,9 +408,15 @@ describe('Connect redux store', () => {
const config = { mode: VERIFY_MODE, current_member_guid: 'MBR-1' }
const member = {
connection_status: ReadableStatuses.CONNECTED,
error: {
error_code: 1000,
error_message: 'Test',
error_type: 'MEMBER',
locale: 'en',
user_message: 'Test',
},
is_oauth: false,
guid: 'MBR-1',
most_recent_job_detail_code: 1000,
}
const members = [member]
const afterState = reducer(
Expand Down
1 change: 1 addition & 0 deletions src/services/mockedData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export const member = {
member: {
aggregation_status: 0,
connection_status: 0,
error: null,
guid: 'MBR-123',
institution_guid: 'INS-123',
institution_name: null,
Expand Down
4 changes: 2 additions & 2 deletions src/utilities/pollers.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ export const DEFAULT_POLLING_STATE = {
userMessage: CONNECTING_MESSAGES.STARTING, // message to show the end user
}

export function pollMember(memberGuid, api, onPostMessage, sendPosthogEvent) {
export function pollMember(memberGuid, api, onPostMessage, sendPosthogEvent, clientLocale) {
return interval(3000).pipe(
switchMap(() =>
// Poll the currentMember. Catch errors but don't handle it here
// the scan will handle it below
defer(() => api.loadMemberByGuid(memberGuid)).pipe(
defer(() => api.loadMemberByGuid(memberGuid, clientLocale)).pipe(
mergeMap((member) =>
defer(() => api.loadJob(member.most_recent_job_guid)).pipe(
map((job) => {
Expand Down
9 changes: 2 additions & 7 deletions src/views/actionableError/ActionableError.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const ActionableError = () => {
const institution = useSelector((state: RootState) => state.connect.selectedInstitution)
const currentMember = useSelector(getCurrentMember)
const initialConfig = useSelector(selectInitialConfig)
const jobDetailCode = currentMember.most_recent_job_detail_code
const jobDetailCode = currentMember.error.error_code
const tokens = useTokens()
const styles = getStyles(tokens)
const getNextDelay = getDelay()
Expand All @@ -30,11 +30,6 @@ export const ActionableError = () => {
() => ({
[ACTIONABLE_ERROR_CODES.NO_ELIGIBLE_ACCOUNTS]: {
title: __('No eligible accounts'),
userMessage: (institution: InstitutionResponseType) =>
__(
'Only checking or savings accounts can be used for transfers. If you have one at %1, make sure to select it when connecting. Otherwise, try connecting a different institution.',
institution.name,
),
primaryAction: {
label: __('Log in again'),
action: () => dispatch({ type: ActionTypes.ACTIONABLE_ERROR_LOG_IN_AGAIN }),
Expand Down Expand Up @@ -95,7 +90,7 @@ export const ActionableError = () => {
truncate={false}
variant="Paragraph"
>
{messagingMap[jobDetailCode].userMessage(institution)}
{currentMember.error.user_message}
</Text>
</SlideDown>

Expand Down
14 changes: 10 additions & 4 deletions src/views/actionableError/__tests__/ActionableError-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { render, screen } from 'src/utilities/testingLibrary'
import { ActionableError } from 'src/views/actionableError/ActionableError'
import { initialState as defaultState } from 'src/services/mockedData'
import { STEPS } from 'src/const/Connect'
import { ACTIONABLE_ERROR_CODES } from '../consts'

const institutionMock = {
name: 'Institution',
Expand All @@ -13,13 +12,20 @@ const institutionMock = {
const membersMock = [
{
guid: 'MEM-123',
error: {
error_code: 1000,
error_message: 'This Member has no eligible checking, savings, or money market accounts.',
error_type: 'MEMBER',
locale: 'en',
user_message:
"We couldn't find any accounts eligible for transfers. Please link a checking or savings account.",
},
name: 'Member',
most_recent_job_detail_code: ACTIONABLE_ERROR_CODES.NO_ELIGIBLE_ACCOUNTS,
},
{
guid: 'MEM-456',
error: null,
name: 'Member',
most_recent_job_detail_code: null,
},
]

Expand Down Expand Up @@ -54,7 +60,7 @@ describe('ActionableError', () => {
expect(screen.getByText('No eligible accounts')).toBeInTheDocument()
expect(
screen.getByText(
`Only checking or savings accounts can be used for transfers. If you have one at ${institutionMock.name}, make sure to select it when connecting. Otherwise, try connecting a different institution.`,
"We couldn't find any accounts eligible for transfers. Please link a checking or savings account.",
),
).toBeInTheDocument()
})
Expand Down
10 changes: 6 additions & 4 deletions src/views/connecting/Connecting.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState, useRef, useContext } from 'react'
import React, { useEffect, useState, useRef, useContext, useMemo } from 'react'
import PropTypes from 'prop-types'
import { defer, of } from 'rxjs'
import {
Expand Down Expand Up @@ -60,7 +60,9 @@ export const Connecting = (props) => {

const selectedInstitution = useSelector(getSelectedInstitution)
const sendPosthogEvent = useAnalyticsEvent()

const clientLocale = useMemo(() => {
return document.querySelector('html')?.getAttribute('lang') || 'en'
}, [document.querySelector('html')?.getAttribute('lang')])
const currentMember = useSelector(getCurrentMember)
const isComboJobsEnabled = useSelector(isConnectComboJobsEnabled)
const jobSchedule = useSelector((state) => state.connect.jobSchedule)
Expand Down Expand Up @@ -245,7 +247,7 @@ export const Connecting = (props) => {
const startJob$ = defer(() =>
api.runJob(activeJob?.type, currentMember.guid, connectConfig, true),
).pipe(
mergeMap(() => api.loadMemberByGuid(currentMember.guid)),
mergeMap(() => api.loadMemberByGuid(currentMember.guid, clientLocale)),

catchError((error) => {
// We control the scenarios of a 409 error (job already running, or member already exists).
Expand All @@ -268,7 +270,7 @@ export const Connecting = (props) => {
})
.pipe(
concatMap((member) =>
pollMember(member.guid, api, onPostMessage, sendPosthogEvent).pipe(
pollMember(member.guid, api, onPostMessage, sendPosthogEvent, clientLocale).pipe(
tap((pollingState) => handleMemberPoll(pollingState)),
filter((pollingState) => pollingState.jobIsDone),
pluck('currentResponse'),
Expand Down
7 changes: 5 additions & 2 deletions src/views/credentials/CreateMemberForm.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState, useContext } from 'react'
import React, { useEffect, useState, useContext, useMemo } from 'react'
import PropTypes from 'prop-types'
import { defer, of } from 'rxjs'
import { catchError, delay, map, mergeMap } from 'rxjs/operators'
Expand Down Expand Up @@ -32,6 +32,9 @@ export const CreateMemberForm = (props) => {
const config = useSelector(selectConfig)
const isHuman = useSelector((state) => state.app.humanEvent)
const currentMembers = useSelector((state) => state.connect.members)
const clientLocale = useMemo(() => {
return document.querySelector('html')?.getAttribute('lang') || 'en'
}, [document.querySelector('html')?.getAttribute('lang')])

const [isCreatingMember, setIsCreatingMember] = useState(false)
const [memberCreateError, setMemberCreateError] = useState(null)
Expand Down Expand Up @@ -127,7 +130,7 @@ export const CreateMemberForm = (props) => {
}
}),
)
return defer(() => api.loadMemberByGuid(memberGuid)).pipe(
return defer(() => api.loadMemberByGuid(memberGuid, clientLocale)).pipe(
mergeMap((member) => {
const shouldStepToMFA = member.connection_status === ReadableStatuses.CHALLENGED
return shouldStepToMFA ? stepToMFA$(member) : updateMember$
Expand Down
7 changes: 5 additions & 2 deletions src/views/manualAccount/ManualAccountForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import React, { MutableRefObject, useEffect, useState, useRef } from 'react'
import React, { MutableRefObject, useEffect, useState, useRef, useMemo } from 'react'
import { useSelector, useDispatch } from 'react-redux'

import { from, of, zip, defer } from 'rxjs'
Expand Down Expand Up @@ -51,6 +51,9 @@ export const ManualAccountForm = React.forwardRef<HTMLInputElement, ManualAccoun
useAnalyticsPath(name, path)
const { api } = useApi()
const members = useSelector(getMembers)
const clientLocale = useMemo(() => {
return document.querySelector('html')?.getAttribute('lang') || 'en'
}, [document.querySelector('html')?.getAttribute('lang')])
const [saving, setSaving] = useState(false)
const [isPersonal, setIsPersonal] = useState(true)
const [returnField, setReturnField] = useState<string | null>(null)
Expand Down Expand Up @@ -168,7 +171,7 @@ export const ManualAccountForm = React.forwardRef<HTMLInputElement, ManualAccoun

// Otherwise go get the newly created account's member and institution
return zip(
from(api.loadMemberByGuid!(savedAccount.member_guid)),
from(api.loadMemberByGuid!(savedAccount.member_guid, clientLocale)),
from(api.loadInstitutionByGuid(savedAccount.institution_guid)),
).pipe(
map(([loadedMember, loadedInstitution]) => {
Expand Down
7 changes: 7 additions & 0 deletions typings/apiTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ type MemberDeleteType = {
type MemberResponseType = {
aggregation_status: number
connection_status: number
error?: {
error_code: number
error_message: string
error_type: string
locale: string
user_message: string
}
guid: string
institution_guid: string
institution_name?: string | null
Expand Down
7 changes: 7 additions & 0 deletions typings/mxTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ type MemberDeleteType = {
type MemberResponseType = {
aggregation_status: number
connection_status: number
error?: {
error_code: number
error_message: string
error_type: string
locale: string
user_message: string
}
guid: string
institution_guid: string
institution_name?: string | null
Expand Down
Loading