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); + }); });