Skip to content

Commit

Permalink
Merge pull request #130 from edx/aakbar/PROD-2396
Browse files Browse the repository at this point in the history
Self contain enrollment component
  • Loading branch information
Ali-D-Akbar authored Jul 9, 2021
2 parents f4bce47 + 7013ee7 commit af1b687
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 58 deletions.
1 change: 0 additions & 1 deletion src/users/UserPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ export default function UserPage({ location }) {
/>
<Enrollments
user={data.user.username}
data={data.enrollments}
changeHandler={handleEnrollmentsChange}
expanded={showEnrollments}
/>
Expand Down
3 changes: 0 additions & 3 deletions src/users/data/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,6 @@ export async function getOnboardingStatus(enrollments, username) {
export async function getAllUserData(userIdentifier) {
const errors = [];
let user = null;
let enrollments = [];
try {
user = await getUser(userIdentifier);
} catch (error) {
Expand All @@ -265,14 +264,12 @@ export async function getAllUserData(userIdentifier) {
}
}
if (user !== null) {
enrollments = await getEnrollments(user.username);
user.passwordStatus = await getUserPasswordStatus(user.username);
}

return {
errors,
user,
enrollments,
};
}

Expand Down
8 changes: 3 additions & 5 deletions src/users/data/api.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('API', () => {
});

// prepare enrollments data
const { data } = enrollmentsData;
const data = enrollmentsData;
data[1].mode = 'verified';
data[1].course_id = data[1].courseId;
data[1].is_active = true;
Expand Down Expand Up @@ -366,14 +366,12 @@ describe('API', () => {

it('Successful User Data Retrieval', async () => {
mockAdapter.onGet(`${userAccountApiBaseUrl}/${testUsername}`).reply(200, successDictResponse);
mockAdapter.onGet(enrollmentsApiUrl).reply(200, []);
mockAdapter.onGet(passwordStatusApiUrl).reply(200, {});

const response = await api.getAllUserData(testUsername);
expect(response).toEqual({
errors: [],
user: { ...successDictResponse, passwordStatus: {} },
enrollments: [],
});
});
});
Expand Down Expand Up @@ -575,11 +573,11 @@ describe('API', () => {
describe('Enrollments Fetch', () => {
it('Enrollments Response', async () => {
mockAdapter.onGet(enrollmentsApiUrl).reply(200, enrollmentsData);
const expectedData = { ...enrollmentsData };
const expectedData = { ...enrollmentsData[0] };
delete expectedData.changeHandler;

const response = await api.getEnrollments(testUsername);
expect(response).toEqual(expectedData);
expect(response[0]).toEqual(expectedData);
});
});

Expand Down
10 changes: 3 additions & 7 deletions src/users/data/test/enrollments.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ export const createEnrollmentFormData = {
closeHandler: jest.fn(() => {}),
};

export const enrollmentsData = {
data: [{
export const enrollmentsData = [
{
courseId: 'course-v1:testX+test123+2030',
courseStart: Date().toLocaleString(),
courseName: 'Test Course 1',
Expand Down Expand Up @@ -67,8 +67,4 @@ export const enrollmentsData = {
],
manualEnrollment: {},
},
],
user: 'edX',
changeHandler: jest.fn(() => {}),
expanded: true,
};
];
81 changes: 47 additions & 34 deletions src/users/enrollments/Enrollments.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,28 @@ import React, {
useCallback,
useRef,
useLayoutEffect,
useEffect,
} from 'react';

import { Button, TransitionReplace, Collapsible } from '@edx/paragon';
import { getConfig } from '@edx/frontend-platform';
import { camelCaseObject, getConfig } from '@edx/frontend-platform';
import PropTypes from 'prop-types';
import Certificates from './Certificates';
import EnrollmentForm from './EnrollmentForm';
import EnrollmentExtra from './EnrollmentExtra';
import { CREATE, CHANGE } from './constants';
import PageLoading from '../../components/common/PageLoading';
import Table from '../../Table';
import { formatDate, sort } from '../../utils';
import { getEnrollments } from '../data/api';

export default function Enrollments({
data, changeHandler, user, expanded,
changeHandler, user, expanded,
}) {
const [sortColumn, setSortColumn] = useState('created');
const [sortDirection, setSortDirection] = useState('desc');
const [formType, setFormType] = useState(null);
const [enrollmentData, setEnrollmentData] = useState(null);
const [enrollmentToChange, setEnrollmentToChange] = useState(undefined);
const [enrollmentExtraData, setEnrollmentExtraData] = useState(undefined);
const [selectedCourseId, setSelectedCourseId] = useState(undefined);
Expand All @@ -39,48 +43,55 @@ export default function Enrollments({
setEnrollmentExtraData(extraData);
}

useEffect(() => {
getEnrollments(user).then((result) => {
const camelCaseResult = camelCaseObject(result);
setEnrollmentData(camelCaseResult);
});
}, [user]);

useLayoutEffect(() => {
if (enrollmentExtraData !== undefined && selectedCourseId === undefined) {
extraRef.current.focus();
}
});

const tableData = useMemo(() => {
if (data === null || data.length === 0) {
if (enrollmentData === null || enrollmentData.length === 0) {
return [];
}
return data.map(result => ({
return enrollmentData.map(enrollment => ({
courseId: {
displayValue: <a href={`${getConfig().LMS_BASE_URL}/courses/${result.courseId}`} rel="noopener noreferrer" target="_blank" className="word_break">{result.courseId}</a>,
value: result.courseId,
displayValue: <a href={`${getConfig().LMS_BASE_URL}/courses/${enrollment.courseId}`} rel="noopener noreferrer" target="_blank" className="word_break">{enrollment.courseId}</a>,
value: enrollment.courseId,
},
courseName: {
value: result.courseName,
value: enrollment.courseName,
},
courseStart: {
displayValue: formatDate(result.courseStart),
value: result.courseStart,
displayValue: formatDate(enrollment.courseStart),
value: enrollment.courseStart,
},
courseEnd: {
displayValue: formatDate(result.courseEnd),
value: result.courseEnd,
displayValue: formatDate(enrollment.courseEnd),
value: enrollment.courseEnd,
},
upgradeDeadline: {
displayValue: formatDate(result.verifiedUpgradeDeadline),
value: result.verifiedUpgradeDeadline,
displayValue: formatDate(enrollment.verifiedUpgradeDeadline),
value: enrollment.verifiedUpgradeDeadline,
},
created: {
displayValue: formatDate(result.created),
value: result.created,
displayValue: formatDate(enrollment.created),
value: enrollment.created,
},
pacingType: {
value: result.pacingType,
value: enrollment.pacingType,
},
active: {
value: result.isActive ? 'True' : 'False',
value: enrollment.isActive ? 'True' : 'False',
},
mode: {
value: result.mode,
value: enrollment.mode,
},
actions: {
displayValue: (
Expand All @@ -90,7 +101,7 @@ export default function Enrollments({
variant="outline-primary"
id="enrollment-change"
onClick={() => {
setEnrollmentToChange(result);
setEnrollmentToChange(enrollment);
setFormType(CHANGE);
}}
>
Expand All @@ -101,7 +112,7 @@ export default function Enrollments({
id="extra-data"
variant="primary mt-2 mr-2"
onClick={() => {
setupEnrollmentExtraData(result);
setupEnrollmentExtraData(enrollment);
}}
>
Show Extra
Expand All @@ -111,7 +122,7 @@ export default function Enrollments({
id="certificate"
variant="outline-primary mt-2 mr-2"
onClick={() => {
setSelectedCourseId(result.courseId);
setSelectedCourseId(enrollment.courseId);
}}
>
View Certificate
Expand All @@ -121,7 +132,7 @@ export default function Enrollments({
value: 'Change',
},
}));
}, [data]);
}, [enrollmentData]);

const setSort = useCallback((column) => {
if (sortColumn === column) {
Expand Down Expand Up @@ -223,29 +234,31 @@ export default function Enrollments({
) : (<React.Fragment key="nothing" />) }
</TransitionReplace>
<Collapsible title={`Enrollments (${tableData.length})`} defaultOpen={expanded}>
<Table
className="w-auto"
data={tableDataSortable.sort(
(firstElement, secondElement) => sort(firstElement, secondElement, sortColumn, sortDirection),
)}
columns={columns}
tableSortable
defaultSortedColumn="created"
defaultSortDirection="desc"
/>
{enrollmentData
? (
<Table
className="w-auto"
data={tableDataSortable.sort(
(firstElement, secondElement) => sort(firstElement, secondElement, sortColumn, sortDirection),
)}
columns={columns}
tableSortable
defaultSortedColumn="created"
defaultSortDirection="desc"
/>
)
: <PageLoading srMessage="Loading" />}
</Collapsible>
</section>
);
}

Enrollments.propTypes = {
data: PropTypes.arrayOf(PropTypes.object),
changeHandler: PropTypes.func.isRequired,
user: PropTypes.string.isRequired,
expanded: PropTypes.bool,
};

Enrollments.defaultProps = {
data: null,
expanded: false,
};
23 changes: 15 additions & 8 deletions src/users/enrollments/Enrollments.test.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { mount } from 'enzyme';
import React from 'react';

import { waitForComponentToPaint } from '../../setupTest';
import Enrollments from './Enrollments';
import { enrollmentsData } from '../data/test/enrollments';
import UserMessagesProvider from '../../userMessages/UserMessagesProvider';
import { waitForComponentToPaint } from '../../setupTest';
import * as api from '../data/api';

const EnrollmentPageWrapper = (props) => (
Expand All @@ -15,19 +14,27 @@ const EnrollmentPageWrapper = (props) => (

describe('Course Enrollments Listing', () => {
let wrapper;

beforeEach(() => {
wrapper = mount(<EnrollmentPageWrapper {...enrollmentsData} />);
const props = {
user: 'edX',
changeHandler: jest.fn(() => {}),
expanded: true,
};

beforeEach(async () => {
jest.spyOn(api, 'getEnrollments').mockImplementationOnce(() => Promise.resolve(enrollmentsData));
wrapper = mount(<EnrollmentPageWrapper {...props} />);
await waitForComponentToPaint(wrapper);
});

it('default collapsible with enrollment data', () => {
const collapsible = wrapper.find('CollapsibleAdvanced').find('.collapsible-trigger').hostNodes();
expect(collapsible.text()).toEqual('Enrollments (2)');
});

it('No Enrollment Data', () => {
const enrollmentData = { ...enrollmentsData, data: [] };
wrapper = mount(<Enrollments {...enrollmentData} />);
it('No Enrollment Data', async () => {
jest.spyOn(api, 'getEnrollments').mockImplementationOnce(() => Promise.resolve([]));
wrapper = mount(<Enrollments {...props} />);
await waitForComponentToPaint(wrapper);
const collapsible = wrapper.find('CollapsibleAdvanced').find('.collapsible-trigger').hostNodes();
expect(collapsible.text()).toEqual('Enrollments (0)');
});
Expand Down

0 comments on commit af1b687

Please sign in to comment.