Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add page not found route #1514

Merged
merged 3 commits into from
Nov 12, 2024
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
49 changes: 49 additions & 0 deletions src/generic/PageNotFound.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { getConfig } from '@edx/frontend-platform';
import { Hyperlink } from '@openedx/paragon';
import { useIntl } from '@edx/frontend-platform/i18n';
import { logError } from '@edx/frontend-platform/logging';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import FooterSlot from '@openedx/frontend-slot-footer';

import HeaderSlot from '../plugin-slots/HeaderSlot';
import messages from './messages';

const PageNotFound = () => {
const { formatMessage } = useIntl();
const location = window.location.href;

logError('Page failed to load, probably an invalid URL.', location);
sendTrackEvent('edx.ui.lms.page_not_found', { location });

return (
<>
<HeaderSlot />
<main
id="main-content"
className="main-content d-flex justify-content-center align-items-center flex-column"
style={{
height: '50vh',
}}
>
<h1 className="h3">
{formatMessage(messages.pageNotFoundHeader)}
</h1>
<p>
{formatMessage(
messages.pageNotFoundBody,
{
homepageLink: (
<Hyperlink destination={getConfig().LMS_BASE_URL}>
{formatMessage(messages.homepageLink)}
</Hyperlink>
),
},
)}
</p>
</main>
<FooterSlot />
</>
);
};

export default PageNotFound;
41 changes: 41 additions & 0 deletions src/generic/PageNotFound.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { getConfig, history } from '@edx/frontend-platform';
import { Routes, Route } from 'react-router-dom';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';

import {
initializeTestStore,
render,
screen,
} from '../setupTest';
import PageNotFound from './PageNotFound';
import messages from './messages';

jest.mock('@edx/frontend-platform/analytics');

describe('PageNotFound', () => {
beforeEach(async () => {
await initializeTestStore();
const invalidUrl = '/new/course';
history.push(invalidUrl);
render(
<Routes>
<Route path="*" element={<PageNotFound />} />
</Routes>,
{ wrapWithRouter: true },
);
});

it('displays page not found header', () => {
expect(screen.getByText(messages.pageNotFoundHeader.defaultMessage)).toBeVisible();
});

it('displays link back to learner dashboard', () => {
const expected = getConfig().LMS_BASE_URL;
const homepageLink = screen.getByRole('link', { name: messages.homepageLink.defaultMessage });
expect(homepageLink).toHaveAttribute('href', expected);
});

it('calls tracking events', () => {
expect(sendTrackEvent).toHaveBeenCalled();
});
});
15 changes: 15 additions & 0 deletions src/generic/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ const messages = defineMessages({
defaultMessage: 'Sign in',
description: 'Text in a button, prompting the user to log in.',
},
pageNotFoundHeader: {
id: 'learning.pageNotFound.header',
defaultMessage: 'Page not found',
description: 'Text for header notifying them that the page is not found',
},
pageNotFoundBody: {
id: 'learning.pageNotFound.body',
defaultMessage: 'The page you you were looking for was not found. Go back to the {homepageLink}.',
description: 'Text for body, prompting the user to go back to the home page',
},
homepageLink: {
id: 'learning.pageNotFound.body.homepageLink.label',
defaultMessage: 'homepage',
description: 'Text for url, telling them the page they will be navigated to',
},
});

export default messages;
3 changes: 2 additions & 1 deletion src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
getConfig,
} from '@edx/frontend-platform';
import { AppProvider, ErrorPage, PageWrap } from '@edx/frontend-platform/react';
import React from 'react';
import ReactDOM from 'react-dom';
import { Routes, Route } from 'react-router-dom';

Expand Down Expand Up @@ -35,6 +34,7 @@ import CourseAccessErrorPage from './generic/CourseAccessErrorPage';
import DecodePageRoute from './decode-page-route';
import { DECODE_ROUTES, ROUTES } from './constants';
import PreferencesUnsubscribe from './preferences-unsubscribe';
import PageNotFound from './generic/PageNotFound';

subscribe(APP_READY, () => {
ReactDOM.render(
Expand All @@ -46,6 +46,7 @@ subscribe(APP_READY, () => {
<NoticesProvider>
<UserMessagesProvider>
<Routes>
<Route path="*" element={<PageWrap><PageNotFound /></PageWrap>} />
<Route path={ROUTES.UNSUBSCRIBE} element={<PageWrap><GoalUnsubscribe /></PageWrap>} />
<Route path={ROUTES.REDIRECT} element={<PageWrap><CoursewareRedirectLandingPage /></PageWrap>} />
<Route path={ROUTES.PREFERENCES_UNSUBSCRIBE} element={<PageWrap><PreferencesUnsubscribe /></PageWrap>} />
Expand Down
Loading