diff --git a/src/features/Instructors/AddInstructors/_test_/index.test.jsx b/src/features/Instructors/AddInstructors/_test_/index.test.jsx index 3cace2a7..823f08d9 100644 --- a/src/features/Instructors/AddInstructors/_test_/index.test.jsx +++ b/src/features/Instructors/AddInstructors/_test_/index.test.jsx @@ -41,5 +41,11 @@ describe('Add instructor component', () => { const ccxSelect = getByText('Select Class Name'); expect(instructorInfoInput).toBeInTheDocument(); expect(ccxSelect).toBeInTheDocument(); + + fireEvent.change(instructorInfoInput, { target: { value: 'Name' } }); + const submitButton = getByText('Add'); + await act(async () => { + fireEvent.click(submitButton); + }); }); }); diff --git a/src/features/Instructors/AddInstructors/index.jsx b/src/features/Instructors/AddInstructors/index.jsx index 939ed3e9..77216a45 100644 --- a/src/features/Instructors/AddInstructors/index.jsx +++ b/src/features/Instructors/AddInstructors/index.jsx @@ -2,7 +2,7 @@ import React, { useState, useReducer, useEffect } from 'react'; import { Button, FormGroup, ModalDialog, useToggle, Form, } from '@edx/paragon'; -import { getCCXList } from 'features/Instructors/data/api'; +import { getCCXList, handleInstructorsEnrollment } from 'features/Instructors/data/api'; import reducer from 'features/Instructors/AddInstructors/reducer'; import { logError } from '@edx/frontend-platform/logging'; import { camelCaseObject } from '@edx/frontend-platform'; @@ -26,6 +26,8 @@ const AddInstructors = () => { const [state, dispatch] = useReducer(reducer, initialState); const [isOpen, open, close] = useToggle(false); const [addInstructorInfo, setAddInstructorInfo] = useState(addInstructorState); + const [isNoUser, setIsNoUser] = useState(false); + const enrollmentData = new FormData(); const fetchData = async () => { dispatch({ type: FETCH_CCX_LIST_REQUEST }); @@ -46,6 +48,17 @@ const AddInstructors = () => { }); }; + // Set default value + useEffect(() => { + if (state.data.length > 0) { + setAddInstructorInfo((prevState) => ({ + ...prevState, + ccxId: state.data[0].classId, + ccxName: state.data[0].className, + })); + } + }, [state.data]); + const handleCcxSelect = (e) => { const select = e.target; setAddInstructorInfo({ @@ -55,6 +68,24 @@ const AddInstructors = () => { }); }; + const handleAddInstructors = async () => { + try { + enrollmentData.append('unique_student_identifier', addInstructorInfo.instructorInfo); + enrollmentData.append('rolename', 'staff'); + enrollmentData.append('action', 'allow'); + const response = await handleInstructorsEnrollment(enrollmentData, addInstructorInfo.ccxId); + if (response.data?.userDoesNotExist) { + setIsNoUser(true); + } else { + fetchData(); + close(); + setIsNoUser(false); + } + } catch (error) { + logError(error); + } + }; + useEffect(() => { fetchData(); }, []); @@ -83,9 +114,12 @@ const AddInstructors = () => { className="my-4 mr-0" onChange={handleCcxSelect} id="selectCcx" + value={addInstructorInfo.ccxId} > {state.data.map((ccx) => )} + + { onChange={handleInstructorInput} className="my-4 mr-0" /> -
- -
+ {isNoUser && ( + + User does not exist + + )}
+
+ +
+ diff --git a/src/features/Instructors/data/_test_/api.test.js b/src/features/Instructors/data/_test_/api.test.js index 9e4f38c1..70825fdf 100644 --- a/src/features/Instructors/data/_test_/api.test.js +++ b/src/features/Instructors/data/_test_/api.test.js @@ -1,5 +1,5 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; -import { getInstructorData } from 'features/Instructors/data/api'; +import { getInstructorData, handleInstructorsEnrollment } from 'features/Instructors/data/api'; jest.mock('@edx/frontend-platform/auth', () => ({ getAuthenticatedHttpClient: jest.fn(), @@ -34,3 +34,27 @@ describe('getInstructorData', () => { ); }); }); + +describe('handleInstructorsEnrollment', () => { + test('should call getAuthenticatedHttpClient with the correct parameters', () => { + const httpClientMock = { + post: jest.fn(), + }; + + const courseId = 'course123'; + const data = new FormData(); + + getAuthenticatedHttpClient.mockReturnValue(httpClientMock); + + handleInstructorsEnrollment(data, courseId); + + expect(getAuthenticatedHttpClient).toHaveBeenCalledTimes(2); + expect(getAuthenticatedHttpClient).toHaveBeenCalledWith(); + + expect(httpClientMock.post).toHaveBeenCalledTimes(1); + expect(httpClientMock.post).toHaveBeenCalledWith( + 'http://localhost:18000/courses/course123/instructor/api/modify_access', + data, + ); + }); +}); diff --git a/src/features/Instructors/data/api.js b/src/features/Instructors/data/api.js index c87e5bb0..e90ae436 100644 --- a/src/features/Instructors/data/api.js +++ b/src/features/Instructors/data/api.js @@ -17,11 +17,22 @@ function getInstructorData(page, filters) { function getCCXList() { const apiV2BaseUrl = getConfig().COURSE_OPERATIONS_API_V2_BASE_URL; return getAuthenticatedHttpClient().get( - `${apiV2BaseUrl}/classes?limit=false`, + `${apiV2BaseUrl}/classes/?limit=false`, + ); +} + +function handleInstructorsEnrollment(data, courseId) { + const INSTRUCTOR_API_URL = `${getConfig().LMS_BASE_URL}/courses/course_id/instructor/api`; + const courseIdSearchPattern = /course_id/; + + return getAuthenticatedHttpClient().post( + `${INSTRUCTOR_API_URL.replace(courseIdSearchPattern, courseId)}/modify_access`, + data, ); } export { getInstructorData, getCCXList, + handleInstructorsEnrollment, };