diff --git a/CHANGELOG.md b/CHANGELOG.md
index e2d06079de..bfe9ee2889 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# Changelog
+## v.0.9.3
+
+### Added
+
+- Adding a UCP specific variable to the connection success event
+
## v.0.9.2
### Added
diff --git a/package.json b/package.json
index aa671e75e0..bf17017cf4 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@mxenabled/connect-widget",
"description": "A simple ui library for React",
- "version": "0.9.2",
+ "version": "0.9.3",
"module": "dist/index.es.js",
"types": "dist/index.d.ts",
"type": "module",
diff --git a/src/components/RenderConnectStep.js b/src/components/RenderConnectStep.js
index de3415e6d6..473048c820 100644
--- a/src/components/RenderConnectStep.js
+++ b/src/components/RenderConnectStep.js
@@ -10,7 +10,7 @@ import { useTokens } from '@kyper/tokenprovider'
import * as connectActions from 'src/redux/actions/Connect'
import { getSize } from 'src/redux/selectors/Browser'
-import { getCurrentMember, getMembers } from 'src/redux/selectors/Connect'
+import { getCurrentMember, getMembers, getSelectedInstitution } from 'src/redux/selectors/Connect'
import {
selectConnectConfig,
selectIsMobileWebView,
@@ -57,7 +57,7 @@ const RenderConnectStep = (props) => {
)
const connectedMembers = useSelector(getMembers)
const currentMember = useSelector(getCurrentMember)
- const selectedInstitution = useSelector((state) => state.connect.selectedInstitution)
+ const selectedInstitution = useSelector(getSelectedInstitution)
const updateCredentials = useSelector((state) => state.connect.updateCredentials)
const verifyMemberError = useSelector((state) => state.connect.error)
diff --git a/src/hooks/__tests__/useSelectInstitution-test.tsx b/src/hooks/__tests__/useSelectInstitution-test.tsx
index 3c4f1bfd7e..a5e7c72056 100644
--- a/src/hooks/__tests__/useSelectInstitution-test.tsx
+++ b/src/hooks/__tests__/useSelectInstitution-test.tsx
@@ -1,12 +1,12 @@
import React from 'react'
import { useSelector } from 'react-redux'
-import type { RootState } from 'src/redux/Store'
import { screen, render } from 'src/utilities/testingLibrary'
import useSelectInstitution from 'src/hooks/useSelectInstitution'
import { institutionData } from 'src/services/mockedData'
+import { getSelectedInstitution } from 'src/redux/selectors/Connect'
const TestSelectInstitutionComponent = () => {
- const selectedInstitution = useSelector((state: RootState) => state.connect.selectedInstitution)
+ const selectedInstitution = useSelector(getSelectedInstitution)
const { handleSelectInstitution } = useSelectInstitution()
return (
diff --git a/src/redux/selectors/Connect.js b/src/redux/selectors/Connect.js
index 0ed27c0a0b..653961a29b 100644
--- a/src/redux/selectors/Connect.js
+++ b/src/redux/selectors/Connect.js
@@ -15,13 +15,34 @@ const getMemberByGuid = (members, guid) => {
/**
* Selectors
*/
+
+const getConnectSlice = createSelector(
+ (state) => state,
+ (state) => state.connect,
+)
+
+const getMembersRaw = createSelector(getConnectSlice, (slice) => slice.members)
+
export const getCurrentMember = createSelector(
- (state) => state.connect.members,
+ getMembersRaw,
(state) => state.connect.currentMemberGuid,
getMemberByGuid,
)
+
export const getMembers = createSelector(
- (state) => state.connect.members,
+ getMembersRaw,
(members) =>
members?.filter((member) => !(member.connection_status === ReadableStatuses.PENDING)) ?? [],
)
+
+export const getSelectedInstitution = createSelector(
+ getConnectSlice,
+ (slice) => slice.selectedInstitution,
+)
+
+export const getSelectedInstitutionUcpInstitutionId = createSelector(
+ getSelectedInstitution,
+ (selectedInstitution) => {
+ return selectedInstitution?.ucpInstitutionId
+ },
+)
diff --git a/src/redux/selectors/__tests__/Connect-test.js b/src/redux/selectors/__tests__/Connect-test.js
index 72f3151bff..182b8def09 100644
--- a/src/redux/selectors/__tests__/Connect-test.js
+++ b/src/redux/selectors/__tests__/Connect-test.js
@@ -1,5 +1,21 @@
-import * as ConnectSelectors from 'src/redux/selectors/Connect'
import { genMember } from 'src/utilities/generators/Members'
+import {
+ getCurrentMember,
+ getMembers,
+ getSelectedInstitution,
+ getSelectedInstitutionUcpInstitutionId,
+} from '../Connect'
+import { ReadableStatuses } from 'src/const/Statuses'
+
+const ucpInstitutionId = 'testUcpInstitutionId'
+
+const stateWithASelectedInstitution = {
+ connect: {
+ selectedInstitution: {
+ ucpInstitutionId,
+ },
+ },
+}
describe('Connect Selectors', () => {
describe('getCurrentMember', () => {
@@ -10,9 +26,52 @@ describe('Connect Selectors', () => {
members: [genMember({ guid: 'MBR-1' }), genMember({ guid: 'MBR-2' })],
},
}
- const currentMember = ConnectSelectors.getCurrentMember(state)
+ const currentMember = getCurrentMember(state)
expect(currentMember.guid).toEqual('MBR-1')
})
})
+
+ describe('getMembers', () => {
+ it("returns an empty array if members doesn't exist", () => {
+ const state = {
+ connect: {},
+ }
+
+ expect(getMembers(state)).toEqual([])
+ })
+
+ it("returns any members that aren't pending", () => {
+ const memberThatIsPending = genMember({
+ connection_status: ReadableStatuses.PENDING,
+ })
+ const memberThatIsntPending = genMember({
+ connection_status: ReadableStatuses.CHALLENGED,
+ })
+
+ const state = {
+ connect: {
+ members: [memberThatIsPending, memberThatIsntPending],
+ },
+ }
+
+ expect(getMembers(state)).toEqual([memberThatIsntPending])
+ })
+ })
+
+ describe('getSelectedInstitution', () => {
+ it('returns the selected institution', () => {
+ expect(getSelectedInstitution(stateWithASelectedInstitution)).toEqual(
+ stateWithASelectedInstitution.connect.selectedInstitution,
+ )
+ })
+ })
+
+ describe('getSelectedInstitutionUcpInstitutionId', () => {
+ it("returns the selected institution's ucpId", () => {
+ expect(getSelectedInstitutionUcpInstitutionId(stateWithASelectedInstitution)).toEqual(
+ ucpInstitutionId,
+ )
+ })
+ })
})
diff --git a/src/views/connecting/Connecting.js b/src/views/connecting/Connecting.js
index 30c67f7809..b084d745ce 100644
--- a/src/views/connecting/Connecting.js
+++ b/src/views/connecting/Connecting.js
@@ -27,7 +27,10 @@ import * as JobSchedule from 'src/utilities/JobSchedule'
import { AriaLive } from 'src/components/AriaLive'
import useAnalyticsPath from 'src/hooks/useAnalyticsPath'
import { useApi } from 'src/context/ApiContext'
-import { getCurrentMember } from 'src/redux/selectors/Connect'
+import {
+ getCurrentMember,
+ getSelectedInstitutionUcpInstitutionId,
+} from 'src/redux/selectors/Connect'
import { isConnectComboJobsEnabled } from 'src/redux/reducers/userFeaturesSlice'
import { ErrorStatuses, ReadableStatuses } from 'src/const/Statuses'
@@ -69,6 +72,9 @@ export const Connecting = (props) => {
const styles = getStyles(tokens)
const getNextDelay = getDelay()
const dispatch = useDispatch()
+
+ const ucpInstitutionId = useSelector(getSelectedInstitutionUcpInstitutionId)
+
const analyticFunctions = useContext(AnalyticContext)
const postMessageFunctions = useContext(PostMessageContext)
const connectingRef = useRef(null)
@@ -125,6 +131,10 @@ export const Connecting = (props) => {
event.aggregator = currentMember.aggregator
}
+ if (ucpInstitutionId) {
+ event.ucpInstitutionId = ucpInstitutionId
+ }
+
postMessageFunctions.onPostMessage(POST_MESSAGES.MEMBER_CONNECTED, event)
analyticFunctions.onAnalyticEvent(`connect_${POST_MESSAGES.MEMBER_CONNECTED}`, {
type: connectConfig.is_mobile_webview ? 'url' : 'message',
diff --git a/src/views/credentials/CreateMemberForm.js b/src/views/credentials/CreateMemberForm.js
index 5e183d704d..a734988ca1 100644
--- a/src/views/credentials/CreateMemberForm.js
+++ b/src/views/credentials/CreateMemberForm.js
@@ -15,6 +15,7 @@ import { LoadingSpinner } from 'src/components/LoadingSpinner'
import { ReadableStatuses } from 'src/const/Statuses'
import { PostMessageContext } from 'src/ConnectWidget'
+import { getSelectedInstitution } from 'src/redux/selectors/Connect'
/**
* Responsibilities:
@@ -23,7 +24,7 @@ import { PostMessageContext } from 'src/ConnectWidget'
* - Performs the CREATE
*/
export const CreateMemberForm = (props) => {
- const institution = useSelector((state) => state.connect.selectedInstitution)
+ const institution = useSelector(getSelectedInstitution)
useAnalyticsPath(...PageviewInfo.CONNECT_CREATE_CREDENTIALS, {
institution_guid: institution.guid,
institution_name: institution.name,
diff --git a/src/views/credentials/Credentials.js b/src/views/credentials/Credentials.js
index 8a40d5f67e..f694010184 100644
--- a/src/views/credentials/Credentials.js
+++ b/src/views/credentials/Credentials.js
@@ -35,7 +35,7 @@ import { InstitutionBlock } from 'src/components/InstitutionBlock'
import { InstructionalText } from 'src/components/InstructionalText'
import { InstructionList } from 'src/components/InstructionList'
import { Support, VIEWS as SUPPORT_VIEWS } from 'src/components/support/Support'
-import { getCurrentMember } from 'src/redux/selectors/Connect'
+import { getCurrentMember, getSelectedInstitution } from 'src/redux/selectors/Connect'
import { buildInitialValues, buildFormSchema } from 'src/views/credentials/utils'
import { CREDENTIAL_FIELD_TYPES } from 'src/views/credentials/consts'
@@ -77,7 +77,7 @@ export const Credentials = React.forwardRef(
// Redux Selectors/Dispatch
const connectConfig = useSelector(selectConnectConfig)
const isSmall = useSelector((state) => state.browser.size) === 'small'
- const institution = useSelector((state) => state.connect.selectedInstitution)
+ const institution = useSelector(getSelectedInstitution)
const showExternalLinkPopup = useSelector(
(state) => state.profiles.clientProfile.show_external_link_popup,
)
diff --git a/src/views/credentials/UpdateMemberForm.js b/src/views/credentials/UpdateMemberForm.js
index f704c7d135..c333faf94e 100644
--- a/src/views/credentials/UpdateMemberForm.js
+++ b/src/views/credentials/UpdateMemberForm.js
@@ -6,7 +6,7 @@ import { useDispatch, useSelector } from 'react-redux'
import { useApi } from 'src/context/ApiContext'
import useAnalyticsPath from 'src/hooks/useAnalyticsPath'
import { PageviewInfo } from 'src/const/Analytics'
-import { getCurrentMember } from 'src/redux/selectors/Connect'
+import { getCurrentMember, getSelectedInstitution } from 'src/redux/selectors/Connect'
import { ActionTypes } from 'src/redux/actions/Connect'
import { selectConfig } from 'src/redux/reducers/configSlice'
@@ -23,7 +23,7 @@ import { PostMessageContext } from 'src/ConnectWidget'
*/
export const UpdateMemberForm = (props) => {
useAnalyticsPath(...PageviewInfo.CONNECT_UPDATE_CREDENTIALS)
- const institution = useSelector((state) => state.connect.selectedInstitution)
+ const institution = useSelector(getSelectedInstitution)
const currentMember = useSelector(getCurrentMember)
const config = useSelector(selectConfig)
const isHuman = useSelector((state) => state.app.humanEvent)
diff --git a/src/views/disclosure/Interstitial.js b/src/views/disclosure/Interstitial.js
index f4d2fc14eb..ac8fc26d27 100644
--- a/src/views/disclosure/Interstitial.js
+++ b/src/views/disclosure/Interstitial.js
@@ -21,6 +21,7 @@ import { ConnectLogoHeader } from 'src/components/ConnectLogoHeader'
import { PrivacyPolicy } from 'src/views/disclosure/PrivacyPolicy'
import { DataRequested } from 'src/views/disclosure/DataRequested'
import { DataAvailable } from 'src/views/disclosure/DataAvailable'
+import { getSelectedInstitution } from 'src/redux/selectors/Connect'
export const VIEWS = {
AVAILABLE_DATA: 'available_data',
@@ -35,7 +36,7 @@ export const DisclosureInterstitial = React.forwardRef((props, interstitialNavRe
const tokens = useTokens()
const styles = getStyles(tokens)
const getNextDelay = getDelay()
- const institution = useSelector((state) => state.connect.selectedInstitution)
+ const institution = useSelector(getSelectedInstitution)
const appName = useSelector((state) => state.profiles.client.oauth_app_name || null)
const [currentView, setCurrentView] = useState(VIEWS.INTERSTITIAL_DISCLOSURE)
diff --git a/src/views/loginError/NoEligibleAccountsError.js b/src/views/loginError/NoEligibleAccountsError.js
index e43c5471ae..41ba4e7617 100644
--- a/src/views/loginError/NoEligibleAccountsError.js
+++ b/src/views/loginError/NoEligibleAccountsError.js
@@ -9,7 +9,7 @@ import { Button } from '@mui/material'
import { __ } from 'src/utilities/Intl'
import { ActionTypes } from 'src/redux/actions/Connect'
-import { getCurrentMember } from 'src/redux/selectors/Connect'
+import { getCurrentMember, getSelectedInstitution } from 'src/redux/selectors/Connect'
import { AriaLive } from 'src/components/AriaLive'
import { SlideDown } from 'src/components/SlideDown'
@@ -27,7 +27,7 @@ export const NoEligibleAccounts = () => {
const dispatch = useDispatch()
const currentMember = useSelector(getCurrentMember)
- const selectedInstitution = useSelector((state) => state.connect.selectedInstitution)
+ const selectedInstitution = useSelector(getSelectedInstitution)
const postHogEventMetadata = {
authentication_method: currentMember.is_oauth
diff --git a/src/views/oauth/OAuthError.js b/src/views/oauth/OAuthError.js
index b6dde6c853..2c2b36d7a6 100644
--- a/src/views/oauth/OAuthError.js
+++ b/src/views/oauth/OAuthError.js
@@ -15,6 +15,7 @@ import { InstitutionBlock } from 'src/components/InstitutionBlock'
import { SlideDown } from 'src/components/SlideDown'
import { getDelay } from 'src/utilities/getDelay'
import { PostMessageContext } from 'src/ConnectWidget'
+import { getSelectedInstitution } from 'src/redux/selectors/Connect'
export const OAuthError = React.forwardRef((props, navigationRef) => {
useAnalyticsPath(...PageviewInfo.CONNECT_OAUTH_ERROR)
@@ -22,7 +23,7 @@ export const OAuthError = React.forwardRef((props, navigationRef) => {
const postMessageFunctions = useContext(PostMessageContext)
const errorReason = useSelector((state) => state.connect.oauthErrorReason)
- const selectedInstitution = useSelector((state) => state.connect.selectedInstitution)
+ const selectedInstitution = useSelector(getSelectedInstitution)
const tokens = useTokens()
const styles = getStyles(tokens)
const getNextDelay = getDelay()