From 200ea9c4d547ac6ed645ab78f275b8a20c03af42 Mon Sep 17 00:00:00 2001 From: Jameson Date: Tue, 19 May 2026 08:31:45 -0600 Subject: [PATCH] feat: add CONNECT_RUX feature and related authentication methods --- docs/APIDOCUMENTATION.md | 42 +++++++++++++++++++ docs/USER_FEATURES.md | 1 + src/const/Connect.js | 1 + src/const/UserFeatures.js | 1 + src/hooks/useLoadConnect.tsx | 3 ++ .../__tests__/userFeaturesSlice-test.js | 25 +++++++++++ src/redux/reducers/userFeaturesSlice.ts | 6 ++- 7 files changed, 78 insertions(+), 1 deletion(-) diff --git a/docs/APIDOCUMENTATION.md b/docs/APIDOCUMENTATION.md index 50a10cf11f..bf354c120c 100644 --- a/docs/APIDOCUMENTATION.md +++ b/docs/APIDOCUMENTATION.md @@ -654,3 +654,45 @@ xee --- + +#### authPersonInitiate(phoneNumber) + +
+ Initiates authentication for a person + +##### Parameters + +> | name | type | data type | description | +> | ------------- | -------- | --------- | ---------------------------------------------- | +> | `phoneNumber` | required | string | The phone number of the person to authenticate | + +##### Responses + +> | http code | content-type | response | +> | --------- | ------------------ | ------------------------------- | +> | `200` | `application/json` | `TBD` | +> | `40#` | `application/json` | `{"response": {"status": 40#}}` | + +
+ +--- + +#### authPersonVerify(code) + +
+ Verifies authentication for a person + +##### Parameters + +> | name | type | data type | description | +> | ------ | -------- | --------- | ----------------------------------------------------- | +> | `code` | required | string | The verification code sent to the user's phone number | + +##### Responses + +> | http code | content-type | response | +> | --------- | ------------------ | ------------------------------- | +> | `200` | `application/json` | `TBD | +> | `40#` | `application/json` | `{"response": {"status": 40#}}` | + +--- diff --git a/docs/USER_FEATURES.md b/docs/USER_FEATURES.md index 649018a58a..01b99e13e2 100644 --- a/docs/USER_FEATURES.md +++ b/docs/USER_FEATURES.md @@ -25,6 +25,7 @@ const userFeatures = [ | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | `SHOW_CONNECT_GLOBAL_NAVIGATION_HEADER` | When enabled, adds a back button to the top of the widget and gets rid of any explicit back buttons |
{
 feature_name: 'SHOW_CONNECT_GLOBAL_NAVIGATION_HEADER',
 guid: 'FTR-123',
 is_enabled: true
 }
| | `CONNECT_COMBO_JOBS` | When enabled, the Connect widget will create COMBINATION jobs instead of individual jobs (aggregate, verification, reward, etc). |
{
 feature_name: 'CONNECT_COMBO_JOBS',
 guid: 'FTR-123',
 is_enabled: true
 }
| +| `CONNECT_RUX` | When enabled, the Connect widget will start by initializing the RUX authentication flow. |
{
 feature_name: 'CONNECT_RUX',
 guid: 'FTR-123',
 is_enabled: true
 }
|

