Skip to content

Commit

Permalink
feat: display course credentials on VC page
Browse files Browse the repository at this point in the history
  • Loading branch information
kyrylo-kh committed Jan 28, 2025
1 parent db6fc53 commit 68d2cfd
Show file tree
Hide file tree
Showing 23 changed files with 2,242 additions and 3,797 deletions.
5,703 changes: 2,041 additions & 3,662 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
"@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",
"babel-polyfill": "6.26.0",
"core-js": "3.40.0",
"js-cookie": "3.0.5",
Expand All @@ -59,7 +61,8 @@
"react-router": "6.28.2",
"react-router-dom": "6.28.2",
"redux": "4.2.1",
"regenerator-runtime": "0.14.1"
"regenerator-runtime": "0.14.1",
"schema-utils": "^4.2.0"
},
"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

0 comments on commit 68d2cfd

Please sign in to comment.