Skip to content

Commit 39cc97e

Browse files
committed
refactor: Convert Stepper from Modal to Page
1 parent e182155 commit 39cc97e

9 files changed

Lines changed: 209 additions & 175 deletions

File tree

src/library-authoring/LibraryLayout.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { ROUTES } from './routes';
2020
import { LibrarySectionPage, LibrarySubsectionPage } from './section-subsections';
2121
import { LibraryUnitPage } from './units';
2222
import { LibraryTeamModal } from './library-team';
23+
import { ImportStepperPage } from './import-course/stepper/ImportStepperPage';
2324

2425
const LibraryLayoutWrapper: React.FC<React.PropsWithChildren> = ({ children }) => {
2526
const {
@@ -97,6 +98,10 @@ const LibraryLayout = () => (
9798
path={ROUTES.IMPORT}
9899
Component={CourseImportHomePage}
99100
/>
101+
<Route
102+
path={ROUTES.IMPORT_COURSE}
103+
Component={ImportStepperPage}
104+
/>
100105
</Route>
101106
</Routes>
102107
);

src/library-authoring/import-course/CourseImportHomePage.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const render = (libraryId: string) => (
2929
{children}
3030
</LibraryProvider>
3131
),
32-
path: '/libraries/:libraryId/import-course',
32+
path: '/libraries/:libraryId/import',
3333
params: { libraryId },
3434
},
3535
)
Lines changed: 55 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
import { useNavigate } from 'react-router-dom';
12
import { Helmet } from 'react-helmet';
23
import {
34
Button,
45
Card,
56
Container,
67
Layout,
78
Stack,
8-
useToggle,
99
} from '@openedx/paragon';
1010
import { Add } from '@openedx/paragon/icons';
1111
import { getConfig } from '@edx/frontend-platform';
@@ -18,7 +18,6 @@ import { useLibraryContext } from '../common/context/LibraryContext';
1818
import { useCourseImports } from '../data/apiHooks';
1919
import { HelpSidebar } from './HelpSidebar';
2020
import { ImportedCourseCard } from './ImportedCourseCard';
21-
import { ImportStepperModal } from './stepper/ImportStepperModal';
2221
import messages from './messages';
2322

