Skip to content

Commit

Permalink
feat: bulk students enroll
Browse files Browse the repository at this point in the history
  • Loading branch information
AuraAlba committed Jul 12, 2024
1 parent 75ae301 commit 3016b1a
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 18 deletions.
23 changes: 14 additions & 9 deletions src/features/Classes/EnrollStudent/__test__/index.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,22 @@ jest.mock('react-router-dom', () => ({
}));

jest.mock('features/Students/data/api', () => ({
handleEnrollments: jest.fn(() => Promise.resolve()),
handleEnrollments: jest.fn().mockReturnValue({}),
getMessages: jest.fn().mockReturnValue({}),
}));

jest.mock('@edx/frontend-platform/logging', () => ({
logError: jest.fn(),
}));

describe('EnrollStudent', () => {
afterEach(() => {
jest.clearAllMocks();
});

test('Should render with correct elements', () => {
const { getByText, getByPlaceholderText } = renderWithProviders(
<EnrollStudent isOpen onClose={() => {}} />,
<EnrollStudent isOpen onClose={() => {}} queryClassId="ccx1" />,
{ preloadedState: {} },
);

Expand All @@ -37,14 +42,14 @@ describe('EnrollStudent', () => {
const onCloseMock = jest.fn();

const { getByPlaceholderText, getByText } = renderWithProviders(
<EnrollStudent isOpen onClose={onCloseMock} />,
<EnrollStudent isOpen onClose={onCloseMock} queryClassId="ccx1" />,
{ preloadedState: {} },
);

const handleEnrollmentsMock = jest.spyOn(api, 'handleEnrollments').mockResolvedValue({
data: {
results: [{
tags: 'success',
identifier: '[email protected]',
}],
},
});
Expand All @@ -56,7 +61,7 @@ describe('EnrollStudent', () => {
fireEvent.click(submitButton);

await waitFor(() => {
expect(getByText('Email invite has been sent successfully')).toBeInTheDocument();
expect(getByText('Successfully enrolled and sent email to the following users: [email protected]')).toBeInTheDocument();
});

expect(handleEnrollmentsMock).toHaveBeenCalledTimes(1);
Expand All @@ -66,14 +71,14 @@ describe('EnrollStudent', () => {
test('Should handle form submission and show error toast', async () => {
const onCloseMock = jest.fn();

const handleEnrollmentsMock = jest.spyOn(api, 'handleEnrollments').mockResolvedValue({
const messagesApiMock = jest.spyOn(api, 'getMessages').mockResolvedValue({
data: {
results: [{ tags: 'error', message: 'Enrollment limit reached' }],
},
});

const { getByPlaceholderText, getByText } = renderWithProviders(
<EnrollStudent isOpen onClose={onCloseMock} />,
<EnrollStudent isOpen onClose={onCloseMock} queryClassId="ccx1" />,
{ preloadedState: {} },
);

Expand All @@ -87,8 +92,8 @@ describe('EnrollStudent', () => {
expect(getByText('Enrollment limit reached')).toBeInTheDocument();
});

expect(handleEnrollmentsMock).toHaveBeenCalledTimes(1);
expect(messagesApiMock).toHaveBeenCalledTimes(1);

handleEnrollmentsMock.mockRestore();
messagesApiMock.mockRestore();
});
});
42 changes: 35 additions & 7 deletions src/features/Classes/EnrollStudent/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { Button } from 'react-paragon-topaz';
import { logError } from '@edx/frontend-platform/logging';

import { fetchStudentsData } from 'features/Students/data';
import { handleEnrollments } from 'features/Students/data/api';
import { handleEnrollments, getMessages } from 'features/Students/data/api';
import { fetchAllClassesData } from 'features/Classes/data/thunks';
import { initialPage } from 'features/constants';

Expand Down Expand Up @@ -47,20 +47,47 @@ const EnrollStudent = ({ isOpen, onClose, queryClassId }) => {
try {
setLoading(true);
const response = await handleEnrollments(formData, queryClassId);
const validationEmailList = response?.data?.results;
const messages = await getMessages();
let validEmails = [];
let invalidEmails = [];
let textToast = '';

/**
* This is because the service that checks the enrollment status is a different
* endpoint, and that endpoint always returns a status 200, so the error cannot be
* caught with a .catch.
*/
if (response?.data?.results[0]?.tags === 'error') {
setToastMessage(decodeURIComponent(response?.data?.results[0]?.message));
if (messages?.data?.results[0]?.tags === 'error') {
setToastMessage(decodeURIComponent(messages?.data?.results[0]?.message));
setShowToast(true);

return onClose();
}

setToastMessage('Email invite has been sent successfully');
validationEmailList.map(email => {
if (email?.invalidIdentifier) {
invalidEmails = [
...invalidEmails,
email.identifier,
];
return invalidEmails;
}
validEmails = [
...validEmails,
email.identifier,
];
return validEmails;
});

if (invalidEmails.length > 0) {
textToast = `The following email adresses are invalid: ${invalidEmails.join(' ')}\n`;
}
if (validEmails.length > 0) {
textToast += `Successfully enrolled and sent email to the following users: ${validEmails.join(' ')}`;
}

setToastMessage(textToast);

const params = {
course_name: courseNameDecoded,
Expand All @@ -84,7 +111,7 @@ const EnrollStudent = ({ isOpen, onClose, queryClassId }) => {

return (
<>
<Toast onClose={() => setShowToast(false)} show={showToast}>
<Toast onClose={() => setShowToast(false)} show={showToast} className="toast-message">
{toastMessage}
</Toast>
<ModalDialog
Expand Down Expand Up @@ -113,12 +140,13 @@ const EnrollStudent = ({ isOpen, onClose, queryClassId }) => {
<Form onSubmit={handleEnrollStudent}>
<FormGroup controlId="studentInfo">
<Form.Control
type="email"
as="textarea"
placeholder="Enter email of the student to enroll"
floatingLabel="Email"
className="my-4 mr-0"
className="my-4 mr-0 student-email"
name="studentEmail"
required
autoResize
/>
</FormGroup>
<div className="d-flex justify-content-end">
Expand Down
8 changes: 8 additions & 0 deletions src/features/Classes/EnrollStudent/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,12 @@

.body-container {
min-height: 193px;

.student-email .pgn__form-control-floating-label {
display: block;
}
}

.toast-message {
white-space: pre-wrap;
}
9 changes: 7 additions & 2 deletions src/features/Students/data/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ function handleEnrollments(data, courseId) {
return getAuthenticatedHttpClient().post(
`${INSTRUCTOR_API_URL.replace(courseIdSearchPattern, courseId)}/students_update_enrollment`,
data,
).then(() => getAuthenticatedHttpClient().get(
);
}

function getMessages() {
return getAuthenticatedHttpClient().get(
`${getConfig().LMS_BASE_URL}/pearson_course_operation/api/messages/get-messages/`,
));
);
}

function getStudentsMetrics(institutionId, days) {
Expand Down Expand Up @@ -55,4 +59,5 @@ export {
handleEnrollments,
getStudentsMetrics,
getClassesMetrics,
getMessages,
};

0 comments on commit 3016b1a

Please sign in to comment.