feat: update related program location (#104)

This commit is contained in:
leangseu-edx
2023-02-13 14:12:27 -05:00
committed by GitHub
parent a13085a6a1
commit 0933d185af
51 changed files with 1507 additions and 32 deletions

View File

@@ -0,0 +1,23 @@
import React from 'react';
import PropTypes from 'prop-types';
export const ProgramsList = ({ programs }) => (
<ul className="related-programs-list-container">
{programs.map((program) => (
<li key={program.programUrl} className="my-2">
<a href={program.programUrl}>{program.title}</a>
</li>
))}
</ul>
);
ProgramsList.propTypes = {
programs: PropTypes.arrayOf(
PropTypes.shape({
programUrl: PropTypes.string,
title: PropTypes.string,
}),
).isRequired,
};
export default ProgramsList;

View File

@@ -0,0 +1,23 @@
import { shallow } from 'enzyme';
import { ProgramsList } from './ProgramsList';
describe('ProgramsList', () => {
const programs = [
{
programUrl: 'http://example.com',
title: 'Example Program 1',
},
{
programUrl: 'http://example.com',
title: 'Example Program 2',
},
];
it('renders correctly', () => {
const wrapper = shallow(<ProgramsList programs={programs} />);
expect(wrapper).toMatchSnapshot();
expect(wrapper.find('li').length).toEqual(programs.length);
});
});

View File

@@ -0,0 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ProgramsList renders correctly 1`] = `
<ul
className="related-programs-list-container"
>
<li
className="my-2"
key="http://example.com"
>
<a
href="http://example.com"
>
Example Program 1
</a>
</li>
<li
className="my-2"
key="http://example.com"
>
<a
href="http://example.com"
>
Example Program 2
</a>
</li>
</ul>
`;

View File

@@ -0,0 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`RelatedProgramsBanner render with programs 1`] = `
<Banner
className="bg-white border-top border-bottom mb-0 related-programs-banner"
icon={[MockFunction icons.Program]}
variant="info"
>
Related Programs:
<ProgramsList
programs={
Array [
Object {
"title": "Program 1",
"url": "http://example.com/program1",
},
Object {
"title": "Program 2",
"url": "http://example.com/program2",
},
]
}
/>
</Banner>
`;

View File

@@ -0,0 +1,34 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Program } from '@edx/paragon/icons';
import { useIntl } from '@edx/frontend-platform/i18n';
import { reduxHooks } from 'hooks';
import Banner from 'components/Banner';
import ProgramList from './ProgramsList';
import messages from './messages';
export const RelatedProgramsBanner = ({ cardId }) => {
const { formatMessage } = useIntl();
const programData = reduxHooks.useCardRelatedProgramsData(cardId);
return (
programData?.length > 0 && (
<Banner
icon={Program}
className="bg-white border-top border-bottom mb-0 related-programs-banner"
>
{formatMessage(messages.relatedPrograms)}
<ProgramList programs={programData.list} />
</Banner>
)
);
};
RelatedProgramsBanner.propTypes = {
cardId: PropTypes.string.isRequired,
};
export default RelatedProgramsBanner;

View File

@@ -0,0 +1,42 @@
import { shallow } from 'enzyme';
import { reduxHooks } from 'hooks';
import RelatedProgramsBanner from '.';
jest.mock('./ProgramsList', () => 'ProgramsList');
jest.mock('hooks', () => ({
reduxHooks: {
useCardRelatedProgramsData: jest.fn(),
},
}));
const cardId = 'test-card-id';
describe('RelatedProgramsBanner', () => {
test('render empty', () => {
reduxHooks.useCardRelatedProgramsData.mockReturnValue({
length: 0,
});
const el = shallow(<RelatedProgramsBanner cardId={cardId} />);
expect(el.isEmptyRender()).toEqual(true);
});
test('render with programs', () => {
reduxHooks.useCardRelatedProgramsData.mockReturnValue({
list: [
{
title: 'Program 1',
url: 'http://example.com/program1',
},
{
title: 'Program 2',
url: 'http://example.com/program2',
},
],
length: 2,
});
const el = shallow(<RelatedProgramsBanner cardId={cardId} />);
expect(el).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,31 @@
import { StrictDict } from 'utils';
export const messages = StrictDict({
relatedPrograms: {
id: 'learner-dash.courseCard.banners.relatedPrograms',
description: 'title for related programs banner',
defaultMessage: 'Related Programs: ',
},
expandBanner: {
id: 'learner-dash.courseCard.banners.expandBanner',
description: 'expand banner button text',
defaultMessage: 'More',
},
expandBannerAlt: {
id: 'learner-dash.courseCard.banners.expandBannerAlt',
description: 'expand banner button alt text',
defaultMessage: 'Expand banner icon',
},
collapseBanner: {
id: 'learner-dash.courseCard.banners.collapseBanner',
description: 'collapse banner button text',
defaultMessage: 'Less',
},
collapseBannerAlt: {
id: 'learner-dash.courseCard.banners.collapseBannerAlt',
description: 'collapse banner button alt text',
defaultMessage: 'Collapse banner icon',
},
});
export default messages;

View File

@@ -0,0 +1,41 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CourseCardBanners render with isEnrolled false 1`] = `
<div
className="course-card-banners"
data-testid="CourseCardBanners"
>
<RelatedProgramsBanner
cardId="test-card-id"
/>
<CourseBanner
cardId="test-card-id"
/>
<EntitlementBanner
cardId="test-card-id"
/>
</div>
`;
exports[`CourseCardBanners renders default CourseCardBanners 1`] = `
<div
className="course-card-banners"
data-testid="CourseCardBanners"
>
<RelatedProgramsBanner
cardId="test-card-id"
/>
<CourseBanner
cardId="test-card-id"
/>
<EntitlementBanner
cardId="test-card-id"
/>
<CertificateBanner
cardId="test-card-id"
/>
<CreditBanner
cardId="test-card-id"
/>
</div>
`;

