diff --git a/src/course-outline/CourseOutline.jsx b/src/course-outline/CourseOutline.jsx
index fe428c1c7..28e8dd4b2 100644
--- a/src/course-outline/CourseOutline.jsx
+++ b/src/course-outline/CourseOutline.jsx
@@ -104,7 +104,6 @@ const CourseOutline = ({ courseId }) => {
handleNewUnitSubmit,
getUnitUrl,
handleVideoSharingOptionChange,
- handleCopyToClipboardClick,
handlePasteClipboardClick,
notificationDismissUrl,
discussionsSettings,
@@ -397,7 +396,6 @@ const CourseOutline = ({ courseId }) => {
onDuplicateSubmit={handleDuplicateUnitSubmit}
getTitleLink={getUnitUrl}
onOrderChange={updateUnitOrderByIndex}
- onCopyToClipboardClick={handleCopyToClipboardClick}
discussionsSettings={discussionsSettings}
/>
))}
diff --git a/src/course-outline/CourseOutline.test.jsx b/src/course-outline/CourseOutline.test.jsx
index b7f8332ee..cdb4739c3 100644
--- a/src/course-outline/CourseOutline.test.jsx
+++ b/src/course-outline/CourseOutline.test.jsx
@@ -2182,9 +2182,6 @@ describe('', () => {
.onPost(getClipboardUrl(), {
usage_key: unit.id,
}).reply(200, clipboardUnit);
- // check that initialUserClipboard state is empty
- const { initialUserClipboard } = store.getState().courseOutline;
- expect(initialUserClipboard).toBeUndefined();
// find menu button and click on it to open menu
const menu = await within(unitElement).findByTestId('unit-card-header__menu-button');
@@ -2194,9 +2191,6 @@ describe('', () => {
const copyButton = await within(unitElement).findByText(cardHeaderMessages.menuCopy.defaultMessage);
await act(async () => fireEvent.click(copyButton));
- // check that initialUserClipboard state is updated
- expect(store.getState().generic.clipboardData).toEqual(clipboardUnit);
-
[subsectionElement] = await within(sectionElement).findAllByTestId('subsection-card');
// find clipboard content label
const clipboardLabel = await within(subsectionElement).findByText(
diff --git a/src/course-outline/data/api.js b/src/course-outline/data/api.js
index fc61f3c11..bd2c95254 100644
--- a/src/course-outline/data/api.js
+++ b/src/course-outline/data/api.js
@@ -28,7 +28,6 @@ export const getCourseReindexApiUrl = (reindexLink) => `${getApiBaseUrl()}${rein
export const getXBlockBaseApiUrl = () => `${getApiBaseUrl()}/xblock/`;
export const getCourseItemApiUrl = (itemId) => `${getXBlockBaseApiUrl()}${itemId}`;
export const getXBlockApiUrl = (blockId) => `${getXBlockBaseApiUrl()}outline/${blockId}`;
-export const getClipboardUrl = () => `${getApiBaseUrl()}/api/content-staging/v1/clipboard/`;
export const exportTags = (courseId) => `${getApiBaseUrl()}/api/content_tagging/v1/object_tags/${courseId}/export/`;
/**
diff --git a/src/course-outline/data/thunk.js b/src/course-outline/data/thunk.js
index 315c5846c..c4cebdc44 100644
--- a/src/course-outline/data/thunk.js
+++ b/src/course-outline/data/thunk.js
@@ -1,5 +1,4 @@
import { RequestStatus } from '../../data/constants';
-import { updateClipboardData } from '../../generic/data/slice';
import { NOTIFICATION_MESSAGES } from '../../constants';
import { API_ERROR_TYPES, COURSE_BLOCK_NAMES } from '../constants';
import {
@@ -88,7 +87,6 @@ export function fetchCourseOutlineIndexQuery(courseId) {
},
} = outlineIndex;
dispatch(fetchOutlineIndexSuccess(outlineIndex));
- dispatch(updateClipboardData(outlineIndex.initialUserClipboard));
dispatch(updateStatusBar({
courseReleaseDate,
highlightsEnabledForMessaging,
diff --git a/src/course-outline/hooks.jsx b/src/course-outline/hooks.jsx
index 25b9d8bed..51e003761 100644
--- a/src/course-outline/hooks.jsx
+++ b/src/course-outline/hooks.jsx
@@ -4,7 +4,6 @@ import { useNavigate } from 'react-router-dom';
import { useToggle } from '@openedx/paragon';
import { getConfig } from '@edx/frontend-platform';
-import { copyToClipboard } from '../generic/data/thunks';
import { getSavingStatus as getGenericSavingStatus } from '../generic/data/selectors';
import { RequestStatus } from '../data/constants';
import { COURSE_BLOCK_NAMES } from './constants';
@@ -72,6 +71,7 @@ const useCourseOutline = ({ courseId }) => {
mfeProctoredExamSettingsUrl,
advanceSettingsUrl,
} = useSelector(getOutlineIndexData);
+
const { outlineIndexLoadingStatus, reIndexLoadingStatus } = useSelector(getLoadingStatus);
const statusBarData = useSelector(getStatusBarData);
const savingStatus = useSelector(getSavingStatus);
@@ -95,10 +95,6 @@ const useCourseOutline = ({ courseId }) => {
const isSavingStatusFailed = savingStatus === RequestStatus.FAILED || genericSavingStatus === RequestStatus.FAILED;
- const handleCopyToClipboardClick = (usageKey) => {
- dispatch(copyToClipboard(usageKey));
- };
-
const handlePasteClipboardClick = (parentLocator, sectionId) => {
dispatch(pasteClipboardContent(parentLocator, sectionId));
};
@@ -339,7 +335,6 @@ const useCourseOutline = ({ courseId }) => {
openUnitPage,
handleNewUnitSubmit,
handleVideoSharingOptionChange,
- handleCopyToClipboardClick,
handlePasteClipboardClick,
notificationDismissUrl,
discussionsSettings,
diff --git a/src/course-outline/subsection-card/SubsectionCard.jsx b/src/course-outline/subsection-card/SubsectionCard.jsx
index 9f134fdbe..032178618 100644
--- a/src/course-outline/subsection-card/SubsectionCard.jsx
+++ b/src/course-outline/subsection-card/SubsectionCard.jsx
@@ -16,7 +16,7 @@ import { RequestStatus } from '../../data/constants';
import CardHeader from '../card-header/CardHeader';
import SortableItem from '../../generic/drag-helper/SortableItem';
import { DragContext } from '../../generic/drag-helper/DragContextProvider';
-import { useCopyToClipboard, PasteComponent } from '../../generic/clipboard';
+import { useClipboard, PasteComponent } from '../../generic/clipboard';
import TitleButton from '../card-header/TitleButton';
import XBlockStatus from '../xblock-status/XBlockStatus';
import { getItemStatus, getItemStatusBorder, scrollToElement } from '../utils';
@@ -49,7 +49,7 @@ const SubsectionCard = ({
const isScrolledToElement = locatorId === subsection.id;
const [isFormOpen, openForm, closeForm] = useToggle(false);
const namePrefix = 'subsection';
- const { sharedClipboardData, showPasteUnit } = useCopyToClipboard();
+ const { sharedClipboardData, showPasteUnit } = useClipboard();
const {
id,
@@ -233,7 +233,7 @@ const SubsectionCard = ({
>
{intl.formatMessage(messages.newUnitButton)}
- {enableCopyPasteUnits && showPasteUnit && (
+ {enableCopyPasteUnits && showPasteUnit && sharedClipboardData && (
{
const currentRef = useRef(null);
@@ -41,6 +41,8 @@ const UnitCard = ({
const [isFormOpen, openForm, closeForm] = useToggle(false);
const namePrefix = 'unit';
+ const { copyToClipboard } = useClipboard();
+
const {
id,
category,
@@ -98,7 +100,7 @@ const UnitCard = ({
};
const handleCopyClick = () => {
- onCopyToClipboardClick(unit.id);
+ copyToClipboard(id);
};
const titleComponent = (
@@ -241,7 +243,6 @@ UnitCard.propTypes = {
onOrderChange: PropTypes.func.isRequired,
isSelfPaced: PropTypes.bool.isRequired,
isCustomRelativeDatesActive: PropTypes.bool.isRequired,
- onCopyToClipboardClick: PropTypes.func.isRequired,
discussionsSettings: PropTypes.shape({
providerType: PropTypes.string,
enableGradedUnits: PropTypes.bool,
diff --git a/src/course-outline/unit-card/UnitCard.test.jsx b/src/course-outline/unit-card/UnitCard.test.jsx
index 192963375..db0ed71aa 100644
--- a/src/course-outline/unit-card/UnitCard.test.jsx
+++ b/src/course-outline/unit-card/UnitCard.test.jsx
@@ -1,4 +1,3 @@
-import React from 'react';
import {
act, render, fireEvent, within,
} from '@testing-library/react';
@@ -48,6 +47,13 @@ const unit = {
const queryClient = new QueryClient();
+const clipboardBroadcastChannelMock = {
+ postMessage: jest.fn(),
+ close: jest.fn(),
+};
+
+global.BroadcastChannel = jest.fn(() => clipboardBroadcastChannelMock);
+
const renderComponent = (props) => render(
@@ -62,7 +68,6 @@ const renderComponent = (props) => render(
onOpenPublishModal={jest.fn()}
onOpenDeleteModal={jest.fn()}
onOpenConfigureModal={jest.fn()}
- onCopyToClipboardClick={jest.fn()}
savingStatus=""
onEditSubmit={jest.fn()}
onDuplicateSubmit={jest.fn()}
diff --git a/src/course-unit/CourseUnit.jsx b/src/course-unit/CourseUnit.jsx
index 2b54f876e..e6fb60dd8 100644
--- a/src/course-unit/CourseUnit.jsx
+++ b/src/course-unit/CourseUnit.jsx
@@ -185,7 +185,9 @@ const CourseUnit = ({ courseId }) => {
{showPasteXBlock && canPasteComponent && (
handleCreateNewCourseXBlock({ stagedContent: 'clipboard', parentLocator: blockId })
+ }
text={intl.formatMessage(messages.pasteButtonText)}
/>
)}
diff --git a/src/course-unit/CourseUnit.test.jsx b/src/course-unit/CourseUnit.test.jsx
index d6b00a385..85115bd99 100644
--- a/src/course-unit/CourseUnit.test.jsx
+++ b/src/course-unit/CourseUnit.test.jsx
@@ -1,4 +1,5 @@
import MockAdapter from 'axios-mock-adapter';
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import {
act, render, waitFor, fireEvent, within, screen,
} from '@testing-library/react';
@@ -38,10 +39,7 @@ import {
courseVerticalChildrenMock,
clipboardMockResponse,
} from './__mocks__';
-import {
- clipboardUnit,
- clipboardXBlock,
-} from '../__mocks__';
+import { clipboardUnit, clipboardXBlock } from '../__mocks__';
import { executeThunk } from '../utils';
import deleteModalMessages from '../generic/delete-modal/messages';
import pasteComponentMessages from '../generic/clipboard/paste-component/messages';
@@ -54,6 +52,7 @@ import { extractCourseUnitId } from './sidebar/utils';
import CourseUnit from './CourseUnit';
import configureModalMessages from '../generic/configure-modal/messages';
+import { getClipboardUrl } from '../generic/data/api';
import courseXBlockMessages from './course-xblock/messages';
import addComponentMessages from './add-component/messages';
import { PUBLISH_TYPES, UNIT_VISIBILITY_STATES } from './constants';
@@ -63,6 +62,7 @@ import { RequestStatus } from '../data/constants';
let axiosMock;
let store;
+let queryClient;
const courseId = '123';
const blockId = '567890';
const unitDisplayName = courseUnitIndexMock.metadata.display_name;
@@ -80,31 +80,6 @@ jest.mock('react-router-dom', () => ({
useNavigate: () => mockedUsedNavigate,
}));
-jest.mock('@tanstack/react-query', () => ({
- useQuery: jest.fn(({ queryKey }) => {
- if (queryKey[0] === 'contentTaxonomyTags') {
- return {
- data: {
- taxonomies: [],
- },
- isSuccess: true,
- };
- } if (queryKey[0] === 'contentTagsCount') {
- return {
- data: 17,
- isSuccess: true,
- };
- }
- return {
- data: {},
- isSuccess: true,
- };
- }),
- useQueryClient: jest.fn(() => ({
- setQueryData: jest.fn(),
- })),
-}));
-
const clipboardBroadcastChannelMock = {
postMessage: jest.fn(),
close: jest.fn(),
@@ -115,7 +90,9 @@ global.BroadcastChannel = jest.fn(() => clipboardBroadcastChannelMock);
const RootWrapper = () => (
-
+
+
+
);
@@ -132,7 +109,17 @@ describe('', () => {
});
global.localStorage.clear();
store = initializeStore();
+ queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ retry: false,
+ },
+ },
+ });
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
+ axiosMock
+ .onGet(getClipboardUrl())
+ .reply(200, clipboardUnit);
axiosMock
.onGet(getCourseUnitApiUrl(courseId))
.reply(200, courseUnitIndexMock);
@@ -147,7 +134,7 @@ describe('', () => {
await executeThunk(fetchCourseVerticalChildrenData(blockId), store.dispatch);
axiosMock
.onGet(getContentTaxonomyTagsApiUrl(blockId))
- .reply(200, {});
+ .reply(200, { taxonomies: [] });
axiosMock
.onGet(getContentTaxonomyTagsCountApiUrl(blockId))
.reply(200, 17);
@@ -1087,19 +1074,16 @@ describe('', () => {
queryByTestId, getByRole, getAllByLabelText, getByText,
} = render();
+ axiosMock
+ .onGet(getClipboardUrl())
+ .reply(200, clipboardXBlock);
+
await waitFor(() => {
const [xblockActionBtn] = getAllByLabelText(courseXBlockMessages.blockActionsDropdownAlt.defaultMessage);
userEvent.click(xblockActionBtn);
userEvent.click(getByRole('button', { name: courseXBlockMessages.blockLabelButtonCopyToClipboard.defaultMessage }));
});
- axiosMock
- .onGet(getCourseSectionVerticalApiUrl(blockId))
- .reply(200, {
- ...courseSectionVerticalMock,
- user_clipboard: clipboardXBlock,
- });
-
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
expect(getByRole('button', { name: messages.pasteButtonText.defaultMessage })).toBeInTheDocument();
@@ -1141,11 +1125,8 @@ describe('', () => {
});
axiosMock
- .onGet(getCourseSectionVerticalApiUrl(blockId))
- .reply(200, {
- ...courseSectionVerticalMock,
- user_clipboard: clipboardXBlock,
- });
+ .onGet(getClipboardUrl())
+ .reply(200, clipboardXBlock);
axiosMock
.onGet(getCourseUnitApiUrl(courseId))
@@ -1197,11 +1178,8 @@ describe('', () => {
});
axiosMock
- .onGet(getCourseSectionVerticalApiUrl(blockId))
- .reply(200, {
- ...courseSectionVerticalMock,
- user_clipboard: clipboardXBlock,
- });
+ .onGet(getClipboardUrl())
+ .reply(200, clipboardXBlock);
axiosMock
.onGet(getCourseUnitApiUrl(courseId))
@@ -1228,13 +1206,6 @@ describe('', () => {
enable_copy_paste_units: true,
});
- axiosMock
- .onGet(getCourseSectionVerticalApiUrl(blockId))
- .reply(200, {
- ...courseSectionVerticalMock,
- user_clipboard: clipboardUnit,
- });
-
await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch);
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
@@ -1288,13 +1259,6 @@ describe('', () => {
enable_copy_paste_units: true,
});
- axiosMock
- .onGet(getCourseSectionVerticalApiUrl(blockId))
- .reply(200, {
- ...courseSectionVerticalMock,
- user_clipboard: clipboardUnit,
- });
-
await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch);
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
@@ -1349,13 +1313,6 @@ describe('', () => {
enable_copy_paste_units: true,
});
- axiosMock
- .onGet(getCourseSectionVerticalApiUrl(blockId))
- .reply(200, {
- ...courseSectionVerticalMock,
- user_clipboard: clipboardUnit,
- });
-
await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch);
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
@@ -1410,13 +1367,6 @@ describe('', () => {
enable_copy_paste_units: true,
});
- axiosMock
- .onGet(getCourseSectionVerticalApiUrl(blockId))
- .reply(200, {
- ...courseSectionVerticalMock,
- user_clipboard: clipboardUnit,
- });
-
await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch);
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
diff --git a/src/course-unit/course-xblock/CourseXBlock.jsx b/src/course-unit/course-xblock/CourseXBlock.jsx
index 89a13ece7..ddba7397e 100644
--- a/src/course-unit/course-xblock/CourseXBlock.jsx
+++ b/src/course-unit/course-xblock/CourseXBlock.jsx
@@ -1,7 +1,7 @@
import { useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
-import { useDispatch, useSelector } from 'react-redux';
+import { useSelector } from 'react-redux';
import {
ActionRow, Card, Dropdown, Icon, IconButton, useToggle,
} from '@openedx/paragon';
@@ -15,7 +15,7 @@ import ConfigureModal from '../../generic/configure-modal/ConfigureModal';
import SortableItem from '../../generic/drag-helper/SortableItem';
import { scrollToElement } from '../../course-outline/utils';
import { COURSE_BLOCK_NAMES } from '../../constants';
-import { copyToClipboard } from '../../generic/data/thunks';
+import { useClipboard } from '../../generic/clipboard';
import { COMPONENT_TYPES } from '../../generic/block-type-utils/constants';
import XBlockMessages from './xblock-messages/XBlockMessages';
import messages from './messages';
@@ -28,7 +28,6 @@ const CourseXBlock = ({
const courseXBlockElementRef = useRef(null);
const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useToggle(false);
const [isConfigureModalOpen, openConfigureModal, closeConfigureModal] = useToggle(false);
- const dispatch = useDispatch();
const canEdit = useSelector(getCanEdit);
const courseId = useSelector(getCourseId);
const intl = useIntl();
@@ -48,6 +47,8 @@ const CourseXBlock = ({
showCorrectness: 'always',
};
+ const { copyToClipboard } = useClipboard(canEdit);
+
const onDeleteSubmit = () => {
unitXBlockActions.handleDelete(id);
closeDeleteModal();
@@ -120,7 +121,7 @@ const CourseXBlock = ({
{intl.formatMessage(messages.blockLabelButtonMove)}
{canEdit && (
- dispatch(copyToClipboard(id))}>
+ copyToClipboard(id)}>
{intl.formatMessage(messages.blockLabelButtonCopyToClipboard)}
)}
diff --git a/src/course-unit/course-xblock/CourseXBlock.test.jsx b/src/course-unit/course-xblock/CourseXBlock.test.jsx
index 95482d098..f72a9ef74 100644
--- a/src/course-unit/course-xblock/CourseXBlock.test.jsx
+++ b/src/course-unit/course-xblock/CourseXBlock.test.jsx
@@ -1,3 +1,4 @@
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import {
render, waitFor, within,
} from '@testing-library/react';
@@ -24,6 +25,15 @@ import messages from './messages';
let axiosMock;
let store;
+let queryClient;
+
+const clipboardBroadcastChannelMock = {
+ postMessage: jest.fn(),
+ close: jest.fn(),
+};
+
+global.BroadcastChannel = jest.fn(() => clipboardBroadcastChannelMock);
+
const courseId = '1234';
const blockId = '567890';
const handleDeleteMock = jest.fn();
@@ -49,17 +59,19 @@ jest.mock('react-redux', () => ({
const renderComponent = (props) => render(
-
+
+
+
,
);
@@ -98,6 +110,7 @@ describe('', () => {
.onGet(getCourseSectionVerticalApiUrl(blockId))
.reply(200, courseSectionVerticalMock);
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
+ queryClient = new QueryClient();
});
it('render CourseXBlock component correctly', async () => {
diff --git a/src/course-unit/data/thunk.js b/src/course-unit/data/thunk.js
index c2ac2be7c..496c4127a 100644
--- a/src/course-unit/data/thunk.js
+++ b/src/course-unit/data/thunk.js
@@ -8,7 +8,6 @@ import { handleResponseErrors } from '../../generic/saving-error-alert';
import { RequestStatus } from '../../data/constants';
import { NOTIFICATION_MESSAGES } from '../../constants';
import { updateModel, updateModels } from '../../generic/model-store';
-import { updateClipboardData } from '../../generic/data/slice';
import {
getCourseUnitData,
editUnitDisplayName,
@@ -75,7 +74,6 @@ export function fetchCourseSectionVerticalData(courseId, sequenceId) {
}));
dispatch(fetchStaticFileNoticesSuccess(JSON.parse(localStorage.getItem('staticFileNotices'))));
localStorage.removeItem('staticFileNotices');
- dispatch(updateClipboardData(courseSectionVerticalData.userClipboard));
dispatch(fetchSequenceSuccess({ sequenceId }));
return true;
} catch (error) {
@@ -214,8 +212,6 @@ export function deleteUnitItemQuery(itemId, xblockId) {
try {
await deleteUnitItem(xblockId);
dispatch(deleteXBlock(xblockId));
- const { userClipboard } = await getCourseSectionVerticalData(itemId);
- dispatch(updateClipboardData(userClipboard));
const courseUnit = await getCourseUnitData(itemId);
dispatch(fetchCourseItemSuccess(courseUnit));
dispatch(hideProcessingNotification());
diff --git a/src/course-unit/hooks.jsx b/src/course-unit/hooks.jsx
index 66182ef1f..14bdd4190 100644
--- a/src/course-unit/hooks.jsx
+++ b/src/course-unit/hooks.jsx
@@ -3,6 +3,7 @@ import { useDispatch, useSelector } from 'react-redux';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { RequestStatus } from '../data/constants';
+import { useClipboard } from '../generic/clipboard';
import {
createNewCourseXBlock,
fetchCourseUnitQuery,
@@ -28,8 +29,6 @@ import {
import { changeEditTitleFormOpen, updateQueryPendingStatus } from './data/slice';
import { PUBLISH_TYPES } from './constants';
-import { useCopyToClipboard } from '../generic/clipboard';
-
// eslint-disable-next-line import/prefer-default-export
export const useCourseUnit = ({ courseId, blockId }) => {
const dispatch = useDispatch();
@@ -47,7 +46,7 @@ export const useCourseUnit = ({ courseId, blockId }) => {
const isTitleEditFormOpen = useSelector(state => state.courseUnit.isTitleEditFormOpen);
const canEdit = useSelector(getCanEdit);
const { currentlyVisibleToStudents } = courseUnit;
- const { sharedClipboardData, showPasteXBlock, showPasteUnit } = useCopyToClipboard(canEdit);
+ const { sharedClipboardData, showPasteXBlock, showPasteUnit } = useClipboard(canEdit);
const { canPasteComponent } = courseVerticalChildren;
const unitTitle = courseUnit.metadata?.displayName || '';
diff --git a/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.jsx b/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.jsx
index 5f78ae761..645651a27 100644
--- a/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.jsx
+++ b/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.jsx
@@ -1,15 +1,14 @@
import PropTypes from 'prop-types';
-import { useDispatch, useSelector } from 'react-redux';
+import { useSelector } from 'react-redux';
import { Button } from '@openedx/paragon';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Divider } from '../../../../generic/divider';
import { getCanEdit, getCourseUnitData } from '../../../data/selectors';
-import { copyToClipboard } from '../../../../generic/data/thunks';
+import { useClipboard } from '../../../../generic/clipboard';
import messages from '../../messages';
const ActionButtons = ({ openDiscardModal, handlePublishing }) => {
- const dispatch = useDispatch();
const intl = useIntl();
const {
id,
@@ -18,6 +17,7 @@ const ActionButtons = ({ openDiscardModal, handlePublishing }) => {
enableCopyPasteUnits,
} = useSelector(getCourseUnitData);
const canEdit = useSelector(getCanEdit);
+ const { copyToClipboard } = useClipboard();
return (
<>
@@ -40,7 +40,7 @@ const ActionButtons = ({ openDiscardModal, handlePublishing }) => {
<>