= ({
>
{(isCreateWorkflow || studioViewFinished) ? (
-
+
) : (
{
const [highlighted, setHighlighted] = React.useState(null);
const [
@@ -128,7 +129,10 @@ export const useVideoListProps = ({
},
selectBtnProps: {
onClick: () => {
- if (highlighted) {
+ /* istanbul ignore next */
+ if (returnFunction) {
+ returnFunction()();
+ } else if (highlighted) {
navigateTo(`/course/${learningContextId}/editor/video/${blockId}?selectedVideoId=${highlighted}`);
} else {
setShowSelectVideoError(true);
@@ -138,10 +142,15 @@ export const useVideoListProps = ({
};
};
-export const useVideoUploadHandler = ({ replace }) => {
+export const useVideoUploadHandler = ({ replace, uploadHandler }) => {
const learningContextId = useSelector(selectors.app.learningContextId);
const blockId = useSelector(selectors.app.blockId);
const path = `/course/${learningContextId}/editor/video_upload/${blockId}`;
+ if (uploadHandler) {
+ return () => {
+ uploadHandler();
+ };
+ }
if (replace) {
return () => window.location.replace(path);
}
@@ -191,11 +200,12 @@ export const getstatusBadgeVariant = ({ status }) => {
export const getStatusMessage = ({ status }) => Object.values(filterMessages).find((m) => m.defaultMessage === status);
-export const useVideoProps = ({ videos }) => {
+export const useVideoProps = ({ videos, uploadHandler, returnFunction }) => {
const searchSortProps = useSearchAndSortProps();
const videoList = useVideoListProps({
searchSortProps,
videos,
+ returnFunction,
});
const {
galleryError,
@@ -203,7 +213,7 @@ export const useVideoProps = ({ videos }) => {
inputError,
selectBtnProps,
} = videoList;
- const fileInput = { click: useVideoUploadHandler({ replace: false }) };
+ const fileInput = { click: useVideoUploadHandler({ replace: false, uploadHandler }) };
return {
galleryError,
diff --git a/src/editors/containers/VideoGallery/index.jsx b/src/editors/containers/VideoGallery/index.jsx
index 5f5a8a8ca8..ac25c85268 100644
--- a/src/editors/containers/VideoGallery/index.jsx
+++ b/src/editors/containers/VideoGallery/index.jsx
@@ -1,5 +1,10 @@
-import React, { useEffect } from 'react';
-import { Image } from '@openedx/paragon';
+import React, { useCallback, useEffect } from 'react';
+import PropTypes from 'prop-types';
+import { useIntl } from '@edx/frontend-platform/i18n';
+import {
+ Image, useToggle, StandardModal,
+} from '@openedx/paragon';
+import { useSearchParams } from 'react-router-dom';
import { useSelector } from 'react-redux';
import { selectors } from '../../data/redux';
import * as hooks from './hooks';
@@ -8,8 +13,11 @@ import { acceptedImgKeys } from './utils';
import messages from './messages';
import { RequestKeys } from '../../data/constants/requests';
import videoThumbnail from '../../data/images/videoThumbnail.svg';
+import VideoUploadEditor from '../VideoUploadEditor';
+import VideoEditor from '../VideoEditor';
-const VideoGallery = () => {
+const VideoGallery = ({ returnFunction, onCancel }) => {
+ const intl = useIntl();
const rawVideos = useSelector(selectors.app.videos);
const isLoaded = useSelector(
(state) => selectors.requests.isFinished(state, { requestKey: RequestKeys.fetchVideos }),
@@ -21,14 +29,27 @@ const VideoGallery = () => {
(state) => selectors.requests.isFailed(state, { requestKey: RequestKeys.uploadVideo }),
);
const videos = hooks.buildVideos({ rawVideos });
- const handleVideoUpload = hooks.useVideoUploadHandler({ replace: true });
+ const [isVideoUploadModalOpen, showVideoUploadModal, closeVideoUploadModal] = useToggle();
+ const [isVideoEditorModalOpen, showVideoEditorModal, closeVideoEditorModal] = useToggle();
+ const setSearchParams = useSearchParams()[1];
useEffect(() => {
- // If no videos exists redirects to the video upload screen
+ // If no videos exists opens to the video upload modal
if (isLoaded && videos.length === 0) {
- handleVideoUpload();
+ showVideoUploadModal();
}
}, [isLoaded]);
+
+ const onVideoUpload = useCallback((videoUrl) => {
+ closeVideoUploadModal();
+ showVideoEditorModal();
+ setSearchParams({ selectedVideoUrl: videoUrl });
+ }, [closeVideoUploadModal, showVideoEditorModal, setSearchParams]);
+
+ const uploadHandler = useCallback(() => {
+ showVideoUploadModal();
+ });
+
const {
galleryError,
inputError,
@@ -36,7 +57,7 @@ const VideoGallery = () => {
galleryProps,
searchSortProps,
selectBtnProps,
- } = hooks.useVideoProps({ videos });
+ } = hooks.useVideoProps({ videos, uploadHandler, returnFunction });
const handleCancel = hooks.useCancelHandler();
const modalMessages = {
@@ -60,8 +81,8 @@ const VideoGallery = () => {
{
isFetchError,
}}
/>
+
+
+
+
+
+ {isVideoEditorModalOpen && (
+
+ )}
);
};
-VideoGallery.propTypes = {};
+VideoGallery.propTypes = {
+ onCancel: PropTypes.func,
+ returnFunction: PropTypes.func,
+};
export default VideoGallery;
diff --git a/src/editors/containers/VideoGallery/index.test.jsx b/src/editors/containers/VideoGallery/index.test.jsx
index 1cffffea82..6e45a02d27 100644
--- a/src/editors/containers/VideoGallery/index.test.jsx
+++ b/src/editors/containers/VideoGallery/index.test.jsx
@@ -6,6 +6,8 @@ import React from 'react';
import {
act, fireEvent, render, screen,
} from '@testing-library/react';
+import * as reactRouterDom from 'react-router-dom';
+import * as reduxThunks from '../../data/redux';
import VideoGallery from './index';
@@ -120,11 +122,10 @@ describe('VideoGallery', () => {
expect(screen.getByText(video.client_video_id)).toBeInTheDocument()
));
});
- it('navigates to video upload page when there are no videos', async () => {
- expect(window.location.replace).not.toHaveBeenCalled();
+ it('renders video upload modal when there are no videos', async () => {
updateState({ videos: [] });
await renderComponent();
- expect(window.location.replace).toHaveBeenCalled();
+ expect(screen.getByRole('heading', { name: /upload or embed a new video/i })).toBeInTheDocument();
});
it.each([
[/newest/i, [2, 1, 3]],
@@ -191,5 +192,36 @@ describe('VideoGallery', () => {
expect(screen.queryByText('client_id_1')).not.toBeInTheDocument();
expect(screen.queryByText('client_id_3')).not.toBeInTheDocument();
});
+
+ it('calls onVideoUpload correctly when a video is uploaded', async () => {
+ // Mock useSearchParams
+ const setSearchParams = jest.fn();
+ jest.spyOn(reactRouterDom, 'useSearchParams').mockReturnValue([{}, setSearchParams]);
+
+ // Mock the uploadVideo thunk to immediately call postUploadRedirect
+ jest.spyOn(reduxThunks.thunkActions.video, 'uploadVideo').mockImplementation(
+ ({ postUploadRedirect }) => () => {
+ if (postUploadRedirect) {
+ postUploadRedirect('http://test.video/url.mp4');
+ }
+ return { type: 'MOCK_UPLOAD_VIDEO' };
+ },
+ );
+
+ await renderComponent();
+
+ // Open the upload modal by clicking the button
+ const openModalButton = screen.getByRole('button', { name: /upload or embed a new video/i });
+ fireEvent.click(openModalButton);
+
+ // Wait for the input to appear in the modal
+ const urlInput = await screen.findByPlaceholderText('Paste your video ID or URL');
+ fireEvent.change(urlInput, { target: { value: 'http://test.video/url.mp4' } });
+
+ const submitButton = screen.getByRole('button', { name: /submit/i });
+ fireEvent.click(submitButton);
+
+ expect(setSearchParams).toHaveBeenCalledWith({ selectedVideoUrl: 'http://test.video/url.mp4' });
+ });
});
});
diff --git a/src/editors/containers/VideoGallery/messages.js b/src/editors/containers/VideoGallery/messages.js
index e26dd63db3..3dd446b7c9 100644
--- a/src/editors/containers/VideoGallery/messages.js
+++ b/src/editors/containers/VideoGallery/messages.js
@@ -21,7 +21,16 @@ const messages = {
defaultMessage: 'Upload or embed a new video',
description: 'Label for upload button',
},
-
+ videoUploadModalTitle: {
+ id: 'authoring.selectvideomodal.upload.title',
+ defaultMessage: 'Upload or embed a new video',
+ description: 'Label for upload modal',
+ },
+ videoEditorModalTitle: {
+ id: 'authoring.selectvideomodal.edit.title',
+ defaultMessage: 'Edit selected video',
+ description: 'Label for editor modal',
+ },
// Sort Dropdown
sortByDateNewest: {
id: 'authoring.selectvideomodal.sort.datenewest.label',
diff --git a/src/editors/containers/VideoUploadEditor/VideoUploader.jsx b/src/editors/containers/VideoUploadEditor/VideoUploader.jsx
index 028d1c085a..09d943db83 100644
--- a/src/editors/containers/VideoUploadEditor/VideoUploader.jsx
+++ b/src/editors/containers/VideoUploadEditor/VideoUploader.jsx
@@ -10,9 +10,9 @@ import { thunkActions } from '../../data/redux';
import * as hooks from './hooks';
import messages from './messages';
-const URLUploader = () => {
+const URLUploader = ({ onUpload }) => {
const [textInputValue, setTextInputValue] = React.useState('');
- const onURLUpload = hooks.onVideoUpload('selectedVideoUrl');
+ const onURLUpload = hooks.onVideoUpload('selectedVideoUrl', onUpload);
const intl = useIntl();
return (
@@ -58,16 +58,16 @@ const URLUploader = () => {
);
};
-export const VideoUploader = ({ setLoading }) => {
+export const VideoUploader = ({ setLoading, onUpload, onClose }) => {
const dispatch = useDispatch();
const intl = useIntl();
- const goBack = hooks.useHistoryGoBack();
+ const goBack = onClose || hooks.useHistoryGoBack();
const handleProcessUpload = ({ fileData }) => {
dispatch(thunkActions.video.uploadVideo({
supportedFiles: [fileData],
setLoadSpinner: setLoading,
- postUploadRedirect: hooks.onVideoUpload('selectedVideoId'),
+ postUploadRedirect: hooks.onVideoUpload('selectedVideoId', onUpload),
}));
};
@@ -85,14 +85,20 @@ export const VideoUploader = ({ setLoading }) => {
}
+ inputComponent={}
/>
);
};
+URLUploader.propTypes = {
+ onUpload: PropTypes.func,
+};
+
VideoUploader.propTypes = {
setLoading: PropTypes.func.isRequired,
+ onUpload: PropTypes.func,
+ onClose: PropTypes.func,
};
export default VideoUploader;
diff --git a/src/editors/containers/VideoUploadEditor/hooks.js b/src/editors/containers/VideoUploadEditor/hooks.js
index a2774d9c60..3cc1f8468e 100644
--- a/src/editors/containers/VideoUploadEditor/hooks.js
+++ b/src/editors/containers/VideoUploadEditor/hooks.js
@@ -11,15 +11,20 @@ export const {
navigateTo,
} = appHooks;
-export const postUploadRedirect = (storeState, uploadType = 'selectedVideoUrl') => {
+export const postUploadRedirect = (storeState, uploadType = 'selectedVideoUrl', onUpload = null) => {
const learningContextId = selectors.app.learningContextId(storeState);
const blockId = selectors.app.blockId(storeState);
+ if (onUpload) {
+ return (videoUrl) => {
+ onUpload(videoUrl, learningContextId, blockId);
+ };
+ }
return (videoUrl) => navigateTo(`/course/${learningContextId}/editor/video/${blockId}?${uploadType}=${videoUrl}`);
};
-export const onVideoUpload = (uploadType) => {
+export const onVideoUpload = (uploadType, onUpload) => {
const storeState = store.getState();
- return module.postUploadRedirect(storeState, uploadType);
+ return module.postUploadRedirect(storeState, uploadType, onUpload);
};
export const useUploadVideo = async ({
diff --git a/src/editors/containers/VideoUploadEditor/index.jsx b/src/editors/containers/VideoUploadEditor/index.jsx
index ae2be7b5fb..91664d3e0a 100644
--- a/src/editors/containers/VideoUploadEditor/index.jsx
+++ b/src/editors/containers/VideoUploadEditor/index.jsx
@@ -1,17 +1,18 @@
import React from 'react';
+import PropTypes from 'prop-types';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Spinner } from '@openedx/paragon';
import './index.scss';
import messages from './messages';
import { VideoUploader } from './VideoUploader';
-const VideoUploadEditor = () => {
+const VideoUploadEditor = ({ onUpload, onClose }) => {
const [loading, setLoading] = React.useState(false);
const intl = useIntl();
return (!loading) ? (
-
+
) : (
{
);
};
+VideoUploadEditor.propTypes = {
+ onUpload: PropTypes.func,
+ onClose: PropTypes.func,
+};
+
export default VideoUploadEditor;
diff --git a/src/editors/data/redux/thunkActions/app.js b/src/editors/data/redux/thunkActions/app.js
index 8da9f24b71..4c5079a5a9 100644
--- a/src/editors/data/redux/thunkActions/app.js
+++ b/src/editors/data/redux/thunkActions/app.js
@@ -125,6 +125,16 @@ export const saveBlock = (content, returnToUnit) => (dispatch) => {
content,
onSuccess: (response) => {
dispatch(actions.app.setSaveResponse(response));
+ const parsedData = JSON.parse(response.config.data);
+ if (parsedData?.has_changes) {
+ const storageKey = 'courseRefreshTriggerOnComponentEditSave';
+ localStorage.setItem(storageKey, Date.now());
+
+ window.dispatchEvent(new StorageEvent('storage', {
+ key: storageKey,
+ newValue: Date.now().toString(),
+ }));
+ }
returnToUnit(response.data);
},
}));
diff --git a/src/editors/data/redux/thunkActions/app.test.js b/src/editors/data/redux/thunkActions/app.test.js
index 35debc7f3c..3f8dc10c9e 100644
--- a/src/editors/data/redux/thunkActions/app.test.js
+++ b/src/editors/data/redux/thunkActions/app.test.js
@@ -352,7 +352,11 @@ describe('app thunkActions', () => {
});
it('dispatches actions.app.setSaveResponse with response and then calls returnToUnit', () => {
dispatch.mockClear();
- const response = 'testRESPONSE';
+ const mockParsedData = { has_changes: true };
+ const response = {
+ config: { data: JSON.stringify(mockParsedData) },
+ data: {},
+ };
calls[1][0].saveBlock.onSuccess(response);
expect(dispatch).toHaveBeenCalledWith(actions.app.setSaveResponse(response));
expect(returnToUnit).toHaveBeenCalled();
diff --git a/src/editors/data/redux/thunkActions/problem.test.ts b/src/editors/data/redux/thunkActions/problem.test.ts
index 17f7f85b0a..3c7edbe52c 100644
--- a/src/editors/data/redux/thunkActions/problem.test.ts
+++ b/src/editors/data/redux/thunkActions/problem.test.ts
@@ -10,7 +10,6 @@ import {
} from './problem';
import { checkboxesOLXWithFeedbackAndHintsOLX, advancedProblemOlX, blankProblemOLX } from '../../../containers/ProblemEditor/data/mockData/olxTestData';
import { ProblemTypeKeys } from '../../constants/problem';
-import * as requests from './requests';
const mockOlx = 'SOmEVALue';
const mockBuildOlx = jest.fn(() => mockOlx);
@@ -72,22 +71,13 @@ describe('problem thunkActions', () => {
);
});
test('switchToMarkdownEditor dispatches correct actions', () => {
- switchToMarkdownEditor()(dispatch, getState);
+ switchToMarkdownEditor()(dispatch);
expect(dispatch).toHaveBeenCalledWith(
actions.problem.updateField({
isMarkdownEditorEnabled: true,
}),
);
-
- expect(dispatch).toHaveBeenCalledWith(
- requests.saveBlock({
- content: {
- settings: { markdown_edited: true },
- olx: blockValue.data.data,
- },
- }),
- );
});
describe('switchEditor', () => {
@@ -110,7 +100,7 @@ describe('problem thunkActions', () => {
test('dispatches switchToMarkdownEditor when editorType is markdown', () => {
switchEditor('markdown')(dispatch, getState);
- expect(switchToMarkdownEditorMock).toHaveBeenCalledWith(dispatch, getState);
+ expect(switchToMarkdownEditorMock).toHaveBeenCalledWith(dispatch);
});
});
diff --git a/src/editors/data/redux/thunkActions/problem.ts b/src/editors/data/redux/thunkActions/problem.ts
index 28ba7b34fc..74876fdb1d 100644
--- a/src/editors/data/redux/thunkActions/problem.ts
+++ b/src/editors/data/redux/thunkActions/problem.ts
@@ -24,17 +24,17 @@ export const switchToAdvancedEditor = () => (dispatch, getState) => {
dispatch(actions.problem.updateField({ problemType: ProblemTypeKeys.ADVANCED, rawOLX }));
};
-export const switchToMarkdownEditor = () => (dispatch, getState) => {
- const state = getState();
+export const switchToMarkdownEditor = () => (dispatch) => {
dispatch(actions.problem.updateField({ isMarkdownEditorEnabled: true }));
- const { blockValue } = state.app;
- const olx = get(blockValue, 'data.data', '');
- const content = { settings: { markdown_edited: true }, olx };
- // Sending a request to save the problem block with the updated markdown_edited value
- dispatch(requests.saveBlock({ content }));
};
-export const switchEditor = (editorType) => (dispatch, getState) => (editorType === 'advanced' ? switchToAdvancedEditor : switchToMarkdownEditor)()(dispatch, getState);
+export const switchEditor = (editorType) => (dispatch, getState) => {
+ if (editorType === 'advanced') {
+ switchToAdvancedEditor()(dispatch, getState);
+ } else {
+ switchToMarkdownEditor()(dispatch);
+ }
+};
export const isBlankProblem = ({ rawOLX }) => {
if (['
', '
'].includes(rawOLX.replace(/\s/g, ''))) {
diff --git a/src/editors/sharedComponents/CodeEditor/hooks.js b/src/editors/sharedComponents/CodeEditor/hooks.js
index 0eb25a7cc0..9fb92ca1bc 100644
--- a/src/editors/sharedComponents/CodeEditor/hooks.js
+++ b/src/editors/sharedComponents/CodeEditor/hooks.js
@@ -100,7 +100,7 @@ export const createCodeMirrorDomNode = ({
}) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
useEffect(() => {
- const languageExtension = CODEMIRROR_LANGUAGES[lang]();
+ const languageExtension = CODEMIRROR_LANGUAGES[lang] ? CODEMIRROR_LANGUAGES[lang]() : xml();
const cleanText = cleanHTML({ initialText });
const newState = EditorState.create({
doc: cleanText,
@@ -115,13 +115,25 @@ export const createCodeMirrorDomNode = ({
],
});
const view = new EditorView({ state: newState, parent: ref.current });
- // eslint-disable-next-line no-param-reassign
- upstreamRef.current = view;
+
+ if (typeof upstreamRef === 'function') {
+ upstreamRef(view);
+ } else if (upstreamRef) {
+ // eslint-disable-next-line no-param-reassign
+ upstreamRef.current = view;
+ }
+
view.focus();
return () => {
// called on cleanup
view.destroy();
+ if (typeof upstreamRef === 'function') {
+ upstreamRef(null);
+ } else if (upstreamRef) {
+ // eslint-disable-next-line no-param-reassign
+ upstreamRef.current = null;
+ }
};
}, []);
};
diff --git a/src/editors/sharedComponents/SourceCodeModal/__snapshots__/index.test.jsx.snap b/src/editors/sharedComponents/SourceCodeModal/__snapshots__/index.test.jsx.snap
index 94cfe04497..91ea6175ac 100644
--- a/src/editors/sharedComponents/SourceCodeModal/__snapshots__/index.test.jsx.snap
+++ b/src/editors/sharedComponents/SourceCodeModal/__snapshots__/index.test.jsx.snap
@@ -41,6 +41,7 @@ exports[`SourceCodeModal renders as expected with default behavior 1`] = `
>
diff --git a/src/editors/sharedComponents/SourceCodeModal/index.jsx b/src/editors/sharedComponents/SourceCodeModal/index.jsx
index 88f7ff9f8e..9282a180c4 100644
--- a/src/editors/sharedComponents/SourceCodeModal/index.jsx
+++ b/src/editors/sharedComponents/SourceCodeModal/index.jsx
@@ -1,4 +1,3 @@
-import React from 'react';
import PropTypes from 'prop-types';
import {
@@ -41,6 +40,7 @@ const SourceCodeModal = ({
diff --git a/src/editors/sharedComponents/TinyMceWidget/hooks.js b/src/editors/sharedComponents/TinyMceWidget/hooks.js
index 5afbba011c..3730e809b5 100644
--- a/src/editors/sharedComponents/TinyMceWidget/hooks.js
+++ b/src/editors/sharedComponents/TinyMceWidget/hooks.js
@@ -304,6 +304,7 @@ export const editorConfig = ({
updateContent,
content,
minHeight,
+ maxHeight,
learningContextId,
staticRootUrl,
enableImageUpload,
@@ -335,6 +336,7 @@ export const editorConfig = ({
content_css: false,
content_style: tinyMCEStyles + a11ycheckerCss,
min_height: minHeight,
+ max_height: maxHeight,
contextmenu: 'link table',
directionality: isLocaleRtl ? 'rtl' : 'ltr',
document_base_url: baseURL,
diff --git a/src/files-and-videos/files-page/FilesPage.jsx b/src/files-and-videos/files-page/FilesPage.jsx
index be100bd55b..eee448d73d 100644
--- a/src/files-and-videos/files-page/FilesPage.jsx
+++ b/src/files-and-videos/files-page/FilesPage.jsx
@@ -32,6 +32,7 @@ import { getFileSizeToClosestByte } from '../../utils';
import FileThumbnail from './FileThumbnail';
import FileInfoModalSidebar from './FileInfoModalSidebar';
import FileValidationModal from './FileValidationModal';
+import './FilesPage.scss';
const FilesPage = ({
courseId,
diff --git a/src/files-and-videos/files-page/FilesPage.scss b/src/files-and-videos/files-page/FilesPage.scss
new file mode 100644
index 0000000000..6b27f995ae
--- /dev/null
+++ b/src/files-and-videos/files-page/FilesPage.scss
@@ -0,0 +1,5 @@
+.files-table {
+ .pgn__data-table-container {
+ overflow-x: visible;
+ }
+}
diff --git a/src/files-and-videos/files-page/FilesPage.test.jsx b/src/files-and-videos/files-page/FilesPage.test.jsx
index 80bb8f1f8c..948d36a35e 100644
--- a/src/files-and-videos/files-page/FilesPage.test.jsx
+++ b/src/files-and-videos/files-page/FilesPage.test.jsx
@@ -70,15 +70,6 @@ const mockStore = async (
}
renderComponent();
await executeThunk(fetchAssets(courseId), store.dispatch);
-
- // Finish loading the expected files into the data table before returning,
- // because loading new files can disrupt things like accessing file menus.
- if (status === RequestStatus.SUCCESSFUL) {
- const numFiles = skipNextPageFetch ? 13 : 15;
- await waitFor(() => {
- expect(screen.getByText(`Showing ${numFiles} of ${numFiles}`)).toBeInTheDocument();
- });
- }
};
const emptyMockStore = async (status) => {
diff --git a/src/files-and-videos/files-page/data/slice.js b/src/files-and-videos/files-page/data/slice.js
index 3a96779185..4fbe4915c9 100644
--- a/src/files-and-videos/files-page/data/slice.js
+++ b/src/files-and-videos/files-page/data/slice.js
@@ -28,7 +28,7 @@ const slice = createSlice({
if (isEmpty(state.assetIds)) {
state.assetIds = payload.assetIds;
} else {
- state.assetIds = [...state.assetIds, ...payload.assetIds];
+ state.assetIds = [...new Set([...state.assetIds, ...payload.assetIds])];
}
},
setSortedAssetIds: (state, { payload }) => {
diff --git a/src/files-and-videos/generic/DeleteConfirmationModal.jsx b/src/files-and-videos/generic/DeleteConfirmationModal.jsx
index bbcb3ab7e1..ffea226564 100644
--- a/src/files-and-videos/generic/DeleteConfirmationModal.jsx
+++ b/src/files-and-videos/generic/DeleteConfirmationModal.jsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { getConfig } from '@edx/frontend-platform';
@@ -7,6 +7,7 @@ import {
AlertModal,
Button,
Collapsible,
+ DataTableContext,
Hyperlink,
Truncate,
} from '@openedx/paragon';
@@ -22,6 +23,13 @@ const DeleteConfirmationModal = ({
// injected
intl,
}) => {
+ const { clearSelection } = useContext(DataTableContext);
+
+ const handleConfirmDeletion = () => {
+ handleBulkDelete();
+ clearSelection();
+ };
+
const firstSelectedRow = selectedRows[0]?.original;
let activeContentRows = [];
if (Array.isArray(selectedRows)) {
@@ -73,7 +81,7 @@ const DeleteConfirmationModal = ({
-