From ef1692d0541cd160fbd700a9cde4f3cf7d493f6c Mon Sep 17 00:00:00 2001
From: Emily Rosario-Aquin <129111440+emrosarioa@users.noreply.github.com>
Date: Thu, 31 Aug 2023 13:43:12 -0500
Subject: [PATCH] Refactor LearnerCreditAllocationTable (#1019)
* chore: refactor LCM data table
---
.../BudgetCard-V2.jsx | 1 +
.../LearnerCreditAllocationTable.jsx | 54 ++++++++++++-------
.../learner-credit-management/data/hooks.js | 13 ++---
.../data/tests/hooks.test.js | 6 +--
.../learner-credit-management/data/utils.js | 1 +
.../tests/BudgetCard.test.jsx | 1 -
.../LearnerCreditAllocationTable.test.jsx | 38 ++++++++++++-
7 files changed, 79 insertions(+), 35 deletions(-)
diff --git a/src/components/learner-credit-management/BudgetCard-V2.jsx b/src/components/learner-credit-management/BudgetCard-V2.jsx
index 16132bf012..d9a1db40c9 100644
--- a/src/components/learner-credit-management/BudgetCard-V2.jsx
+++ b/src/components/learner-credit-management/BudgetCard-V2.jsx
@@ -143,6 +143,7 @@ const BudgetCard = ({
tableData={offerRedemptions}
fetchTableData={fetchOfferRedemptions}
enterpriseUUID={enterpriseUUID}
+ enterpriseSlug={enterpriseSlug}
/>
)}
diff --git a/src/components/learner-credit-management/LearnerCreditAllocationTable.jsx b/src/components/learner-credit-management/LearnerCreditAllocationTable.jsx
index e5eceb7766..7422b41594 100644
--- a/src/components/learner-credit-management/LearnerCreditAllocationTable.jsx
+++ b/src/components/learner-credit-management/LearnerCreditAllocationTable.jsx
@@ -1,10 +1,8 @@
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';
@@ -12,13 +10,19 @@ 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 (
@@ -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 }) => ,
+ 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 }) => (
+ <>
+
+
+
+ {row.original.courseTitle}
+
+
+ >
+ ),
+ 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',
@@ -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;
@@ -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({
diff --git a/src/components/learner-credit-management/data/hooks.js b/src/components/learner-credit-management/data/hooks.js
index 7ff74aaa69..585970c35e 100644
--- a/src/components/learner-credit-management/data/hooks.js
+++ b/src/components/learner-credit-management/data/hooks.js
@@ -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) => {
diff --git a/src/components/learner-credit-management/data/tests/hooks.test.js b/src/components/learner-credit-management/data/tests/hooks.test.js
index fa03c60f9e..8ab61bce2f 100644
--- a/src/components/learner-credit-management/data/tests/hooks.test.js
+++ b/src/components/learner-credit-management/data/tests/hooks.test.js
@@ -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 },
],
});
});
@@ -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(
diff --git a/src/components/learner-credit-management/data/utils.js b/src/components/learner-credit-management/data/utils.js
index 30b0efba01..65524c1346 100644
--- a/src/components/learner-credit-management/data/utils.js
+++ b/src/components/learner-credit-management/data/utils.js
@@ -68,6 +68,7 @@ export const transformUtilizationTableResults = results => results.map(result =>
enrollmentDate: result.enrollmentDate,
courseProductLine: result.courseProductLine,
uuid: uuidv4(),
+ courseKey: result.courseKey,
}));
/**
diff --git a/src/components/learner-credit-management/tests/BudgetCard.test.jsx b/src/components/learner-credit-management/tests/BudgetCard.test.jsx
index cfc91ded7c..7d8f349bda 100644
--- a/src/components/learner-credit-management/tests/BudgetCard.test.jsx
+++ b/src/components/learner-credit-management/tests/BudgetCard.test.jsx
@@ -141,7 +141,6 @@ describe('', () => {
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'));
});
});
diff --git a/src/components/learner-credit-management/tests/LearnerCreditAllocationTable.test.jsx b/src/components/learner-credit-management/tests/LearnerCreditAllocationTable.test.jsx
index fb79748c70..f67aa0e8bb 100644
--- a/src/components/learner-credit-management/tests/LearnerCreditAllocationTable.test.jsx
+++ b/src/components/learner-credit-management/tests/LearnerCreditAllocationTable.test.jsx
@@ -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) => (
@@ -19,6 +23,7 @@ describe('', () => {
enterpriseUUID: 'test-enterprise-id',
isLoading: false,
budgetType: 'OCM',
+ enterpriseSlug: 'test-enterprise-slug',
tableData: {
results: [{
userEmail: 'test@example.com',
@@ -36,7 +41,6 @@ describe('', () => {
render();
- expect(screen.getByText('Open', { exact: false }));
expect(screen.getByText(props.tableData.results[0].userEmail.toString(), {
exact: false,
}));
@@ -46,7 +50,7 @@ describe('', () => {
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 = {
@@ -66,4 +70,34 @@ describe('', () => {
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: 'test@example.com',
+ 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();
+
+ 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);
+ });
});