diff --git a/src/const/Connect.js b/src/const/Connect.js index dc73c577e9..50dafe8a45 100644 --- a/src/const/Connect.js +++ b/src/const/Connect.js @@ -19,6 +19,7 @@ export const STEPS = { MFA: 'mfa', MICRODEPOSITS: 'microdeposits', OAUTH_ERROR: 'oauthError', + RETURNING_USER_EXPERIENCE: 'returningUserExperience', SEARCH: 'search', VERIFY_ERROR: 'verifyError', VERIFY_EXISTING_MEMBER: 'verifyExistingMember', diff --git a/src/const/UserFeatures.js b/src/const/UserFeatures.js index 0ab70725f3..e311fd6c6c 100644 --- a/src/const/UserFeatures.js +++ b/src/const/UserFeatures.js @@ -2,3 +2,4 @@ export const CONNECT_COMBO_JOBS = 'CONNECT_COMBO_JOBS' export const CONNECT_CONSENT = 'CONNECT_CONSENT' +export const CONNECT_RUX = 'CONNECT_RUX' diff --git a/src/hooks/useLoadConnect.tsx b/src/hooks/useLoadConnect.tsx index 8bbd416c60..1006d3ee00 100644 --- a/src/hooks/useLoadConnect.tsx +++ b/src/hooks/useLoadConnect.tsx @@ -18,6 +18,7 @@ import { __ } from 'src/utilities/Intl' import type { RootState } from 'src/redux/Store' import { instutionSupportRequestedProducts } from 'src/utilities/Institution' import { getExperimentalFeatures } from 'src/redux/reducers/experimentalFeaturesSlice' +import { isConnectRuxEnabled } from 'src/redux/reducers/userFeaturesSlice' export const getErrorResource = (err: { config: { url: string | string[] } }) => { if (err.config?.url.includes('/institutions')) { @@ -49,6 +50,7 @@ const useLoadConnect = () => { const { api } = useApi() const profiles = useSelector((state: RootState) => state.profiles) const experimentalFeatures = useSelector(getExperimentalFeatures) + const isRuxEnabled = useSelector(isConnectRuxEnabled) const clientLocale = useMemo(() => { return document.querySelector('html')?.getAttribute('lang') || 'en' }, [document.querySelector('html')?.getAttribute('lang')]) @@ -82,6 +84,7 @@ const useLoadConnect = () => { experimentalFeatures, members, widgetProfile: profiles.widgetProfile, + isRuxEnabled, ...dependencies, }), ), diff --git a/src/redux/reducers/__tests__/userFeaturesSlice-test.js b/src/redux/reducers/__tests__/userFeaturesSlice-test.js index 13856a5347..c176e4409e 100644 --- a/src/redux/reducers/__tests__/userFeaturesSlice-test.js +++ b/src/redux/reducers/__tests__/userFeaturesSlice-test.js @@ -2,6 +2,7 @@ import reducer, { loadUserFeatures, initialState, getUserFeatures, + isConnectRuxEnabled, } from 'src/redux/reducers/userFeaturesSlice' import Store from 'src/redux/Store' @@ -28,5 +29,29 @@ describe('UserFeatures slice', () => { expect(getUserFeatures(state)).toEqual(state.userFeatures.items) }) }) + + describe('isConnectRuxEnabled selector', () => { + it('should return true if the CONNECT_RUX feature is enabled', () => { + const userFeatures = [{ feature_name: 'CONNECT_RUX', is_enabled: true }] + const mockState = { + ...state, + userFeatures: { + items: userFeatures, + }, + } + expect(isConnectRuxEnabled(mockState)).toBe(true) + }) + + it('should return false if the CONNECT_RUX feature is not enabled', () => { + const userFeatures = [{ feature_name: 'CONNECT_RUX', is_enabled: false }] + const mockState = { + ...state, + userFeatures: { + items: userFeatures, + }, + } + expect(isConnectRuxEnabled(mockState)).toBe(false) + }) + }) }) }) diff --git a/src/redux/reducers/userFeaturesSlice.ts b/src/redux/reducers/userFeaturesSlice.ts index d7258bdbc8..133aa8ab16 100644 --- a/src/redux/reducers/userFeaturesSlice.ts +++ b/src/redux/reducers/userFeaturesSlice.ts @@ -1,6 +1,6 @@ import { createSlice, createSelector } from '@reduxjs/toolkit' import * as UserFeatures from 'src/utilities/UserFeatures' -import { CONNECT_COMBO_JOBS, CONNECT_CONSENT } from 'src/const/UserFeatures' +import { CONNECT_COMBO_JOBS, CONNECT_CONSENT, CONNECT_RUX } from 'src/const/UserFeatures' import { RootState } from 'src/redux/Store' type UserFeaturesSlice = { @@ -33,6 +33,10 @@ export const isConsentEnabled = createSelector(getUserFeatures, (userFeatures) = return UserFeatures.isFeatureEnabled(userFeatures, CONNECT_CONSENT) }) +export const isConnectRuxEnabled = createSelector(getUserFeatures, (userFeatures) => + UserFeatures.isFeatureEnabled(userFeatures, CONNECT_RUX), +) + export const { loadUserFeatures } = userFeaturesSlice.actions export default userFeaturesSlice.reducer