View File

@@ -7,11 +7,13 @@ import CourseBanner from './CourseBanner';
import CertificateBanner from './CertificateBanner';
import CreditBanner from './CreditBanner';
import EntitlementBanner from './EntitlementBanner';
import RelatedProgramsBanner from './RelatedProgramsBanner';
export const CourseCardBanners = ({ cardId }) => {
const { isEnrolled } = reduxHooks.useCardEnrollmentData(cardId);
return (
<div className="course-card-banners" data-testid="CourseCardBanners">
<RelatedProgramsBanner cardId={cardId} />
<CourseBanner cardId={cardId} />
<EntitlementBanner cardId={cardId} />
{isEnrolled && <CertificateBanner cardId={cardId} />}

View File

@@ -0,0 +1,32 @@
import { shallow } from 'enzyme';
import { reduxHooks } from 'hooks';
import CourseCardBanners from '.';
jest.mock('./CourseBanner', () => 'CourseBanner');
jest.mock('./CertificateBanner', () => 'CertificateBanner');
jest.mock('./CreditBanner', () => 'CreditBanner');
jest.mock('./EntitlementBanner', () => 'EntitlementBanner');
jest.mock('./RelatedProgramsBanner', () => 'RelatedProgramsBanner');
jest.mock('hooks', () => ({
reduxHooks: {
useCardEnrollmentData: jest.fn(() => ({ isEnrolled: true })),
},
}));
describe('CourseCardBanners', () => {
const props = {
cardId: 'test-card-id',
};
test('renders default CourseCardBanners', () => {
const wrapper = shallow(<CourseCardBanners {...props} />);
expect(wrapper).toMatchSnapshot();
});
test('render with isEnrolled false', () => {
reduxHooks.useCardEnrollmentData.mockReturnValueOnce({ isEnrolled: false });
const wrapper = shallow(<CourseCardBanners {...props} />);
expect(wrapper).toMatchSnapshot();
});
});