diff --git a/src/library-authoring/component-info/ComponentInfo.tsx b/src/library-authoring/component-info/ComponentInfo.tsx index 38906d2d5c..e6ea4d74c2 100644 --- a/src/library-authoring/component-info/ComponentInfo.tsx +++ b/src/library-authoring/component-info/ComponentInfo.tsx @@ -5,21 +5,18 @@ import { Tabs, Stack, } from '@openedx/paragon'; -import { useContext } from 'react'; -import { ToastContext } from '../../generic/toast-context'; import { useLibraryContext } from '../common/context'; import { ComponentMenu } from '../components'; import { canEditComponent } from '../components/ComponentEditorModal'; -import { useAddComponentToCourse } from '../data/apiHooks'; import ComponentDetails from './ComponentDetails'; import ComponentManagement from './ComponentManagement'; import ComponentPreview from './ComponentPreview'; import messages from './messages'; +import { getBlockType } from '../../generic/key-utils'; const ComponentInfo = () => { const intl = useIntl(); - const { showToast } = useContext(ToastContext); const { sidebarComponentUsageKey: usageKey, @@ -34,22 +31,15 @@ const ComponentInfo = () => { throw new Error('usageKey is required'); } - const { - mutateAsync: addComponentToCourse, - reset, - } = useAddComponentToCourse(parentLocator, usageKey); - const canEdit = canEditComponent(usageKey); const handleAddComponentToCourse = () => { - addComponentToCourse() - .then(() => { - window.parent.postMessage('closeComponentPicker', '*'); - }) - .catch(() => { - showToast(intl.formatMessage(messages.addComponentToCourseError)); - reset(); - }); + window.parent.postMessage({ + parentLocator, + usageKey, + type: 'pickerComponentSelected', + category: getBlockType(usageKey), + }, '*'); }; return ( diff --git a/src/library-authoring/component-picker/ComponentPicker.test.tsx b/src/library-authoring/component-picker/ComponentPicker.test.tsx index f173c7b704..030dd4662e 100644 --- a/src/library-authoring/component-picker/ComponentPicker.test.tsx +++ b/src/library-authoring/component-picker/ComponentPicker.test.tsx @@ -1,12 +1,9 @@ -import type MockAdapter from 'axios-mock-adapter'; - import { mockContentSearchConfig, mockSearchResult } from '../../search-manager/data/api.mock'; import { initializeMocks, fireEvent, render, screen, - waitFor, within, } from '../../testUtils'; import mockResult from '../__mocks__/library-search.json'; @@ -17,7 +14,6 @@ import { mockGetContentLibraryV2List, mockLibraryBlockMetadata, } from '../data/api.mocks'; -import { getXBlockBaseApiUrl } from '../data/api'; import { ComponentPicker } from './ComponentPicker'; @@ -27,8 +23,7 @@ mockGetCollectionMetadata.applyMock(); mockGetContentLibraryV2List.applyMock(); mockLibraryBlockMetadata.applyMock(); -let axiosMock: MockAdapter; -let mockShowToast: (message: string) => void; +let postMessageSpy: jest.SpyInstance; jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -44,10 +39,8 @@ jest.mock('react-router-dom', () => ({ describe('', () => { beforeEach(() => { - const mocks = initializeMocks(); - axiosMock = mocks.axiosMock; - mockShowToast = mocks.mockShowToast; - axiosMock.onPost(getXBlockBaseApiUrl()).reply(200, {}); + initializeMocks(); + postMessageSpy = jest.spyOn(window.parent, 'postMessage'); mockSearchResult(mockResult); }); @@ -67,41 +60,12 @@ describe('', () => { // Click the add component from the component card fireEvent.click(screen.queryAllByRole('button', { name: 'Add' })[0]); - await waitFor(() => { - expect(axiosMock.history.post.length).toBe(1); - expect(axiosMock.history.post[0].url).toBe(getXBlockBaseApiUrl()); - expect(axiosMock.history.post[0].data).toBe(JSON.stringify({ - parent_locator: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical1', - library_content_key: 'lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd', - })); - }); - }); - - it('should show toast if error on api call from the component card button', async () => { - axiosMock.onPost(getXBlockBaseApiUrl()).reply(500, {}); - render(); - - expect(await screen.findByText('Test Library 1')).toBeInTheDocument(); - fireEvent.click(screen.getByDisplayValue(/lib:sampletaxonomyorg1:tl1/i)); - - fireEvent.click(screen.getByText('Next')); - - // Wait for the content library to load - await screen.findByText(/Change Library/i); - expect(await screen.findByText('Test Library 1')).toBeInTheDocument(); - - // Click the add component from the component card - fireEvent.click(screen.queryAllByRole('button', { name: 'Add' })[0]); - - await waitFor(() => { - expect(axiosMock.history.post.length).toBe(1); - expect(axiosMock.history.post[0].url).toBe(getXBlockBaseApiUrl()); - expect(axiosMock.history.post[0].data).toBe(JSON.stringify({ - parent_locator: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical1', - library_content_key: 'lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd', - })); - expect(mockShowToast).toHaveBeenCalledWith('Failed to add component to course'); - }); + expect(postMessageSpy).toHaveBeenCalledWith({ + parentLocator: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical1', + usageKey: 'lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd', + type: 'pickerComponentSelected', + category: 'html', + }, '*'); }); it('should pick component using the component sidebar', async () => { @@ -124,46 +88,12 @@ describe('', () => { // Click the add component from the component sidebar fireEvent.click(within(sidebar).getByRole('button', { name: 'Add to Course' })); - await waitFor(() => { - expect(axiosMock.history.post.length).toBe(1); - expect(axiosMock.history.post[0].url).toBe(getXBlockBaseApiUrl()); - expect(axiosMock.history.post[0].data).toBe(JSON.stringify({ - parent_locator: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical1', - library_content_key: 'lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd', - })); - }); - }); - - it('should show toast if error on api call from the component sidebar button', async () => { - axiosMock.onPost(getXBlockBaseApiUrl()).reply(500, {}); - render(); - - expect(await screen.findByText('Test Library 1')).toBeInTheDocument(); - fireEvent.click(screen.getByDisplayValue(/lib:sampletaxonomyorg1:tl1/i)); - - fireEvent.click(screen.getByText('Next')); - - // Wait for the content library to load - await screen.findByText(/Change Library/i); - expect(await screen.findByText('Test Library 1')).toBeInTheDocument(); - - // Click on the component card to open the sidebar - fireEvent.click(screen.queryAllByText('Introduction to Testing')[0]); - - const sidebar = await screen.findByTestId('library-sidebar'); - - // Click the add component from the component sidebar - fireEvent.click(within(sidebar).getByRole('button', { name: 'Add to Course' })); - - await waitFor(() => { - expect(axiosMock.history.post.length).toBe(1); - expect(axiosMock.history.post[0].url).toBe(getXBlockBaseApiUrl()); - expect(axiosMock.history.post[0].data).toBe(JSON.stringify({ - parent_locator: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical1', - library_content_key: 'lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd', - })); - expect(mockShowToast).toHaveBeenCalledWith('Failed to add component to course'); - }); + expect(postMessageSpy).toHaveBeenCalledWith({ + parentLocator: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical1', + usageKey: 'lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd', + type: 'pickerComponentSelected', + category: 'html', + }, '*'); }); it('should pick component inside a collection using the card', async () => { @@ -196,14 +126,12 @@ describe('', () => { // Click the add component from the component card fireEvent.click(screen.queryAllByRole('button', { name: 'Add' })[0]); - await waitFor(() => { - expect(axiosMock.history.post.length).toBe(1); - expect(axiosMock.history.post[0].url).toBe(getXBlockBaseApiUrl()); - expect(axiosMock.history.post[0].data).toBe(JSON.stringify({ - parent_locator: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical1', - library_content_key: 'lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd', - })); - }); + expect(postMessageSpy).toHaveBeenCalledWith({ + parentLocator: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical1', + usageKey: 'lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd', + type: 'pickerComponentSelected', + category: 'html', + }, '*'); }); it('should pick component inside a collection using the sidebar', async () => { @@ -241,14 +169,12 @@ describe('', () => { // Click the add component from the collection sidebar fireEvent.click(within(collectionSidebar).getByRole('button', { name: 'Add to Course' })); - await waitFor(() => { - expect(axiosMock.history.post.length).toBe(1); - expect(axiosMock.history.post[0].url).toBe(getXBlockBaseApiUrl()); - expect(axiosMock.history.post[0].data).toBe(JSON.stringify({ - parent_locator: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical1', - library_content_key: 'lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd', - })); - }); + expect(postMessageSpy).toHaveBeenCalledWith({ + parentLocator: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical1', + usageKey: 'lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd', + type: 'pickerComponentSelected', + category: 'html', + }, '*'); }); it('should return to library selection', async () => { diff --git a/src/library-authoring/components/ComponentCard.tsx b/src/library-authoring/components/ComponentCard.tsx index 3e0b4e2d33..c8df6c202b 100644 --- a/src/library-authoring/components/ComponentCard.tsx +++ b/src/library-authoring/components/ComponentCard.tsx @@ -14,7 +14,7 @@ import { updateClipboard } from '../../generic/data/api'; import { ToastContext } from '../../generic/toast-context'; import { type ContentHit } from '../../search-manager'; import { useLibraryContext } from '../common/context'; -import { useAddComponentToCourse, useRemoveComponentsFromCollection } from '../data/apiHooks'; +import { useRemoveComponentsFromCollection } from '../data/apiHooks'; import BaseComponentCard from './BaseComponentCard'; import { canEditComponent } from './ComponentEditorModal'; import messages from './messages'; @@ -90,14 +90,11 @@ export const ComponentMenu = ({ usageKey }: { usageKey: string }) => { }; const ComponentCard = ({ contentHit }: ComponentCardProps) => { - const intl = useIntl(); - const { openComponentInfoSidebar, componentPickerMode, parentLocator, } = useLibraryContext(); - const { showToast } = useContext(ToastContext); const { blockType, @@ -112,20 +109,13 @@ const ComponentCard = ({ contentHit }: ComponentCardProps) => { ) ?? '';/* eslint-enable */ const displayName = formatted?.displayName ?? ''; - const { - mutateAsync: addComponentToCourse, - reset, - } = useAddComponentToCourse(parentLocator, contentHit.usageKey); - const handleAddComponentToCourse = () => { - addComponentToCourse() - .then(() => { - window.parent.postMessage('closeComponentPicker', '*'); - }) - .catch(() => { - showToast(intl.formatMessage(messages.addComponentToCourseError)); - reset(); - }); + window.parent.postMessage({ + parentLocator, + usageKey, + type: 'pickerComponentSelected', + category: blockType, + }, '*'); }; return ( diff --git a/src/library-authoring/data/api.ts b/src/library-authoring/data/api.ts index 578c06b336..d8f22c741d 100644 --- a/src/library-authoring/data/api.ts +++ b/src/library-authoring/data/api.ts @@ -483,15 +483,3 @@ export async function updateComponentCollections(usageKey: string, collectionKey collection_keys: collectionKeys, }); } - -/** - * Add a component to a course. - */ -// istanbul ignore next -export async function addComponentToCourse(parentLocator: string, componentUsageKey: string) { - const client = getAuthenticatedHttpClient(); - await client.post(getXBlockBaseApiUrl(), { - parent_locator: parentLocator, - library_content_key: componentUsageKey, - }); -} diff --git a/src/library-authoring/data/apiHooks.ts b/src/library-authoring/data/apiHooks.ts index 6cfb0f333f..de43624855 100644 --- a/src/library-authoring/data/apiHooks.ts +++ b/src/library-authoring/data/apiHooks.ts @@ -40,7 +40,6 @@ import { getXBlockAssets, updateComponentCollections, removeComponentsFromCollection, - addComponentToCourse, } from './api'; export const libraryQueryPredicate = (query: Query, libraryId: string): boolean => { @@ -474,18 +473,3 @@ export const useUpdateComponentCollections = (libraryId: string, usageKey: strin }, }); }; - -/** - * Use this mutation to add a component to a course - */ -export const useAddComponentToCourse = (parentLocator: string | undefined, componentUsageKey: string) => ( - useMutation({ - mutationFn: () => { - // istanbul ignore if: this should never happen - if (!parentLocator) { - throw new Error('parentLocator is required'); - } - return addComponentToCourse(parentLocator, componentUsageKey); - }, - }) -);