Skip to content

Commit

Permalink
Merge pull request #2258 from HHS/main
Browse files Browse the repository at this point in the history
[PROD] 07/10 TTAHUB-3102 Temporarily disable resource scrape job, TTAHUB-2907 Add a "something went wrong" page
  • Loading branch information
Jones-QuarteyDana authored Jul 10, 2024
2 parents b9bf534 + 9fc14a2 commit 1b689a8
Show file tree
Hide file tree
Showing 39 changed files with 1,570 additions and 340 deletions.
2 changes: 1 addition & 1 deletion colorsjschecksum
Original file line number Diff line number Diff line change
@@ -1 +1 @@
69962956f5817a804f1a491395986eb3c612a6feb4d76315f58c5b273cdf25a7
5dfc9c0a9f719af9ac72655dee86b64b9122ee7cda857e6ac68ae4a3dc76ade6
2 changes: 1 addition & 1 deletion colorsscsschecksum
Original file line number Diff line number Diff line change
@@ -1 +1 @@
45fe702aa79405030c90def8c4690064d0be4ca316fc297e6b1dbe1117ae95ff
36906d289c12231e597eeb56423d83f37593429766f6d496f2db5f508c7d6ee8
2 changes: 1 addition & 1 deletion cucumber/features/notFound.feature
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ Feature: Not Found Page
Scenario: User is shown a 404 page if route is not found
Given I am logged in
And I go to an unknown page
Then I see the "Not Found" alert message
Then I see the "404 error" alert message
7 changes: 5 additions & 2 deletions cucumber/features/steps/notFoundSteps.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ Given('I go to an unknown page', async () => {

Then('I see the {string} alert message', async (heading) => {
const page = scope.context.currentPage;
const value = await page.$eval('.usa-alert__heading', (el) => el.textContent);

// find a div with the class 'smart-hub--something-went-wrong'..
const value = await page.evaluate(() => {
const element = document.querySelector('.smart-hub--something-went-wrong');
return element ? element.innerText : '';
});
assertTrue(value.includes(heading));
});
76 changes: 47 additions & 29 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import React, { useState, useEffect, useMemo } from 'react';
import '@trussworks/react-uswds/lib/uswds.css';
import '@trussworks/react-uswds/lib/index.css';

import { BrowserRouter, Route, Switch } from 'react-router-dom';
import {
BrowserRouter, Route, Switch,
} from 'react-router-dom';
import { Helmet } from 'react-helmet';

import { fetchUser, fetchLogout } from './fetchers/Auth';
import { HTTPError } from './fetchers';
import { getSiteAlerts } from './fetchers/siteAlerts';
import FeatureFlag from './components/FeatureFlag';
import UserContext from './UserContext';
import SomethingWentWrongContext from './SomethingWentWrongContext';
import SiteNav from './components/SiteNav';
import Header from './components/Header';

Expand All @@ -19,7 +22,6 @@ import TrainingReports from './pages/TrainingReports';
import ResourcesDashboard from './pages/ResourcesDashboard';
import CourseDashboard from './pages/CourseDashboard';
import Unauthenticated from './pages/Unauthenticated';
import NotFound from './pages/NotFound';
import Home from './pages/Home';
import Landing from './pages/Landing';
import ActivityReport from './pages/ActivityReport';
Expand Down Expand Up @@ -58,6 +60,7 @@ import SessionForm from './pages/SessionForm';
import ViewTrainingReport from './pages/ViewTrainingReport';
import useGaUserData from './hooks/useGaUserData';
import QADashboard from './pages/QADashboard';
import SomethingWentWrong from './components/SomethingWentWrong';

const WHATSNEW_NOTIFICATIONS_KEY = 'whatsnew-read-notifications';

Expand All @@ -76,6 +79,8 @@ function App() {
const [notifications, setNotifications] = useState({ whatsNew: '' });

const [areThereUnreadNotifications, setAreThereUnreadNotifications] = useState(false);
const [errorResponseCode, setErrorResponseCode] = useState(null);
const [showingNotFound, setShowingNotFound] = useState(false);

useGaUserData(user);

Expand Down Expand Up @@ -441,7 +446,7 @@ function App() {
<Route
render={() => (
<AppWrapper hasAlerts={!!(alert)} authenticated logout={logout}>
<NotFound />
<SomethingWentWrong />
</AppWrapper>
)}
/>
Expand All @@ -456,9 +461,15 @@ function App() {
</Helmet>
<Loader loading={isAppLoading} loadingLabel={`App ${appLoadingText}`} text={appLoadingText} isFixed />
<AppLoadingContext.Provider value={{ isAppLoading, setIsAppLoading, setAppLoadingText }}>
<BrowserRouter>
<ScrollToTop />
{authenticated && (
<SomethingWentWrongContext.Provider value={
{
errorResponseCode, setErrorResponseCode, showingNotFound, setShowingNotFound,
}
}
>
<BrowserRouter>
<ScrollToTop />
{authenticated && !errorResponseCode && !showingNotFound && (
<>
<a className="usa-skipnav" href="#main-content">
Skip to main content
Expand All @@ -475,30 +486,37 @@ function App() {
/>
</UserContext.Provider>
</>
)}
<AriaLiveContext.Provider value={{ announce }}>
<MyGroupsProvider authenticated={authenticated}>
<UserContext.Provider value={{ user, authenticated, logout }}>
<Header
authenticated
alert={alert}
areThereUnreadNotifications={areThereUnreadNotifications}
setAreThereUnreadNotifications={setAreThereUnreadNotifications}
/>
{!authenticated && (authError === 403
? <AppWrapper logout={logout}><RequestPermissions /></AppWrapper>
: (
<AppWrapper padded={false} logout={logout}>
<Unauthenticated loggedOut={loggedOut} timedOut={timedOut} />
)}
<AriaLiveContext.Provider value={{ announce }}>
<MyGroupsProvider authenticated={authenticated}>
<UserContext.Provider value={{ user, authenticated, logout }}>
<Header
authenticated
alert={alert}
areThereUnreadNotifications={areThereUnreadNotifications}
setAreThereUnreadNotifications={setAreThereUnreadNotifications}
/>
{!authenticated && (authError === 403
? <AppWrapper logout={logout}><RequestPermissions /></AppWrapper>
: (
<AppWrapper padded={false} logout={logout}>
<Unauthenticated loggedOut={loggedOut} timedOut={timedOut} />
</AppWrapper>
)
)}
{authenticated && errorResponseCode
&& (
<AppWrapper hasAlerts={false} authenticated logout={logout}>
<SomethingWentWrong passedErrorResponseCode={errorResponseCode} />
</AppWrapper>
)
)}
{authenticated && renderAuthenticatedRoutes()}
</UserContext.Provider>
</MyGroupsProvider>
</AriaLiveContext.Provider>
</BrowserRouter>
<AriaLiveRegion messages={announcements} />
)}
{authenticated && !errorResponseCode && renderAuthenticatedRoutes()}
</UserContext.Provider>
</MyGroupsProvider>
</AriaLiveContext.Provider>
</BrowserRouter>
<AriaLiveRegion messages={announcements} />
</SomethingWentWrongContext.Provider>
</AppLoadingContext.Provider>
</>
);
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/SomethingWentWrongContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react';

const SomethingWentWrong = React.createContext({
});

export default SomethingWentWrong;
1 change: 1 addition & 0 deletions frontend/src/colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const colors = {
textInk: '#1b1b1b',
textLink: '#46789B',
textVisited: '#8C39DB',
responseCode: '#71767A',
};

module.exports = colors;
3 changes: 2 additions & 1 deletion frontend/src/colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ $error-dark: #b50909;
$blue-vivid-focus: #2491FF;
$text-ink: #1b1b1b;
$text-link: #46789B;
$text-visited: #8C39DB;
$text-visited: #8C39DB;
$response-code: #71767A;
4 changes: 2 additions & 2 deletions frontend/src/components/DisplayWithPermission.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import NotFound from '../pages/NotFound';
import UserContext from '../UserContext';
import isAdmin from '../permissions';
import SomethingWentWrong from './SomethingWentWrong';

export default function DisplayWithPermission({
scopes, renderNotFound, children,
Expand All @@ -16,7 +16,7 @@ export default function DisplayWithPermission({

if (!admin && !userHasScope) {
if (renderNotFound) {
return <NotFound />;
return <SomethingWentWrong />;
}
return <></>;
}
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/FeatureFlag.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import NotFound from '../pages/NotFound';
import UserContext from '../UserContext';
import isAdmin from '../permissions';
import SomethingWentWrong from './SomethingWentWrong';

export default function FeatureFlag({
flag, renderNotFound, children,
Expand All @@ -12,7 +12,7 @@ export default function FeatureFlag({

if (!admin && user.flags && !user.flags.includes(flag)) {
if (renderNotFound) {
return <NotFound />;
return <SomethingWentWrong />;
}
return <></>;
}
Expand Down
46 changes: 30 additions & 16 deletions frontend/src/components/GoalForm/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
screen,
within,
waitFor,
act,
} from '@testing-library/react';
import { SCOPE_IDS } from '@ttahub/common';
import selectEvent from 'react-select-event';
Expand All @@ -18,6 +19,7 @@ import UserContext from '../../../UserContext';
import { OBJECTIVE_ERROR_MESSAGES } from '../constants';
import { BEFORE_OBJECTIVES_CREATE_GOAL, BEFORE_OBJECTIVES_SELECT_RECIPIENTS } from '../Form';
import AppLoadingContext from '../../../AppLoadingContext';
import SomethingWentWrongContext from '../../../SomethingWentWrongContext';

const [objectiveTitleError] = OBJECTIVE_ERROR_MESSAGES;

Expand Down Expand Up @@ -101,31 +103,33 @@ describe('create goal', () => {
}],
}];

function renderForm(recipient = defaultRecipient, goalId = 'new') {
function renderForm(recipient = defaultRecipient, goalId = 'new', setErrorResponseCode = jest.fn()) {
const history = createMemoryHistory();
render((
<Router history={history}>
<UserContext.Provider value={{
user: {
permissions: [{ regionId: 1, scopeId: SCOPE_IDS.READ_WRITE_ACTIVITY_REPORTS }],
},
}}
>
<AppLoadingContext.Provider value={
<SomethingWentWrongContext.Provider value={{ setErrorResponseCode }}>
<UserContext.Provider value={{
user: {
permissions: [{ regionId: 1, scopeId: SCOPE_IDS.READ_WRITE_ACTIVITY_REPORTS }],
},
}}
>
<AppLoadingContext.Provider value={
{
setIsAppLoading: jest.fn(),
setAppLoadingText: jest.fn(),
isAppLoading: false,
}
}
>
<CreateGoal
recipient={recipient}
regionId="1"
isNew={goalId === 'new'}
/>
</AppLoadingContext.Provider>
</UserContext.Provider>
>
<CreateGoal
recipient={recipient}
regionId="1"
isNew={goalId === 'new'}
/>
</AppLoadingContext.Provider>
</UserContext.Provider>
</SomethingWentWrongContext.Provider>
</Router>
));
}
Expand Down Expand Up @@ -368,6 +372,16 @@ describe('create goal', () => {
expect(alert.textContent).toBe('There was an error saving your goal');
});

it('correctly calls the setErrorResponseCode function when there is an error', async () => {
const setErrorResponseCode = jest.fn();
fetchMock.restore();
fetchMock.get('/api/recipient/1/goals?goalIds=', 500);
await act(async () => {
renderForm(defaultRecipient, '48743', setErrorResponseCode);
await waitFor(() => expect(setErrorResponseCode).toHaveBeenCalledWith(500));
});
});

it('removes goals', async () => {
fetchMock.post('/api/goals', postResponse);

Expand Down
14 changes: 11 additions & 3 deletions frontend/src/components/GoalForm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import AppLoadingContext from '../../AppLoadingContext';
import useUrlParamState from '../../hooks/useUrlParamState';
import UserContext from '../../UserContext';
import VanillaModal from '../VanillaModal';
import SomethingWentWrongContext from '../../SomethingWentWrongContext';

const [objectiveTextError] = OBJECTIVE_ERROR_MESSAGES;

Expand Down Expand Up @@ -112,6 +113,7 @@ export default function GoalForm({

const { isAppLoading, setIsAppLoading, setAppLoadingText } = useContext(AppLoadingContext);
const { user } = useContext(UserContext);
const { setErrorResponseCode } = useContext(SomethingWentWrongContext);

const canView = useMemo(() => user.permissions.filter(
(permission) => permission.regionId === parseInt(regionId, DECIMAL_BASE),
Expand All @@ -134,9 +136,14 @@ export default function GoalForm({
async function fetchGoal() {
setFetchAttempted(true); // as to only fetch once
try {
const [goal] = await goalsByIdAndRecipient(
ids, recipient.id.toString(),
);
let goal = null;
try {
[goal] = await goalsByIdAndRecipient(
ids, recipient.id.toString(),
);
} catch (err) {
setErrorResponseCode(err.status);
}

const selectedGoalGrants = goal.grants ? goal.grants : [goal.grant];

Expand Down Expand Up @@ -200,6 +207,7 @@ export default function GoalForm({
ids,
setAppLoadingText,
setIsAppLoading,
setErrorResponseCode,
]);

const setObjectiveError = (objectiveIndex, errorText) => {
Expand Down
Loading

0 comments on commit 1b689a8

Please sign in to comment.