Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Revert "feat: subsidy box points to learner credit (#810)"" #822

Merged
merged 1 commit into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 0 additions & 72 deletions src/components/dashboard/sidebar/EnterpriseOffersSummaryCard.jsx

This file was deleted.

62 changes: 62 additions & 0 deletions src/components/dashboard/sidebar/LearnerCreditSummaryCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Badge, Row, Col } from '@edx/paragon';
import dayjs from 'dayjs';
import {
LEARNER_CREDIT_SUMMARY_CARD_TITLE,
LEARNER_CREDIT_ACTIVE_BADGE_LABEL,
LEARNER_CREDIT_ACTIVE_BADGE_VARIANT,
LEARNER_CREDIT_CARD_SUMMARY,
} from './data/constants';
import SidebarCard from './SidebarCard';

const LearnerCreditSummaryCard = ({
className, expirationDate, searchCoursesCta,
}) => (
<SidebarCard
title={
(
<div className="d-flex align-items-center justify-content-between">
<h3 className="m-0">{LEARNER_CREDIT_SUMMARY_CARD_TITLE}</h3>
<Badge
variant={LEARNER_CREDIT_ACTIVE_BADGE_VARIANT}
className="ml-2"
data-testid="learner-credit-status-badge"
>
{LEARNER_CREDIT_ACTIVE_BADGE_LABEL}
</Badge>
</div>
)
}
cardClassNames={className}
>
<p data-testid="learner-credit-summary-text">
{ LEARNER_CREDIT_CARD_SUMMARY }
</p>

{expirationDate && (
<p data-testid="learner-credit-summary-end-date-text">
Available until <b>{dayjs(expirationDate).format('MMM D, YYYY')}</b>
</p>
)}

{searchCoursesCta && (
<Row className="mt-3 d-flex justify-content-end">
<Col xl={12}>{searchCoursesCta}</Col>
</Row>
)}
</SidebarCard>
);

LearnerCreditSummaryCard.propTypes = {
expirationDate: PropTypes.string.isRequired,
className: PropTypes.string,
searchCoursesCta: PropTypes.node,
};

LearnerCreditSummaryCard.defaultProps = {
className: undefined,
searchCoursesCta: undefined,
};

export default LearnerCreditSummaryCard;
28 changes: 23 additions & 5 deletions src/components/dashboard/sidebar/SubsidiesSummary.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,23 @@ import { Button } from '@edx/paragon';
import classNames from 'classnames';
import CouponCodesSummaryCard from './CouponCodesSummaryCard';
import SubscriptionSummaryCard from './SubscriptionSummaryCard';
import EnterpriseOffersSummaryCard from './EnterpriseOffersSummaryCard';
import LearnerCreditSummaryCard from './LearnerCreditSummaryCard';
import { UserSubsidyContext } from '../../enterprise-user-subsidy';
import { LICENSE_STATUS } from '../../enterprise-user-subsidy/data/constants';
import { CATALOG_ACCESS_CARD_BUTTON_TEXT } from './data/constants';
import SidebarCard from './SidebarCard';
import { CourseEnrollmentsContext } from '../main-content/course-enrollments/CourseEnrollmentsContextProvider';
import { SubsidyRequestsContext, SUBSIDY_TYPE } from '../../enterprise-subsidy-requests';
import { getOfferExpiringFirst, getPolicyExpiringFirst } from './utils';

function getLearnerCreditSummaryCardData({ enterpriseOffers, redeemableLearnerCreditPolicies }) {
const enterpriseOfferExpiringFirst = getOfferExpiringFirst(enterpriseOffers);
const learnerCreditPolicyExpiringFirst = getPolicyExpiringFirst(redeemableLearnerCreditPolicies);
return {
expirationDate: learnerCreditPolicyExpiringFirst?.subsidyExpirationDate
|| enterpriseOfferExpiringFirst?.endDatetime,
};
}

