Skip to content

Commit d388335

Browse files
committed
feat: api call for adding component to collection
1 parent 2848746 commit d388335

File tree

5 files changed

+63
-6
lines changed

5 files changed

+63
-6
lines changed

src/library-authoring/add-content/AddContentContainer.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { useLocation, useNavigate, useParams } from 'react-router-dom';
2121
import { ToastContext } from '../../generic/toast-context';
2222
import { useCopyToClipboard } from '../../generic/clipboard';
2323
import { getCanEdit } from '../../course-unit/data/selectors';
24-
import { useCreateLibraryBlock, useLibraryPasteClipboard } from '../data/apiHooks';
24+
import { useCreateLibraryBlock, useLibraryPasteClipboard, useUpdateCollectionComponents } from '../data/apiHooks';
2525
import { getEditUrl } from '../components/utils';
2626

2727
import messages from './messages';
@@ -66,6 +66,7 @@ const AddContentContainer = () => {
6666
const currentPath = location.pathname;
6767
const { libraryId, collectionId } = useParams();
6868
const createBlockMutation = useCreateLibraryBlock();
69+
const updateComponentsMutation = useUpdateCollectionComponents(libraryId, collectionId);
6970
const pasteClipboardMutation = useLibraryPasteClipboard();
7071
const { showToast } = useContext(ToastContext);
7172
const canEdit = useSelector(getCanEdit);
@@ -149,9 +150,11 @@ const AddContentContainer = () => {
149150
libraryId,
150151
blockType,
151152
definitionId: `${uuid4()}`,
152-
collectionId,
153153
}).then((data) => {
154154
const editUrl = getEditUrl(data.id);
155+
updateComponentsMutation.mutateAsync([data.id]).catch(() => {
156+
showToast(intl.formatMessage(messages.errorAssociateComponentMessage));
157+
});
155158
if (editUrl) {
156159
// Pass currentPath in state so that we can come back to
157160
// current page on save or cancel

src/library-authoring/add-content/messages.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ const messages = defineMessages({
5151
defaultMessage: 'There was an error creating the content.',
5252
description: 'Message when creation of content in library is on error',
5353
},
54+
errorAssociateComponentMessage: {
55+
id: 'course-authoring.library-authoring.associate-collection-content.error.text',
56+
defaultMessage: 'There was an error linking the content to this collection.',
57+
description: 'Message when linking of content to a collection in library fails',
58+
},
5459
addContentTitle: {
5560
id: 'course-authoring.library-authoring.sidebar.title.add-content',
5661
defaultMessage: 'Add Content',

src/library-authoring/data/api.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ export const getLibraryCollectionsApiUrl = (libraryId: string) => `${getApiBaseU
5454
* Get the URL for the collection API.
5555
*/
5656
export const getLibraryCollectionApiUrl = (libraryId: string, collectionId: string) => `${getLibraryCollectionsApiUrl(libraryId)}${collectionId}/`;
57+
/**
58+
* Get the URL for the collection API.
59+
*/
60+
export const getLibraryCollectionComponentApiUrl = (libraryId: string, collectionId: string) => `${getLibraryCollectionApiUrl(libraryId, collectionId)}components/`;
5761

5862
export interface ContentLibrary {
5963
id: string;
@@ -132,7 +136,6 @@ export interface CreateBlockDataRequest {
132136
libraryId: string;
133137
blockType: string;
134138
definitionId: string;
135-
collectionId?: string;
136139
}
137140

138141
export interface LibraryBlockMetadata {
@@ -196,15 +199,13 @@ export async function createLibraryBlock({
196199
libraryId,
197200
blockType,
198201
definitionId,
199-
collectionId,
200202
}: CreateBlockDataRequest): Promise<LibraryBlockMetadata> {
201203
const client = getAuthenticatedHttpClient();
202204
const { data } = await client.post(
203205
getCreateLibraryBlockUrl(libraryId),
204206
{
205207
block_type: blockType,
206208
definition_id: definitionId,
207-
collection_key: collectionId,
208209
},
209210
);
210211
return camelCaseObject(data);
@@ -313,3 +314,12 @@ export async function getXBlockOLX(usageKey: string): Promise<string> {
313314
const { data } = await getAuthenticatedHttpClient().get(getXBlockOLXApiUrl(usageKey));
314315
return data.olx;
315316
}
317+
318+
/**
319+
* Update collection components.
320+
*/
321+
export async function updateCollectionComponents(libraryId:string, collectionId: string, usageKeys: string[]) {
322+
await getAuthenticatedHttpClient().patch(getLibraryCollectionComponentApiUrl(libraryId, collectionId), {
323+
usage_keys: usageKeys,
324+
});
325+
}

src/library-authoring/data/apiHooks.test.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
55
import { renderHook } from '@testing-library/react-hooks';
66
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
77
import MockAdapter from 'axios-mock-adapter';
8-
import { getCommitLibraryChangesUrl, getCreateLibraryBlockUrl, getLibraryCollectionsApiUrl } from './api';
8+
import {
9+
getCommitLibraryChangesUrl,
10+
getCreateLibraryBlockUrl,
11+
getLibraryCollectionComponentApiUrl,
12+
getLibraryCollectionsApiUrl,
13+
} from './api';
914
import {
1015
useCommitLibraryChanges,
1116
useCreateLibraryBlock,
1217
useCreateLibraryCollection,
1318
useRevertLibraryChanges,
19+
useUpdateCollectionComponents,
1420
} from './apiHooks';
1521

1622
let axiosMock;
@@ -89,4 +95,15 @@ describe('library api hooks', () => {
8995

9096
expect(axiosMock.history.post[0].url).toEqual(url);
9197
});
98+
99+
it('should add components to collection', async () => {
100+
const libraryId = 'lib:org:1';
101+
const collectionId = 'my-first-collection';
102+
const url = getLibraryCollectionComponentApiUrl(libraryId, collectionId);
103+
axiosMock.onPatch(url).reply(200);
104+
const { result } = renderHook(() => useUpdateCollectionComponents(libraryId, collectionId), { wrapper });
105+
await result.current.mutateAsync(['some-usage-key']);
106+
107+
expect(axiosMock.history.patch[0].url).toEqual(url);
108+
});
92109
});

src/library-authoring/data/apiHooks.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
updateXBlockFields,
2727
createCollection,
2828
getXBlockOLX,
29+
updateCollectionComponents,
2930
type CreateLibraryCollectionDataRequest,
3031
} from './api';
3132

@@ -275,3 +276,24 @@ export const useXBlockOLX = (usageKey: string) => (
275276
enabled: !!usageKey,
276277
})
277278
);
279+
280+
/**
281+
* Use this mutation to add components to a collection in a library
282+
*/
283+
export const useUpdateCollectionComponents = (libraryId?: string, collectionId?: string) => {
284+
const queryClient = useQueryClient();
285+
return useMutation({
286+
mutationFn: async (usage_keys: string[]) => {
287+
if (libraryId !== undefined && collectionId !== undefined) {
288+
return updateCollectionComponents(libraryId, collectionId, usage_keys);
289+
}
290+
return undefined;
291+
},
292+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
293+
onSettled: (_data, _error, _variables) => {
294+
if (libraryId !== undefined && collectionId !== undefined) {
295+
queryClient.invalidateQueries({ predicate: (query) => libraryQueryPredicate(query, libraryId) });
296+
}
297+
},
298+
});
299+
};

0 commit comments

Comments
 (0)