Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
59fe616
feat: set up redux store
andlar Jul 29, 2026
c930ea5
refactor: use "user" from redux store in a few places
andlar Jul 30, 2026
0311fd8
Merge branch 'staging' into OCD-5392
andlar Aug 3, 2026
7cd7536
Merge branch 'staging' into OCD-5392
andlar Aug 4, 2026
ec3de94
refactor: add login state to redux store
andlar Aug 4, 2026
fce7251
feat: read "loginstate" from redux
andlar Aug 4, 2026
bc4a0e1
feat: save store in localStorage
andlar Aug 7, 2026
96026ba
fix: try to handle long term logout
andlar Aug 10, 2026
8792b0a
refactor: use redux in place of context for user in listing screen
andlar Aug 10, 2026
901690b
refactor: use redux "user" in a variety of places
andlar Aug 10, 2026
7cf0162
refactor: remove unused class definitions
andlar Aug 12, 2026
67fc3de
refactor: set up browser info to be in redux store
andlar Aug 12, 2026
c47f85b
refactor: set up for using redux for browser context
andlar Aug 12, 2026
091a654
refactor: start putting api-key in store
andlar Aug 13, 2026
fbfe9a2
refactor: use store for api-key
andlar Aug 17, 2026
77edc84
refactor: remove OBE constants file
andlar Aug 17, 2026
955eff1
build: read API_KEY from environment variable
andlar Aug 18, 2026
11a1bb9
Merge branch 'staging' into OCD-5392
andlar Aug 18, 2026
7539065
Merge branch 'staging' into OCD-5392
andlar Aug 19, 2026
884b068
fix: revert attempt to save redux state in localstorage
andlar Aug 19, 2026
cb65eca
Merge branch 'staging' into OCD-5392
andlar Aug 20, 2026
26cb63a
Merge branch 'staging' into OCD-5392
andlar Aug 20, 2026
158a664
fix: display orgs correctly for role-developer users
andlar Aug 24, 2026
dab972c
fix: restore functionality for previously compared/viewed search
andlar Aug 24, 2026
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
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@material-ui/core": "^4.12.4",
"@material-ui/icons": "^4.11.3",
"@material-ui/lab": "^4.0.0-alpha.61",
"@reduxjs/toolkit": "^2.12.0",
"@tanstack/react-query": "4.42.0",
"@tanstack/react-query-devtools": "4.42.0",
"@uirouter/react": "^1.0.8",
Expand Down Expand Up @@ -55,6 +56,7 @@
"react-dom": "^18.3.1",
"react-error-boundary": "^6.0.0",
"react-moment": "^1.1.3",
"react-redux": "^9.3.0",
"sass": "^1.62.1",
"swagger-ui-react": "^4.1.3",
"yup": "^0.32.11",
Expand Down
19 changes: 12 additions & 7 deletions src/app/api/axios.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import React, { createContext, useContext, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Axios from 'axios';
import { applyAuthTokenInterceptor, getAccessToken } from 'axios-jwt';
import { applyAuthTokenInterceptor, clearAuthTokens, getAccessToken } from 'axios-jwt';
import { element } from 'prop-types';
import { useSnackbar } from 'notistack';

import { setLoginState, setUser } from 'components/login/userInfo.slice';
import { getAngularService } from 'services/angular-react-helper';
import { UserContext } from 'shared/contexts';

const AxiosContext = createContext();

function AxiosProvider({ children }) {
const apiKey = useSelector((state) => state.browserInfo.apiKey);
const dispatch = useDispatch();
const authService = getAngularService('authService');
const { enqueueSnackbar } = useSnackbar();
const { setLoginWidgetState } = useContext(UserContext);

const axios = useMemo(() => {
const ax = Axios.create({
Expand All @@ -25,14 +27,17 @@ function AxiosProvider({ children }) {
const requestRefresh = (refreshToken) => {
const { cognitoId } = JSON.parse(localStorage.getItem('ngStorage-currentUser'));
const headers = {
'API-Key': '12909a978483dfb8ecd0596c98ae9094',
'API-Key': apiKey,
};
if (cognitoId) {
// Notice that this is the global axios instance, not the axiosInstance! <-- important
return Axios.post('rest/auth/refresh-token', { refreshToken, cognitoId }, { headers })
.then((response) => response.data.accessToken)
.catch(() => {
setLoginWidgetState('SIGNIN');
dispatch(setLoginState('SIGNIN'));
dispatch(setUser({}));
clearAuthTokens();
localStorage.removeItem('ngStorage-currentUser');
authService.logout();
});
}
Expand All @@ -46,7 +51,7 @@ function AxiosProvider({ children }) {
const updated = {
...config,
};
updated.headers['API-Key'] = '12909a978483dfb8ecd0596c98ae9094';
updated.headers['API-Key'] = apiKey;
let accessToken = '';
accessToken = await getAccessToken();
if (accessToken) {
Expand Down Expand Up @@ -77,7 +82,7 @@ function AxiosProvider({ children }) {
},
(error) => {
if (error?.response?.data === 'Invalid authentication token.' && authService.hasAnyRole(['chpl-admin', 'chpl-onc', 'chpl-onc-acb', 'chpl-cms-staff', 'chpl-developer'])) {
setLoginWidgetState('SIGNIN');
dispatch(setLoginState('SIGNIN'));
authService.logout();
}
return Promise.reject(error);
Expand Down
73 changes: 39 additions & 34 deletions src/app/app-wrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import {
ThemeProvider,
makeStyles,
} from '@material-ui/core';
import { bool, node } from 'prop-types';
import { CookiesProvider } from 'react-cookie';
import { Provider } from 'react-redux';
import { bool, node } from 'prop-types';

import store from './store';

import { AnalyticsProvider, HashProvider } from 'shared/contexts';
import ApiWrapper from 'api/api-wrapper';
Expand Down Expand Up @@ -38,40 +41,42 @@ const useStyles = makeStyles({
function AppWrapper({ children, showQueryTools = DEVELOPER_MODE }) {
const classes = useStyles();
return (
<ThemeProvider theme={theme}>
<SnackbarWrapper>
<ApiWrapper showQueryTools={showQueryTools}>
<UserWrapper>
<FlagWrapper>
<CompareWrapper>
<CmsWrapper>
<BrowserWrapper>
<AnalyticsProvider>
<HashProvider>
<CookiesProvider defaultSetOptions={{
path: '/',
expires: new Date(Date.now() + (1000 * 60 * 60 * 10)), // 10 hours
domain: '.healthit.gov',
}}
>
<div className={classes.appContainer}>
<ChplNavigationTop />
<div className={classes.content}>
{children}
<Provider store={store}>
<ThemeProvider theme={theme}>
<SnackbarWrapper>
<ApiWrapper showQueryTools={showQueryTools}>
<UserWrapper>
<FlagWrapper>
<CompareWrapper>
<CmsWrapper>
<BrowserWrapper>
<AnalyticsProvider>
<HashProvider>
<CookiesProvider defaultSetOptions={{
path: '/',
expires: new Date(Date.now() + (1000 * 60 * 60 * 10)), // 10 hours
domain: '.healthit.gov',
}}
>
<div className={classes.appContainer}>
<ChplNavigationTop />
<div className={classes.content}>
{children}
</div>
<ChplNavigationBottom />
</div>
<ChplNavigationBottom />
</div>
</CookiesProvider>
</HashProvider>
</AnalyticsProvider>
</BrowserWrapper>
</CmsWrapper>
</CompareWrapper>
</FlagWrapper>
</UserWrapper>
</ApiWrapper>
</SnackbarWrapper>
</ThemeProvider>
</CookiesProvider>
</HashProvider>
</AnalyticsProvider>
</BrowserWrapper>
</CmsWrapper>
</CompareWrapper>
</FlagWrapper>
</UserWrapper>
</ApiWrapper>
</SnackbarWrapper>
</ThemeProvider>
</Provider>
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext, useState } from 'react';
import React, { useState } from 'react';
import {
Button,
Card,
Expand All @@ -10,14 +10,15 @@ import {
} from '@material-ui/core';
import BorderColorIcon from '@material-ui/icons/BorderColor';
import Moment from 'react-moment';
import { useSelector } from 'react-redux';
import {
bool,
func,
} from 'prop-types';

import { ChplTextField } from 'components/util';
import { eventTrack } from 'services/analytics.service';
import { UserContext, useAnalyticsContext } from 'shared/contexts';
import { useAnalyticsContext } from 'shared/contexts';
import { developer as developerPropType } from 'shared/prop-types';
import { utilStyles } from 'themes';

Expand Down Expand Up @@ -57,8 +58,8 @@ const useStyles = makeStyles({
});

function ChplAttestationWizardSection3({ developer, isSubmitting = false, dispatch }) {
const user = useSelector((state) => state.userInfo.user);
const { analytics } = useAnalyticsContext();
const { user } = useContext(UserContext);
const [signature, setSignature] = useState('');
const classes = useStyles();

Expand Down
12 changes: 6 additions & 6 deletions src/app/components/browser/browser-compared-widget.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useContext, useEffect } from 'react';
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';

import { BrowserContext } from 'shared/contexts';
import { pushPreviouslyCompared } from 'components/browser/browserInfo.slice';
import { listing as listingPropType } from 'shared/prop-types';

function ChplBrowserComparedWidget(props) {
const { listing } = props;
const { addToCompared } = useContext(BrowserContext);
function ChplBrowserComparedWidget({ listing }) {
const dispatch = useDispatch();

useEffect(() => {
addToCompared(listing);
dispatch(pushPreviouslyCompared(listing));
}, []);

return null;
Expand Down
12 changes: 6 additions & 6 deletions src/app/components/browser/browser-viewed-widget.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useContext, useEffect } from 'react';
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';

import { BrowserContext } from 'shared/contexts';
import { pushPreviouslyViewed } from 'components/browser/browserInfo.slice';
import { listing as listingPropType } from 'shared/prop-types';

function ChplBrowserViewedWidget(props) {
const { listing } = props;
const { addToViewed } = useContext(BrowserContext);
function ChplBrowserViewedWidget({ listing }) {
const dispatch = useDispatch();

useEffect(() => {
addToViewed(listing);
dispatch(pushPreviouslyViewed(listing));
}, []);

return null;
Expand Down
35 changes: 35 additions & 0 deletions src/app/components/browser/browserInfo.slice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* eslint-disable no-param-reassign */
import { createSlice } from '@reduxjs/toolkit';

export const browserInfoSlice = createSlice({
name: 'browserInfo',
initialState: {
api: '/rest',
apiKey: window.__env?.API_KEY ?? '12909a978483dfb8ecd0596c98ae9094',
previouslyCompared: JSON.parse(localStorage.getItem('ngStorage-previouslyCompared')) ?? [], // temporary use of localstorage until redux store is truly global
previouslyViewed: JSON.parse(localStorage.getItem('ngStorage-previouslyViewed')) ?? [], // temporary use of localstorage until redux store is truly global
},
reducers: {
pushPreviouslyCompared: (state, action) => {
state.previouslyCompared = [
action.payload.id,
...state.previouslyCompared.filter((id) => id !== action.payload.id),
].slice(0, 20);
localStorage.setItem('ngStorage-previouslyCompared', JSON.stringify(state.previouslyCompared)); // temporary until redux store is truly global
},
pushPreviouslyViewed: (state, action) => {
state.previouslyViewed = [
action.payload.id,
...state.previouslyViewed.filter((id) => id !== action.payload.id),
].slice(0, 20);
localStorage.setItem('ngStorage-previouslyViewed', JSON.stringify(state.previouslyViewed)); // temporary until redux store is truly global
},
},
});

export const {
pushPreviouslyCompared,
pushPreviouslyViewed,
} = browserInfoSlice.actions;

export default browserInfoSlice.reducer;
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from '@material-ui/core';
import BorderColorIcon from '@material-ui/icons/BorderColor';
import Moment from 'react-moment';
import { useSelector } from 'react-redux';
import { bool, func } from 'prop-types';
import { useFormik } from 'formik';
import * as yup from 'yup';
Expand All @@ -22,7 +23,7 @@ import ChplUrlChecker from 'components/url-checker/url-checker';
import UrlCheckerContext from 'components/url-checker/url-checker-context';
import { ChplTextField } from 'components/util';
import { eventTrack } from 'services/analytics.service';
import { DeveloperContext, UserContext, useAnalyticsContext } from 'shared/contexts';
import { DeveloperContext, useAnalyticsContext } from 'shared/contexts';
import { utilStyles } from 'themes';

const useStyles = makeStyles({
Expand Down Expand Up @@ -126,9 +127,9 @@ const getEditField = ({
);

function ChplDemographicsWizardSection2({ isSubmitting = false, dispatch }) {
const user = useSelector((state) => state.userInfo.user);
const { developer } = useContext(DeveloperContext);
const { analytics } = useAnalyticsContext();
const { user } = useContext(UserContext);
const { url, setUrl } = useContext(UrlCheckerContext);
const classes = useStyles();
let formik;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext, useEffect, useState } from 'react';
import React, { useEffect, useState } from 'react';
import {
Box,
Card,
Expand All @@ -8,11 +8,11 @@ import {
ListItem,
Typography,
} from '@material-ui/core';
import { useSelector } from 'react-redux';
import { bool } from 'prop-types';

import ChplIcsFamily from 'components/listing/details/ics-family/ics-family';
import { ChplLink } from 'components/util';
import { UserContext } from 'shared/contexts';
import { getDisplayDateFormat } from 'services/date-util';
import { listing as listingType } from 'shared/prop-types/listing';

Expand Down Expand Up @@ -43,7 +43,7 @@ const getRelatives = (source, user, isParent, listings) => listings.map((listing

function ChplAdditionalInformation({ isConfirming = false, listing }) {
const [currentPi, setCurrentPi] = useState(undefined);
const { user } = useContext(UserContext);
const user = useSelector((state) => state.userInfo.user);

useEffect(() => {
if (listing.promotingInteroperabilityUserHistory?.length > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Button,
} from '@material-ui/core';
import PlayCircleFilledWhiteOutlinedIcon from '@material-ui/icons/PlayCircleFilledWhiteOutlined';
import { useSelector } from 'react-redux';
import { arrayOf, bool, func } from 'prop-types';

import ChplDirectReviews from './direct-reviews';
Expand All @@ -23,8 +24,9 @@ function ChplCompliance({
initialSurveillance,
dispatch = () => {},
}) {
const user = useSelector((state) => state.userInfo.user);
const { listing } = useContext(ListingContext);
const { hasAnyRole, user } = useContext(UserContext);
const { hasAnyRole } = useContext(UserContext);
const [surveillance, setSurveillance] = useState([]);
const [icsSurveillance, setIcsSurveillance] = useState([]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '@material-ui/core';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import EditIcon from '@material-ui/icons/Edit';
import { useSelector } from 'react-redux';
import { arrayOf, bool, func } from 'prop-types';

import { getDataDisplay } from './compliance.services';
Expand Down Expand Up @@ -131,9 +132,10 @@ function ChplSurveillance({
ics = false,
dispatch = () => {},
}) {
const user = useSelector((state) => state.userInfo.user);
const { analytics } = useAnalyticsContext();
const { listing } = useContext(ListingContext);
const { hasAnyRole, user } = useContext(UserContext);
const { hasAnyRole } = useContext(UserContext);
const [surveillance, setSurveillance] = useState([]);
const [expanded, setExpanded] = useState(false);
const classes = useStyles();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
makeStyles,
} from '@material-ui/core';
import InfoIcon from '@material-ui/icons/Info';
import { useSelector } from 'react-redux';
import { arrayOf } from 'prop-types';

import ChplCodeSetIndicator from './code-set-indicator/code-set-indicator';
Expand All @@ -27,7 +28,7 @@ import {
ChplTooltip,
ChplUpdateIndicator,
} from 'components/util';
import { ListingContext, UserContext } from 'shared/contexts';
import { ListingContext } from 'shared/contexts';
import {
accessibilityStandard,
certificationResult,
Expand Down Expand Up @@ -56,7 +57,7 @@ function ChplCriterionDetailsView({
qmsStandards,
accessibilityStandards,
}) {
const { user } = useContext(UserContext);
const user = useSelector((state) => state.userInfo.user);
const { listing } = useContext(ListingContext);
const classes = useStyles();

Expand Down
Loading
Loading