const SubsidiesSummary = ({
className, showSearchCoursesCta, totalCoursesEligibleForCertificate, courseEndDate, programProgressPage,
Expand All @@ -35,8 +45,14 @@ const SubsidiesSummary = ({
couponCodes: { couponCodesCount },
enterpriseOffers,
canEnrollWithEnterpriseOffers,
redeemableLearnerCreditPolicies,
} = useContext(UserSubsidyContext);

const learnerCreditSummaryCardData = getLearnerCreditSummaryCardData({
enterpriseOffers,
redeemableLearnerCreditPolicies,
});

const {
requestsBySubsidyType,
} = useContext(SubsidyRequestsContext);
Expand All @@ -54,9 +70,10 @@ const SubsidiesSummary = ({
&& userSubscriptionLicense?.status === LICENSE_STATUS.ACTIVATED) || licenseRequests.length > 0;

const hasAssignedCodesOrCodeRequests = couponCodesCount > 0 || couponCodeRequests.length > 0;
const hasAvailableLearnerCreditPolicies = redeemableLearnerCreditPolicies?.length > 0;

const hasAvailableSubsidyOrRequests = hasActiveLicenseOrLicenseRequest
|| hasAssignedCodesOrCodeRequests || canEnrollWithEnterpriseOffers;
|| hasAssignedCodesOrCodeRequests || canEnrollWithEnterpriseOffers || hasAvailableLearnerCreditPolicies;

if (!hasAvailableSubsidyOrRequests) {
return null;
Expand Down Expand Up @@ -100,10 +117,11 @@ const SubsidiesSummary = ({
className="border-0 shadow-none"
/>
)}
{canEnrollWithEnterpriseOffers && (
<EnterpriseOffersSummaryCard
{(canEnrollWithEnterpriseOffers || hasAvailableLearnerCreditPolicies)
&& learnerCreditSummaryCardData?.expirationDate && (
<LearnerCreditSummaryCard
className="border-0 shadow-none"
offers={enterpriseOffers}
expirationDate={learnerCreditSummaryCardData.expirationDate}
/>
)}
</div>
Expand Down
6 changes: 6 additions & 0 deletions src/components/dashboard/sidebar/data/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ export const ENTERPRISE_OFFER_ACTIVE_BADGE_LABEL = 'Active';
export const ENTERPRISE_OFFER_ACTIVE_BADGE_VARIANT = 'success';
export const ENTERPRISE_OFFER_SUMMARY_CARD_SUMMARY = 'Apply your organization\'s learner credit balance to enroll into courses with no out of pocket cost.';

// LearnerCreditSummaryCard
export const LEARNER_CREDIT_SUMMARY_CARD_TITLE = 'Learner Credit';
export const LEARNER_CREDIT_ACTIVE_BADGE_LABEL = 'Active';
export const LEARNER_CREDIT_ACTIVE_BADGE_VARIANT = 'success';
export const LEARNER_CREDIT_CARD_SUMMARY = 'Apply your organization\'s learner credit balance to enroll into courses with no out of pocket cost.';

// Dashboard Sidebar texts
export const CATALOG_ACCESS_CARD_BUTTON_TEXT = 'Find a course';
export const NEED_HELP_BLOCK_TITLE = 'Need help?';
Expand Down
47 changes: 46 additions & 1 deletion src/components/dashboard/sidebar/tests/DashboardSidebar.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
LICENSE_REQUESTED_NOTICE,
COUPON_CODES_SUMMARY_NOTICE,
ENTERPRISE_OFFER_SUMMARY_CARD_TITLE,
LEARNER_CREDIT_SUMMARY_CARD_TITLE,
} from '../data/constants';
import { LICENSE_STATUS } from '../../../enterprise-user-subsidy/data/constants';
import CourseEnrollmentsContextProvider from '../../main-content/course-enrollments/CourseEnrollmentsContextProvider';
Expand Down Expand Up @@ -61,6 +62,7 @@ describe('<DashboardSidebar />', () => {
couponCodesCount: 0,
},
enterpriseOffers: [],
redeemableLearnerCreditPolicies: undefined,
};
const initialAppState = {
enterpriseConfig: {
Expand Down Expand Up @@ -173,7 +175,7 @@ describe('<DashboardSidebar />', () => {
);
expect(screen.queryByText(SUBSCRIPTION_SUMMARY_CARD_TITLE)).toBeFalsy();
});
test('Enterprise offers summary card is displayed when enterprise has active offers and no subscriptions or coupons', () => {
test('Enterprise offers summary card is displayed when enterprise has active offers and no subscriptions or coupons or learner credit', () => {
renderWithRouter(
<DashboardSidebarWithContext
initialAppState={initialAppState}
Expand Down Expand Up @@ -219,6 +221,49 @@ describe('<DashboardSidebar />', () => {
expect(screen.queryByText(SUBSCRIPTION_SUMMARY_CARD_TITLE)).not.toBeInTheDocument();
expect(screen.queryByText(COUPON_CODES_SUMMARY_NOTICE)).toBeInTheDocument();
});

test('Learner credit summary card is displayed when enterprise has learner credit', () => {
renderWithRouter(
<DashboardSidebarWithContext
initialAppState={initialAppState}
initialUserSubsidyState={{
...defaultUserSubsidyState,
redeemableLearnerCreditPolicies: [{
remainingBalancePerUser: 5,
subsidyExpirationDate: '2030-01-01 12:00:00Z',
active: true,
}],
}}
/>,
);
expect(screen.queryByText(LEARNER_CREDIT_SUMMARY_CARD_TITLE)).toBeInTheDocument();
});

test('Only learner credit summary card is displayed when enterprise has both; learner credit and offers', () => {
const policyExpirationDate = '2030-01-01 12:00:00Z';
const offerEndDate = '2027-10-25';
renderWithRouter(
<DashboardSidebarWithContext
initialAppState={initialAppState}
initialUserSubsidyState={{
...defaultUserSubsidyState,
redeemableLearnerCreditPolicies: [{
remainingBalancePerUser: 5,
subsidyExpirationDate: policyExpirationDate,
active: true,
}],
enterpriseOffers: [{
uuid: 'enterprise-offer-id',
endDatetime: offerEndDate,
}],
canEnrollWithEnterpriseOffers: true,
}}
/>,
);
expect(screen.getByText('2030', { exact: false })).toBeInTheDocument();
expect(screen.queryByText('2027', { exact: false })).toBeFalsy();
});

test('Find a course button is not rendered when user has no coupon codes or license subsidy', () => {
renderWithRouter(
<DashboardSidebarWithContext
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react';
import '@testing-library/jest-dom/extend-expect';
import { screen, render } from '@testing-library/react';
import LearnerCreditSummaryCard from '../LearnerCreditSummaryCard';
import { LEARNER_CREDIT_SUMMARY_CARD_TITLE } from '../data/constants';

const TEST_EXPIRATION_DATE = '2022-06-01T00:00:00Z';

describe('<LearnerCreditSummaryCard />', () => {
it('should render searchCoursesCta', () => {
const cta = 'Search Courses';
render(
<LearnerCreditSummaryCard
expirationDate={TEST_EXPIRATION_DATE}
searchCoursesCta={
<button type="button">{cta}</button>
}
/>,
);
expect(screen.getByText(LEARNER_CREDIT_SUMMARY_CARD_TITLE)).toBeInTheDocument();
expect(screen.getByText(cta)).toBeInTheDocument();
});

it('should render default summary text', () => {
render(
<LearnerCreditSummaryCard
expirationDate={TEST_EXPIRATION_DATE}
/>,
);
expect(screen.getByTestId('learner-credit-summary-text')).toBeInTheDocument();
});

it('should render the expiration date passed as prop', () => {
render(
<LearnerCreditSummaryCard
expirationDate={TEST_EXPIRATION_DATE}
/>,
);
expect(screen.getByTestId('learner-credit-summary-end-date-text')).toBeInTheDocument();
expect(screen.getByText('2022', { exact: false })).toBeInTheDocument();
});
});
Loading
Loading