2423
const EmptyState = () => (
@@ -36,75 +35,68 @@ const EmptyState = () => (
3635

3736
export const CourseImportHomePage = () => {
3837
const intl = useIntl();
38+
const navigate = useNavigate();
3939
const { libraryId, libraryData, readOnly } = useLibraryContext();
40-
const [importModalIsOpen, openImportModal, closeImportModal] = useToggle(false);
4140
const { data: courseImports } = useCourseImports(libraryId);
4241

4342
if (!courseImports || !libraryData) {
4443
return <Loading />;
4544
}
4645

4746
return (
48-
<>
49-
<div className="d-flex">
50-
<div className="flex-grow-1">
51-
<Helmet>
52-
<title>{libraryData.title} | {process.env.SITE_NAME}</title>
53-
</Helmet>
54-
<Header
55-
number={libraryData.slug}
56-
title={libraryData.title}
57-
org={libraryData.org}
58-
contextId={libraryId}
59-
isLibrary
60-
readOnly={readOnly}
61-
containerProps={{
62-
size: undefined,
63-
}}
64-
/>
65-
<Container className="mt-4 mb-5">
66-
<div className="px-4 bg-light-200 border-bottom">
67-
<SubHeader
68-
title={intl.formatMessage(messages.pageTitle)}
69-
subtitle={intl.formatMessage(messages.pageSubtitle)}
70-
hideBorder
71-
headerActions={
72-
getConfig().ENABLE_COURSE_IMPORT_IN_LIBRARY === 'true' && (
73-
<Button onClick={openImportModal}>
74-
{intl.formatMessage(messages.importCourseButton)}
75-
</Button>
76-
)
77-
}
78-
/>
79-
</div>
80-
<Layout xs={[{ span: 9 }, { span: 3 }]}>
81-
<Layout.Element>
82-
{courseImports.length ? (
83-
<Stack gap={3} className="pl-4 mt-4">
84-
<h3>
85-
<FormattedMessage {...messages.courseImportPreviousImports} />
86-
</h3>
87-
{courseImports.map((courseImport) => (
88-
<ImportedCourseCard
89-
key={courseImport.source.key}
90-
courseImport={courseImport}
91-
/>
92-
))}
93-
</Stack>
94-
) : (<EmptyState />)}
95-
</Layout.Element>
96-
<Layout.Element>
97-
<HelpSidebar />
98-
</Layout.Element>
99-
</Layout>
100-
</Container>
101-
</div>
47+
<div className="d-flex">
48+
<div className="flex-grow-1">
49+
<Helmet>
50+
<title>{libraryData.title} | {process.env.SITE_NAME}</title>
51+
</Helmet>
52+
<Header
53+
number={libraryData.slug}
54+
title={libraryData.title}
55+
org={libraryData.org}
56+
contextId={libraryId}
57+
isLibrary
58+
readOnly={readOnly}
59+
containerProps={{
60+
size: undefined,
61+
}}
62+
/>
63+
<Container className="mt-4 mb-5">
64+
<div className="px-4 bg-light-200 border-bottom">
65+
<SubHeader
66+
title={intl.formatMessage(messages.pageTitle)}
67+
subtitle={intl.formatMessage(messages.pageSubtitle)}
68+
hideBorder
69+
headerActions={
70+
getConfig().ENABLE_COURSE_IMPORT_IN_LIBRARY === 'true' && (
71+
<Button onClick={() => navigate('courses')}>
72+
{intl.formatMessage(messages.importCourseButton)}
73+
</Button>
74+
)
75+
}
76+
/>
77+
</div>
78+
<Layout xs={[{ span: 9 }, { span: 3 }]}>
79+
<Layout.Element>
80+
{courseImports.length ? (
81+
<Stack gap={3} className="pl-4 mt-4">
82+
<h3>
83+
<FormattedMessage {...messages.courseImportPreviousImports} />
84+
</h3>
85+
{courseImports.map((courseImport) => (
86+
<ImportedCourseCard
87+
key={courseImport.source.key}
88+
courseImport={courseImport}
89+
/>
90+
))}
91+
</Stack>
92+
) : (<EmptyState />)}
93+
</Layout.Element>
94+
<Layout.Element>
95+
<HelpSidebar />
96+
</Layout.Element>
97+
</Layout>
98+
</Container>
10299
</div>
103-
<ImportStepperModal
104-
isOpen={importModalIsOpen}
105-
onClose={closeImportModal}
106-
libraryKey={libraryId}
107-
/>
108-
</>
100+
</div>
109101
);
110102
};

src/library-authoring/import-course/messages.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ const messages = defineMessages({
7373
+ '<p>For additional details you can review the Library Import documentation.</p>',
7474
description: 'Body of the second question in the Help & Support sidebar',
7575
},
76-
importCourseModalTitle: {
77-
id: 'course-authoring.library-authoring.import-course.modal.title',
76+
importCourseStepperTitle: {
77+
id: 'course-authoring.library-authoring.import-course.stepper.title',
7878
defaultMessage: 'Import Course to Library',
7979
description: 'Title for the modal to import a course into a library.',
8080
},
@@ -84,27 +84,27 @@ const messages = defineMessages({
8484
description: 'Label of the button to open the modal to import a course into a library.',
8585
},
8686
importCourseSelectCourseStep: {
87-
id: 'course-authoring.library-authoring.import-course.select-course.title',
87+
id: 'course-authoring.library-authoring.import-course.stepper.select-course.title',
8888
defaultMessage: 'Select Course',
8989
description: 'Title for the step to select course in the modal to import a course into a library.',
9090
},
9191
importCourseReviewDetailsStep: {
92-
id: 'course-authoring.library-authoring.import-course.review-details.title',
92+
id: 'course-authoring.library-authoring.import-course.stepper.review-details.title',
9393
defaultMessage: 'Review Import Details',
9494
description: 'Title for the step to review import details in the modal to import a course into a library.',
9595
},
9696
importCourseCalcel: {
97-
id: 'course-authoring.library-authoring.import-course.cancel.text',
97+
id: 'course-authoring.library-authoring.import-course.stepper.cancel.text',
9898
defaultMessage: 'Cancel',
9999
description: 'Label of the button to cancel the course import.',
100100
},
101101
importCourseNext: {
102-
id: 'course-authoring.library-authoring.import-course.next.text',
102+
id: 'course-authoring.library-authoring.import-course.stepper.next.text',
103103
defaultMessage: 'Next step',
104104
description: 'Label of the button go to the next step in the course import modal.',
105105
},
106106
importCourseBack: {
107-
id: 'course-authoring.library-authoring.import-course.back.text',
107+
id: 'course-authoring.library-authoring.import-course.stepper.back.text',
108108
defaultMessage: 'Back',
109109
description: 'Label of the button to go to the previous step in the course import modal.',
110110
},

src/library-authoring/import-course/stepper/ImportStepperModal.tsx

Lines changed: 0 additions & 94 deletions
This file was deleted.

src/library-authoring/import-course/stepper/ImportStepperModal.test.tsx renamed to src/library-authoring/import-course/stepper/ImportStepperPage.test.tsx

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,25 @@ import { type DeprecatedReduxState } from '@src/store';
1212
import studioHomeMock from '@src/studio-home/__mocks__/studioHomeMock';
1313
import { mockGetMigrationInfo } from '@src/studio-home/data/api.mocks';
1414
import { getCourseDetailsApiUrl } from '@src/course-outline/data/api';
15-
import { ImportStepperModal } from './ImportStepperModal';
15+
import { LibraryProvider } from '@src/library-authoring/common/context/LibraryContext';
16+
import { mockContentLibrary } from '@src/library-authoring/data/api.mocks';
17+
import { ImportStepperPage } from './ImportStepperPage';
1618

1719
let axiosMock;
1820
mockGetMigrationInfo.applyMock();
21+
mockContentLibrary.applyMock();
1922
type StudioHomeState = DeprecatedReduxState['studioHome'];
2023

21-
const libraryKey = 'lib:org:lib1';
22-
const mockOnClose = jest.fn();
24+
const libraryKey = mockContentLibrary.libraryId;
2325
const numPages = 1;
2426
const coursesCount = studioHomeMock.courses.length;
2527

28+
const mockNavigate = jest.fn();
29+
jest.mock('react-router-dom', () => ({
30+
...jest.requireActual('react-router-dom'),
31+
useNavigate: () => mockNavigate,
32+
}));
33+
2634
const renderComponent = (studioHomeState: Partial<StudioHomeState> = {}) => {
2735
// Generate a custom initial state based on studioHomeCoursesRequestParams
2836
const customInitialState: Partial<DeprecatedReduxState> = {
@@ -49,11 +57,16 @@ const renderComponent = (studioHomeState: Partial<StudioHomeState> = {}) => {
4957

5058
return {
5159
...render(
52-
<ImportStepperModal
53-
libraryKey={libraryKey}
54-
onClose={mockOnClose}
55-
isOpen
56-
/>,
60+
<ImportStepperPage />,
61+
{
62+
extraWrapper: ({ children }: { children: React.ReactNode }) => (
63+
<LibraryProvider libraryId={libraryKey}>
64+
{children}
65+
</LibraryProvider>
66+
),
67+
path: '/libraries/:libraryId/import/course',
68+
params: { libraryId: libraryKey },
69+
},
5770
),
5871
store,
5972
};
@@ -83,7 +96,7 @@ describe('<ImportStepperModal />', () => {
8396
const cancelButon = await screen.findByRole('button', { name: /cancel/i });
8497
await user.click(cancelButon);
8598

86-
expect(mockOnClose).toHaveBeenCalled();
99+
expect(mockNavigate).toHaveBeenCalled();
87100
});
88101

89102
it('should go to review import details step', async () => {

0 commit comments

Comments
 (0)