Skip to content

Commit

Permalink
Refactor LearnerCreditAllocationTable (#1019)
Browse files Browse the repository at this point in the history
* chore: refactor LCM data table
  • Loading branch information
emrosarioa authored Aug 31, 2023
1 parent 9af4648 commit ef1692d
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 35 deletions.
1 change: 1 addition & 0 deletions src/components/learner-credit-management/BudgetCard-V2.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ const BudgetCard = ({
tableData={offerRedemptions}
fetchTableData={fetchOfferRedemptions}
enterpriseUUID={enterpriseUUID}
enterpriseSlug={enterpriseSlug}
/>
)}
</Stack>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
import React from 'react';
import PropTypes from 'prop-types';
import dayjs from 'dayjs';
import {
DataTable, useMediaQuery, breakpoints,
} from '@edx/paragon';

import { DataTable, Hyperlink } from '@edx/paragon';
import { getConfig } from '@edx/frontend-platform/config';
import TableTextFilter from './TableTextFilter';
import EmailAddressTableCell from './EmailAddressTableCell';
import { getCourseProductLineText } from '../../utils';

export const PAGE_SIZE = 20;
export const DEFAULT_PAGE = 0; // `DataTable` uses zero-index array

const getEnrollmentDetailsAccessor = row => ({
courseTitle: row.courseTitle,
userEmail: row.userEmail,
courseKey: row.courseKey,
});

const LearnerCreditAllocationTable = ({
isLoading,
tableData,
fetchTableData,
enterpriseUUID,
enterpriseSlug,
}) => {
const isDesktopTable = useMediaQuery({ minWidth: breakpoints.extraLarge.minWidth });
const defaultFilter = [];

return (
Expand All @@ -29,32 +33,41 @@ const LearnerCreditAllocationTable = ({
manualPagination
isFilterable
manualFilters
showFiltersInSidebar={isDesktopTable}
isLoading={isLoading}
defaultColumnValues={{ Filter: TableTextFilter }}
/* eslint-disable */
columns={[
{
Header: 'Email Address',
accessor: 'userEmail',
// eslint-disable-next-line react/prop-types, react/no-unstable-nested-components
Cell: ({ row }) => <EmailAddressTableCell row={row} enterpriseUUID={enterpriseUUID} />,
Header: 'Date',
accessor: 'enrollmentDate',
Cell: ({ row }) => dayjs(row.values.enrollmentDate).format('MMM D, YYYY'),
disableFilters: true,
},
{
Header: 'Course Name',
accessor: 'courseTitle',
Header: 'Enrollment details',
accessor: getEnrollmentDetailsAccessor,
Cell: ({ row }) => (
<>
<EmailAddressTableCell row={row} enterpriseUUID={enterpriseUUID} />
<div>
<Hyperlink
destination={`${getConfig().ENTERPRISE_LEARNER_PORTAL_URL}/${enterpriseSlug}/course/${row.original.courseKey}`}
target="_blank"
>
{row.original.courseTitle}
</Hyperlink>
</div>
</>
),
disableFilters: false,
disableSortBy: true,
},
{
Header: 'Course Price',
Header: 'Amount',
accessor: 'courseListPrice',
Cell: ({ row }) => `$${row.values.courseListPrice}`,
disableFilters: true,
},
{
Header: 'Date Spent',
accessor: 'enrollmentDate',
Cell: ({ row }) => dayjs(row.values.enrollmentDate).format('MMMM DD, YYYY'),
disableFilters: true,
},
{
Header: 'Product',
accessor: 'courseProductLine',
Expand All @@ -78,7 +91,6 @@ const LearnerCreditAllocationTable = ({
itemCount={tableData.itemCount}
pageCount={tableData.pageCount}
EmptyTableComponent={
// eslint-disable-next-line react/no-unstable-nested-components
() => {
if (isLoading) {
return null;
Expand All @@ -89,9 +101,11 @@ const LearnerCreditAllocationTable = ({
/>
);
};
/* eslint-enable */

LearnerCreditAllocationTable.propTypes = {
enterpriseUUID: PropTypes.string.isRequired,
enterpriseSlug: PropTypes.string.isRequired,
isLoading: PropTypes.bool.isRequired,
tableData: PropTypes.shape({
results: PropTypes.arrayOf(PropTypes.shape({
Expand Down
13 changes: 5 additions & 8 deletions src/components/learner-credit-management/data/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,15 @@ const applySortByToOptions = (sortBy, options) => {
};

const applyFiltersToOptions = (filters, options) => {
const userSearchQuery = filters?.find(filter => filter.id === 'userEmail')?.value;
const courseTitleSearchQuery = filters?.find(filter => filter.id === 'courseTitle')?.value;
const courseProductLineSearchQuery = filters?.find(filter => filter.id === 'courseProductLine')?.value;
if (userSearchQuery) {
Object.assign(options, { search: userSearchQuery });
}
if (courseTitleSearchQuery) {
Object.assign(options, { searchCourse: courseTitleSearchQuery });
}
const searchQuery = filters?.find(filter => filter.id.toLowerCase() === 'enrollment details')?.value;

if (courseProductLineSearchQuery) {
Object.assign(options, { courseProductLine: courseProductLineSearchQuery });
}
if (searchQuery) {
Object.assign(options, { searchAll: searchQuery });
}
};

export const useOfferRedemptions = (enterpriseUUID, offerId) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,7 @@ describe('useOfferRedemptions', () => {
{ id: 'enrollmentDate', desc: true },
],
filters: [
{ id: 'userEmail', value: mockOfferEnrollments[0].user_email },
{ id: 'courseTitle', value: mockOfferEnrollments[0].course_title },
{ id: 'Enrollment Details', value: mockOfferEnrollments[0].user_email },
],
});
});
Expand All @@ -118,8 +117,7 @@ describe('useOfferRedemptions', () => {
pageSize: 20,
offerId: mockEnterpriseOffer.id,
ordering: '-enrollment_date', // default sort order
search: mockOfferEnrollments[0].user_email,
searchCourse: mockOfferEnrollments[0].course_title,
searchAll: mockOfferEnrollments[0].user_email,
ignoreNullCourseListPrice: true,
};
expect(EnterpriseDataApiService.fetchCourseEnrollments).toHaveBeenCalledWith(
Expand Down
1 change: 1 addition & 0 deletions src/components/learner-credit-management/data/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export const transformUtilizationTableResults = results => results.map(result =>
enrollmentDate: result.enrollmentDate,
courseProductLine: result.courseProductLine,
uuid: uuidv4(),
courseKey: result.courseKey,
}));

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ describe('<BudgetCard />', () => {
const elementsWithTestId = screen.getAllByTestId('view-budget');
const firstElementWithTestId = elementsWithTestId[0];
await waitFor(() => userEvent.click(firstElementWithTestId));
expect(screen.getByText('Filters'));
expect(screen.getByText('No results found'));
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import { IntlProvider } from '@edx/frontend-platform/i18n';

import LearnerCreditAllocationTable from '../LearnerCreditAllocationTable';

jest.mock('@edx/frontend-platform/config', () => ({
getConfig: () => ({ ENTERPRISE_LEARNER_PORTAL_URL: 'https://enterprise.edx.org' }),
}));

const LearnerCreditAllocationTableWrapper = (props) => (
<IntlProvider locale="en">
<LearnerCreditAllocationTable {...props} />
Expand All @@ -19,6 +23,7 @@ describe('<LearnerCreditAllocationTable />', () => {
enterpriseUUID: 'test-enterprise-id',
isLoading: false,
budgetType: 'OCM',
enterpriseSlug: 'test-enterprise-slug',
tableData: {
results: [{
userEmail: '[email protected]',
Expand All @@ -36,7 +41,6 @@ describe('<LearnerCreditAllocationTable />', () => {

render(<LearnerCreditAllocationTableWrapper {...props} />);

expect(screen.getByText('Open', { exact: false }));
expect(screen.getByText(props.tableData.results[0].userEmail.toString(), {
exact: false,
}));
Expand All @@ -46,7 +50,7 @@ describe('<LearnerCreditAllocationTable />', () => {
expect(screen.getByText(props.tableData.results[0].courseListPrice.toString(), {
exact: false,
}));
expect(screen.getByText('February', { exact: false }));
expect(screen.getByText('Feb', { exact: false }));
});
it('renders with empty table data', () => {
const props = {
Expand All @@ -66,4 +70,34 @@ describe('<LearnerCreditAllocationTable />', () => {

expect(screen.getByText('No results found', { exact: false }));
});

it('constructs the correct URL for the course', () => {
const props = {
enterpriseUUID: 'test-enterprise-id',
isLoading: false,
budgetType: 'OCM',
enterpriseSlug: 'test-enterprise-slug',
tableData: {
results: [{
userEmail: '[email protected]',
courseTitle: 'course-title',
courseKey: 'course-v1:edX=CTL.SC101x.3T2019',
courseListPrice: 100,
enrollmentDate: '2-2-23',
courseProductLine: 'OCM',
}],
itemCount: 1,
pageCount: 1,
},
fetchTableData: jest.fn(),
};
props.fetchTableData.mockReturnValue(props.tableData);

render(<LearnerCreditAllocationTableWrapper {...props} />);

const expectedLink = 'https://enterprise.edx.org/test-enterprise-slug/course/course-v1:edX=CTL.SC101x.3T2019';
const courseLinkElement = screen.getByText('course-title');

expect(courseLinkElement.getAttribute('href')).toBe(expectedLink);
});
});

0 comments on commit ef1692d

Please sign in to comment.