Skip to content

Commit

Permalink
chore: upgrade react router to v6 (#861)
Browse files Browse the repository at this point in the history
  • Loading branch information
Syed-Ali-Abbas-Zaidi authored Jan 5, 2024
1 parent a7336b7 commit fccc27c
Show file tree
Hide file tree
Showing 69 changed files with 2,878 additions and 2,248 deletions.
4,192 changes: 2,375 additions & 1,817 deletions package-lock.json

Large diffs are not rendered by default.

17 changes: 8 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,19 @@
],
"dependencies": {
"@edx/brand": "npm:@openedx/brand-openedx@1.2.2",
"@edx/frontend-component-footer": "12.1.2",
"@edx/frontend-enterprise-catalog-search": "4.7.1",
"@edx/frontend-enterprise-hotjar": "1.4.0",
"@edx/frontend-enterprise-logistration": "3.4.0",
"@edx/frontend-enterprise-utils": "3.4.0",
"@edx/frontend-platform": "4.6.3",
"@edx/frontend-component-footer": "12.2.0",
"@edx/frontend-enterprise-catalog-search": "5.0.0",
"@edx/frontend-enterprise-hotjar": "2.0.0",
"@edx/frontend-enterprise-logistration": "4.0.0",
"@edx/frontend-enterprise-utils": "4.0.0",
"@edx/frontend-platform": "5.0.0",
"@edx/paragon": "20.45.4",
"@tanstack/react-query": "4.28.0",
"@tanstack/react-query-devtools": "4.29.0",
"algoliasearch": "4.6.0",
"axios": "0.21.1",
"classnames": "2.2.6",
"color": "3.1.3",
"connected-react-router": "6.9.2",
"core-js": "3.7.0",
"dayjs": "^1.11.9",
"dompurify": "2.3.6",
Expand All @@ -43,8 +42,8 @@
"react-instantsearch-dom": "6.38.1",
"react-parallax": "3.3.0",
"react-redux": "7.2.2",
"react-router": "4.3.1",
"react-router-dom": "5.2.0",
"react-router": "6.16.0",
"react-router-dom": "6.16.0",
"react-router-hash-link": "2.3.1",
"react-scroll": "1.8.4",
"react-string-replace": "1.1.0",
Expand Down
69 changes: 41 additions & 28 deletions src/components/app/App.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { useEffect } from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';
import { AppProvider, AuthenticatedPageRoute, PageRoute } from '@edx/frontend-platform/react';
import {
Routes, Route, Navigate, useLocation,
} from 'react-router-dom';
import { AppProvider, AuthenticatedPageRoute, PageWrap } from '@edx/frontend-platform/react';
import { logError } from '@edx/frontend-platform/logging';
import { initializeHotjar } from '@edx/frontend-enterprise-hotjar';
import {
Expand All @@ -26,6 +28,15 @@ import { UserSubsidy } from '../enterprise-user-subsidy';
// Create a query client for @tanstack/react-query
const queryClient = new QueryClient();

const TruncatedLocation = () => {
const location = useLocation();

if (location.pathname.endsWith('/')) {
return <Navigate to={location.pathname.slice(0, -1)} replace />;
}
return null;
};

const App = () => {
// hotjar initialization
useEffect(() => {
Expand All @@ -49,38 +60,40 @@ const App = () => {
<NoticesProvider>
<ToastsProvider>
<Toasts />
<Switch>
{/* always remove trailing slashes from any route */}
<Redirect from="/:url*(/+)" to={global.location.pathname.slice(0, -1)} />
{/* page routes for the app */}
<AuthenticatedPageRoute exact path="/" component={EnterpriseCustomerRedirect} />
<AuthenticatedPageRoute exact path="/r/:redirectPath+" component={EnterprisePageRedirect} />
<PageRoute exact path="/invite/:enterpriseCustomerInviteKey" component={EnterpriseInvitePage} />
<PageRoute
exact
{/* always remove trailing slashes from any route */}
<TruncatedLocation />
{/* page routes for the app */}
<Routes>
<Route path="/" element={<AuthenticatedPageRoute><EnterpriseCustomerRedirect /></AuthenticatedPageRoute>} />
<Route path="/r/*" element={<AuthenticatedPageRoute><EnterprisePageRedirect /></AuthenticatedPageRoute>} />
<Route path="/invite/:enterpriseCustomerInviteKey" element={<PageWrap><EnterpriseInvitePage /></PageWrap>} />
<Route
path="/:enterpriseSlug/executive-education-2u"
render={(routeProps) => (
<AuthenticatedPage>
<UserSubsidy>
<ExecutiveEducation2UPage {...routeProps} />
</UserSubsidy>
</AuthenticatedPage>
element={(
<PageWrap>
<AuthenticatedPage>
<UserSubsidy>
<ExecutiveEducation2UPage />
</UserSubsidy>
</AuthenticatedPage>
</PageWrap>
)}
/>
<PageRoute
exact
<Route
path="/:enterpriseSlug/executive-education-2u/enrollment-completed"
render={(routeProps) => (
<AuthenticatedPage>
<UserSubsidy>
<EnrollmentCompleted {...routeProps} />
</UserSubsidy>
</AuthenticatedPage>
element={(
<PageWrap>
<AuthenticatedPage>
<UserSubsidy>
<EnrollmentCompleted />
</UserSubsidy>
</AuthenticatedPage>
</PageWrap>
)}
/>
<Route path="/:enterpriseSlug" component={EnterpriseAppPageRoutes} />
<PageRoute path="*" component={NotFoundPage} />
</Switch>
<Route path="/:enterpriseSlug/*" element={<EnterpriseAppPageRoutes />} />
<Route path="*" element={<PageWrap><NotFoundPage /></PageWrap>} />
</Routes>
</ToastsProvider>
</NoticesProvider>
</AppProvider>
Expand Down
6 changes: 3 additions & 3 deletions src/components/app/AuthenticatedPage.test.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { screen } from '@testing-library/react';
import { AppContext } from '@edx/frontend-platform/react';
import { useLocation, useParams, useRouteMatch } from 'react-router-dom';
import { useLocation, useParams, useMatch } from 'react-router-dom';
import { renderWithRouter } from '@edx/frontend-enterprise-utils';
import '@testing-library/jest-dom/extend-expect';

Expand All @@ -11,7 +11,7 @@ jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: jest.fn(),
useParams: jest.fn(),
useRouteMatch: jest.fn(),
useMatch: jest.fn(),
}));

jest.mock('@edx/frontend-enterprise-logistration', () => ({
Expand Down Expand Up @@ -47,7 +47,7 @@ const mockAuthenticatedUser = {

useLocation.mockReturnValue(mockLocation);
useParams.mockReturnValue({ enterpriseSlug: mockEnterpriseSlug });
useRouteMatch.mockReturnValue({ isExact: false });
useMatch.mockReturnValue({});
useRecommendCoursesForMe.mockReturnValue({
shouldRecommendCourses: false,
});
Expand Down
50 changes: 27 additions & 23 deletions src/components/app/EnterpriseAppPageRoutes.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { PageRoute } from '@edx/frontend-platform/react';
import { PageWrap } from '@edx/frontend-platform/react';
import { Route, Routes } from 'react-router-dom';

import { DashboardPage } from '../dashboard';
import { CoursePage } from '../course';
Expand All @@ -17,29 +18,32 @@ import { AcademyDetailPage } from '../academies';
// to reduce API calls by 2 (DashboardPage, CoursePage, SearchPage) or by 3 ( + AuthenticatedPage) if created in App.jsx
const EnterpriseAppPageRoutes = () => (
<AuthenticatedUserSubsidyPage>
<PageRoute exact path="/:enterpriseSlug" component={DashboardPage} />
<PageRoute
exact
path={['/:enterpriseSlug/search', '/:enterpriseSlug/search/:pathwayUUID']}
component={SearchPage}
/>
<PageRoute exact path="/:enterpriseSlug/course/:courseKey" component={CoursePage} />
<PageRoute path="/:enterpriseSlug/:courseType/course/:courseKey" component={CoursePage} />
{features.ENABLE_PROGRAMS && (
<PageRoute exact path="/:enterpriseSlug/program/:programUuid" component={ProgramPage} />
)}
{
<Routes>
<Route path="/" element={<PageWrap><DashboardPage /></PageWrap>} />
{['search', 'search/:pathwayUUID'].map(route => (
<Route
key={route}
path={route}
element={<PageWrap><SearchPage /></PageWrap>}
/>
))}
<Route path="course/:courseKey/*" element={<PageWrap><CoursePage /></PageWrap>} />
<Route path=":courseType/course/:courseKey/*" element={<PageWrap><CoursePage /></PageWrap>} />
{features.ENABLE_PROGRAMS && (
<Route path="program/:programUuid" element={<PageWrap><ProgramPage /></PageWrap>} />
)}
{
// Deprecated URL, will be removed in the future.
<PageRoute exact path="/:enterpriseSlug/program-progress/:programUUID" component={ProgramProgressRedirect} />
}
<PageRoute exact path="/:enterpriseSlug/program/:programUUID/progress" component={ProgramProgressPage} />
<PageRoute exact path="/:enterpriseSlug/skills-quiz" component={SkillsQuizPage} />
<PageRoute exact path="/:enterpriseSlug/licenses/:activationKey/activate" component={LicenseActivationPage} />
{features.FEATURE_ENABLE_PATHWAY_PROGRESS && (
<PageRoute exact path="/:enterpriseSlug/pathway/:pathwayUUID/progress" component={PathwayProgressPage} />
)}

<PageRoute exact path="/:enterpriseSlug/academies/:academyUUID" component={AcademyDetailPage} />
<Route path="program-progress/:programUUID" element={<PageWrap><ProgramProgressRedirect /></PageWrap>} />
}
<Route path="program/:programUUID/progress" element={<PageWrap><ProgramProgressPage /></PageWrap>} />
<Route path="skills-quiz" element={<PageWrap><SkillsQuizPage /></PageWrap>} />
<Route path="licenses/:activationKey/activate" element={<PageWrap><LicenseActivationPage /></PageWrap>} />
{features.FEATURE_ENABLE_PATHWAY_PROGRESS && (
<Route exact path="pathway/:pathwayUUID/progress" element={<PageWrap><PathwayProgressPage /></PageWrap>} />
)}
<Route path="academies/:academyUUID" element={<AcademyDetailPage />} />
</Routes>
</AuthenticatedUserSubsidyPage>
);

Expand Down
6 changes: 3 additions & 3 deletions src/components/app/data/useRecommendCoursesForMe.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
useMemo,
useState,
} from 'react';
import { useParams, useRouteMatch } from 'react-router-dom';
import { useParams, useMatch } from 'react-router-dom';
import { AppContext } from '@edx/frontend-platform/react';
import { logInfo } from '@edx/frontend-platform/logging';

Expand All @@ -18,15 +18,15 @@ export default function useRecommendCoursesForMe() {
const { enterpriseSlug } = useParams();
const { enterpriseConfig } = useContext(AppContext);

const routeMatch = useRouteMatch(`/${enterpriseSlug}/search`);
const routeMatch = useMatch(`/${enterpriseSlug}/search`);
const [shouldRecommendCourses, setShouldRecommendCourses] = useState(false);

const { enterpriseCuration: { canOnlyViewHighlightSets } } = useEnterpriseCuration(enterpriseConfig?.uuid);

const showRecommendCourses = useCallback(() => {
// only show the recommend courses button if the current route is the search page
// and the user is not restricted to only viewing highlight sets.
if (routeMatch?.isExact && !canOnlyViewHighlightSets) {
if (routeMatch && !canOnlyViewHighlightSets) {
setShouldRecommendCourses(true);
} else {
logInfo('Cannot show recommend courses button because the current route is not the search page.');
Expand Down
12 changes: 6 additions & 6 deletions src/components/app/data/useRecommendCoursesForMe.test.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AppContext } from '@edx/frontend-platform/react';
import { useParams, useRouteMatch } from 'react-router-dom';
import { useParams, useMatch } from 'react-router-dom';
import { renderHook, act } from '@testing-library/react-hooks';

import useRecommendCoursesForMe from './useRecommendCoursesForMe';
Expand All @@ -8,7 +8,7 @@ import { useEnterpriseCuration } from '../../search/content-highlights/data';
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: jest.fn(),
useRouteMatch: jest.fn(),
useMatch: jest.fn(),
}));

jest.mock('../../search/content-highlights/data', () => ({
Expand Down Expand Up @@ -44,17 +44,17 @@ describe('useRecommendCoursesForMe', () => {

it.each([
{
mockRouteMatch: { isExact: false }, // simulates non-search page route
mockRouteMatch: null, // simulates non-search page route
canOnlyViewHighlightSets: false,
hasRecommendCourseCTA: false,
},
{
mockRouteMatch: { isExact: true }, // simulates search page route
mockRouteMatch: { path: '/search' }, // simulates search page route
canOnlyViewHighlightSets: false,
hasRecommendCourseCTA: true,
},
{
mockRouteMatch: { isExact: true }, // simulates search page route
mockRouteMatch: { path: '/search' }, // simulates search page route
canOnlyViewHighlightSets: true,
hasRecommendCourseCTA: false,
},
Expand All @@ -63,7 +63,7 @@ describe('useRecommendCoursesForMe', () => {
canOnlyViewHighlightSets,
hasRecommendCourseCTA,
}) => {
useRouteMatch.mockReturnValue(mockRouteMatch);
useMatch.mockReturnValue(mockRouteMatch);
useEnterpriseCuration.mockReturnValue({
enterpriseCuration: {
canOnlyViewHighlightSets,
Expand Down
8 changes: 4 additions & 4 deletions src/components/course/CoursePage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, {
useCallback, useContext, useEffect, useMemo, useState,
} from 'react';
import {
useLocation, useParams, useHistory,
useLocation, useParams, useNavigate,
} from 'react-router-dom';
import { Helmet } from 'react-helmet';
import { Container } from '@edx/paragon';
Expand Down Expand Up @@ -63,7 +63,7 @@ const CoursePage = () => {
},
} = useEnterpriseCuration(enterpriseUUID);
const { pathname, search, state } = useLocation();
const history = useHistory();
const navigate = useNavigate();

const courseRunKey = useMemo(
() => {
Expand Down Expand Up @@ -226,9 +226,9 @@ const CoursePage = () => {
courseState.course,
enterpriseSlug,
);
history.replace(newUrl, state);
navigate(newUrl, { state, replace: true });
}
}, [enterpriseSlug, history, courseState, pathname, state]);
}, [enterpriseSlug, navigate, courseState, pathname, state]);

const subsidyRequestCatalogsApplicableToCourse = useMemo(() => {
const catalogsContainingCourse = new Set(courseState?.catalog?.catalogList);
Expand Down
6 changes: 3 additions & 3 deletions src/components/course/CourseRecommendationCard.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useContext, useMemo } from 'react';
import PropTypes from 'prop-types';
import cardFallbackImg from '@edx/brand/paragon/images/card-imagecap-fallback.png';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { AppContext } from '@edx/frontend-platform/react';
import { Card, Truncate } from '@edx/paragon';
import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils';
Expand All @@ -15,7 +15,7 @@ export const SAME_PART_EVENT_NAME = 'edx.ui.enterprise.learner_portal.same.partn
const CourseRecommendationCard = ({ course, isPartnerRecommendation }) => {
const { enterpriseConfig: { slug, uuid } } = useContext(AppContext);
const eventName = isPartnerRecommendation ? SAME_PART_EVENT_NAME : COURSE_REC_EVENT_NAME;
const history = useHistory();
const navigate = useNavigate();
const cachedLinkToCourse = useMemo(
() => linkToCourse(course, slug),
[course, slug],
Expand Down Expand Up @@ -49,7 +49,7 @@ const CourseRecommendationCard = ({ course, isPartnerRecommendation }) => {
courseKey: course.key,
},
);
history.push(cachedLinkToCourse);
navigate(cachedLinkToCourse);
}}
>
<Card.ImageCap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const wrapper = ({ children }) => (

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useRouteMatch: jest.fn().mockReturnValue({ url: '/test-enterprise/course/edX+DemoX' }),
useLocation: jest.fn().mockReturnValue({ pathname: '/test-enterprise/course/edX+DemoX' }),
}));

jest.mock('../useCourseRunCardHeading', () => jest.fn(() => 'Course started'));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useRouteMatch } from 'react-router-dom';
import { useLocation } from 'react-router-dom';

import { COURSE_AVAILABILITY_MAP } from '../../../data/constants';
import useCourseRunCardHeading from './useCourseRunCardHeading';
Expand Down Expand Up @@ -26,7 +26,7 @@ const useCourseRunCardData = ({
subsidyAccessPolicy,
userCanRequestSubsidyForCourse,
}) => {
const routeMatch = useRouteMatch();
const { pathname } = useLocation();
const {
key: contentKey,
availability,
Expand All @@ -35,7 +35,7 @@ const useCourseRunCardData = ({
const isCourseRunCurrent = availability === COURSE_AVAILABILITY_MAP.CURRENT;
const isUserEnrolled = !!userEnrollment;
const externalCourseEnrollmentUrl = getExternalCourseEnrollmentUrl({
currentRouteUrl: routeMatch.url,
currentRouteUrl: pathname,
});

// Get and return course run card data for display
Expand Down
Loading

0 comments on commit fccc27c

Please sign in to comment.