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

feat: [AXM-1150] display course certificates #16

Merged
merged 1 commit into from
Dec 13, 2024
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
16,724 changes: 6,496 additions & 10,228 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
"@fortawesome/react-fontawesome": "0.2.2",
"@openedx/frontend-plugin-framework": "^1.2.0",
"@openedx/paragon": "^22.2.2",
"ajv": "^8.12.0",
"ajv-keywords": "^5.1.0",
"axios": "^1.7.9",
"babel-polyfill": "6.26.0",
"core-js": "3.39.0",
"js-cookie": "3.0.5",
Expand All @@ -59,7 +62,9 @@
"react-router": "6.28.0",
"react-router-dom": "6.28.0",
"redux": "4.2.1",
"regenerator-runtime": "0.14.1"
"regenerator-runtime": "0.14.1",
"schema-utils": "^4.2.0",
"webpack-dev-server": "^4.15.2"
},
"devDependencies": {
"@edx/browserslist-config": "^1.2.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import {
import { Hyperlink, DropdownButton, Dropdown } from '@openedx/paragon';
import messages from './messages';

function ProgramCertificate({
function Certificate({
intl,
program_title: programTitle,
program_org: programOrg,
type,
credential_title: certificateTitle,
credential_org: certificateOrg,
modified_date: modifiedDate,
uuid,
handleCreate,
Expand Down Expand Up @@ -48,15 +49,17 @@ function ProgramCertificate({
<div className="card-body d-flex flex-column">
<div className="card-title">
<p className="small mb-0">
{intl.formatMessage(messages.certificateCardName)}
{type === 'program'
? intl.formatMessage(messages.programCertificateCardName)
: intl.formatMessage(messages.courseCertificateCardName)}
</p>
<h4 className="certificate-title">{programTitle}</h4>
<h4 className="certificate-title">{certificateTitle}</h4>
</div>
<p className="small mb-0">
<p className="small mb-0 mt-auto">
{intl.formatMessage(messages.certificateCardOrgLabel)}
</p>
<p className="h6 mb-4">
{programOrg
{certificateOrg
|| intl.formatMessage(messages.certificateCardNoOrgText)}
</p>
<p className="small mb-2">
Expand All @@ -71,10 +74,11 @@ function ProgramCertificate({
);
}

ProgramCertificate.propTypes = {
Certificate.propTypes = {
intl: intlShape.isRequired,
program_title: PropTypes.string.isRequired,
program_org: PropTypes.string.isRequired,
type: PropTypes.oneOf(['program', 'course']),
credential_title: PropTypes.string.isRequired,
credential_org: PropTypes.string.isRequired,
modified_date: PropTypes.string.isRequired,
uuid: PropTypes.string.isRequired,
handleCreate: PropTypes.func.isRequired,
Expand All @@ -86,4 +90,4 @@ ProgramCertificate.propTypes = {
).isRequired,
};

export default injectIntl(ProgramCertificate);
export default injectIntl(Certificate);
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// eslint-disable-next-line no-restricted-exports
export { default } from './ProgramCertificate';
export { default } from './Certificate';
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { defineMessages } from '@edx/frontend-platform/i18n';

const messages = defineMessages({
certificateCardName: {
id: 'certificate.card.name',
programCertificateCardName: {
id: 'certificate.program.card.name',
defaultMessage: 'Program Certificate',
description: 'A title text of the available program certificate item.',
},
courseCertificateCardName: {
id: 'certificate.course.card.name',
defaultMessage: 'Course Certificate',
description: 'A title text of the available course certificate item.',
},
certificateCardOrgLabel: {
id: 'certificate.card.organization.label',
defaultMessage: 'From',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import React from 'react';
import {
render, screen, cleanup, initializeMockApp, fireEvent,
} from '../../../setupTest';
import ProgramCertificate from '..';
import Certificate from '../Certificate';

describe('program-certificate', () => {
beforeAll(async () => {
Expand All @@ -15,30 +15,39 @@ describe('program-certificate', () => {
afterEach(cleanup);

const props = {
program_title: 'Program name',
program_org: 'Test org',
credential_title: 'Certificate title',
credential_org: 'Test org',
modified_date: '2023-02-02',
storages: [{ id: 'storageId', name: 'storageName' }],
handleCreate: jest.fn(),
};

it('renders the component', () => {
render(<ProgramCertificate {...props} />);
it('renders the component with type programm', () => {
render(<Certificate {...props} type="program" />);

expect(screen.getByText('Program Certificate')).toBeTruthy();
expect(screen.getByText(props.program_title)).toBeTruthy();
expect(screen.getByText(props.program_org)).toBeTruthy();
expect(screen.getByText(props.credential_title)).toBeTruthy();
expect(screen.getByText(props.credential_org)).toBeTruthy();
expect(screen.getByText('Awarded on 2/2/2023')).toBeTruthy();
});

it('should display "No organization" if Program Organization wasn\'t set', () => {
render(<ProgramCertificate {...props} program_org="" />);
it('renders the component with type course', () => {
render(<Certificate {...props} type="course" />);

expect(screen.getByText('Course Certificate')).toBeTruthy();
expect(screen.getByText(props.credential_title)).toBeTruthy();
expect(screen.getByText(props.credential_org)).toBeTruthy();
expect(screen.getByText('Awarded on 2/2/2023')).toBeTruthy();
});

it('should display "No organization" if Organization wasn\'t set', () => {
render(<Certificate {...props} credential_org="" />);

expect(screen.getByText('No organization')).toBeTruthy();
});

it('renders modal by clicking on a create button', () => {
render(<ProgramCertificate {...props} />);
render(<Certificate {...props} />);
fireEvent.click(screen.getByText('Create'));

expect(screen.findByTitle('Verifiable credential')).toBeTruthy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import messages from './messages';
import appStoreImg from '../../assets/images/appStore.png';
import googlePlayImg from '../../assets/images/googleplay.png';

function ProgramCertificateModal({
function CertificateModal({
intl, isOpen, close, data,
}) {
const {
Expand Down Expand Up @@ -171,11 +171,11 @@ function ProgramCertificateModal({
);
}

ProgramCertificateModal.propTypes = {
CertificateModal.propTypes = {
intl: intlShape.isRequired,
isOpen: PropTypes.bool.isRequired,
close: PropTypes.func.isRequired,
data: PropTypes.shape.isRequired,
};

export default injectIntl(ProgramCertificateModal);
export default injectIntl(CertificateModal);
2 changes: 2 additions & 0 deletions src/components/CertificateModal/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line no-restricted-exports
export { default } from './CertificateModal';
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const messages = defineMessages({
id: 'credentials.modal.mobile.title',
defaultMessage:
'To download a verifiable credential to your mobile wallet application, please follow the instructions below.',
description: 'Text for a mobile dialog of the program certificate.',
description: 'Text for a mobile dialog of the certificate.',
},
certificateModalAppStoreBtn: {
id: 'credentials.modal.instruction.appStore.button',
Expand Down Expand Up @@ -84,9 +84,9 @@ const messages = defineMessages({
credentialsModalError: {
id: 'credentials.modal.error',
defaultMessage:
'An error occurred attempting to retrieve your program certificate. Please try again later.',
'An error occurred attempting to retrieve your certificate. Please try again later.',
description:
"An error message indicating there is a problem retrieving the user's program certificate data",
"An error message indicating there is a problem retrieving the user's certificate data",
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @jest-environment jsdom
*/
import React from 'react';
import ProgramCertificateModal from '..';
import CertificateModal from '..';
import {
render, screen, cleanup, initializeMockApp,
} from '../../../setupTest';
Expand All @@ -18,15 +18,15 @@ const props = {
},
};

describe('program-certificate-modal', () => {
describe('certificate-modal', () => {
beforeAll(async () => {
await initializeMockApp();
});
beforeEach(() => jest.resetModules);
afterEach(cleanup);

it('renders the component', () => {
render(<ProgramCertificateModal {...props} />);
render(<CertificateModal {...props} />);
expect(screen.getByText('Verifiable credential')).toBeTruthy();
expect(screen.getByText('Close modal window')).toBeTruthy();
});
Expand Down
Loading
Loading