diff --git a/package-lock.json b/package-lock.json
index a35f0f5..aad1534 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,7 +13,7 @@
"@edx/frontend-component-footer": "10.1.6",
"@edx/frontend-component-header": "^2.4.6",
"@edx/frontend-platform": "^1.15.6",
- "@edx/paragon": "16.14.4",
+ "@edx/paragon": "19.25.0",
"@fortawesome/fontawesome-svg-core": "^1.2.36",
"@fortawesome/free-brands-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
@@ -3522,36 +3522,34 @@
}
},
"node_modules/@edx/paragon": {
- "version": "16.14.4",
- "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-16.14.4.tgz",
- "integrity": "sha512-vDB8ur2zBvJjHnT0HGmtzRzmeyu9UNjv5fYbACwDnW9iheCnLX4CxP4hPxdM1L0I/FpuoOa3EeKealJzwUhJqQ==",
+ "version": "19.25.0",
+ "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-19.25.0.tgz",
+ "integrity": "sha512-l6V7KNqTGqUyiAJbDRCtPzWQ0Ec7QAhHUPM/FMFvGQbVm1KWqcA2x0f2KcdtzDc0mqXGFhcuL4oxfZOS6NSuHg==",
"dependencies": {
- "@fortawesome/fontawesome-svg-core": "^1.2.30",
- "@fortawesome/free-solid-svg-icons": "^5.14.0",
- "@fortawesome/react-fontawesome": "^0.1.11",
- "@popperjs/core": "^2.6.0",
- "airbnb-prop-types": "^2.12.0",
- "bootstrap": "4.6.0",
- "classnames": "^2.2.6",
+ "@fortawesome/fontawesome-svg-core": "^1.2.36",
+ "@fortawesome/react-fontawesome": "^0.1.18",
+ "@popperjs/core": "^2.11.4",
+ "airbnb-prop-types": "^2.16.0",
+ "bootstrap": "^4.6.1",
+ "classnames": "^2.3.1",
"email-prop-type": "^3.0.0",
"font-awesome": "^4.7.0",
"lodash.uniqby": "^4.7.0",
"mailto-link": "^1.0.0",
- "prop-types": "^15.7.2",
- "react-bootstrap": "^1.3.0",
- "react-focus-on": "^3.5.0",
- "react-popper": "^2.2.4",
+ "prop-types": "^15.8.1",
+ "react-bootstrap": "^1.6.4",
+ "react-focus-on": "^3.5.4",
+ "react-popper": "^2.2.5",
"react-proptype-conditional-require": "^1.0.4",
"react-responsive": "^8.2.0",
- "react-table": "^7.6.1",
- "react-transition-group": "^4.0.0",
+ "react-table": "^7.7.0",
+ "react-transition-group": "^4.4.2",
"tabbable": "^4.0.0",
- "uncontrollable": "7.2.1"
+ "uncontrollable": "^7.2.1"
},
"peerDependencies": {
- "prop-types": "^15.7.2",
- "react": "^16.8.6",
- "react-dom": "^16.8.6"
+ "react": "^16.8.6 || ^17.0.0",
+ "react-dom": "^16.8.6 || ^17.0.0"
}
},
"node_modules/@edx/paragon/node_modules/prop-types": {
@@ -9099,9 +9097,9 @@
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"node_modules/bootstrap": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.0.tgz",
- "integrity": "sha512-Io55IuQY3kydzHtbGvQya3H+KorS/M9rSNyfCGCg9WZ4pyT/lCxIlpJgG1GXW/PswzC84Tr2fBYi+7+jFVQQBw==",
+ "version": "4.6.1",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.1.tgz",
+ "integrity": "sha512-0dj+VgI9Ecom+rvvpNZ4MUZJz8dcX7WCX+eTID9+/8HgOkv3dsRzi8BGeZJCQU6flWQVYxwTQnEZFrmJSEO7og==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
@@ -36248,31 +36246,30 @@
}
},
"@edx/paragon": {
- "version": "16.14.4",
- "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-16.14.4.tgz",
- "integrity": "sha512-vDB8ur2zBvJjHnT0HGmtzRzmeyu9UNjv5fYbACwDnW9iheCnLX4CxP4hPxdM1L0I/FpuoOa3EeKealJzwUhJqQ==",
+ "version": "19.25.0",
+ "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-19.25.0.tgz",
+ "integrity": "sha512-l6V7KNqTGqUyiAJbDRCtPzWQ0Ec7QAhHUPM/FMFvGQbVm1KWqcA2x0f2KcdtzDc0mqXGFhcuL4oxfZOS6NSuHg==",
"requires": {
- "@fortawesome/fontawesome-svg-core": "^1.2.30",
- "@fortawesome/free-solid-svg-icons": "^5.14.0",
- "@fortawesome/react-fontawesome": "^0.1.11",
- "@popperjs/core": "^2.6.0",
- "airbnb-prop-types": "^2.12.0",
- "bootstrap": "4.6.0",
- "classnames": "^2.2.6",
+ "@fortawesome/fontawesome-svg-core": "^1.2.36",
+ "@fortawesome/react-fontawesome": "^0.1.18",
+ "@popperjs/core": "^2.11.4",
+ "airbnb-prop-types": "^2.16.0",
+ "bootstrap": "^4.6.1",
+ "classnames": "^2.3.1",
"email-prop-type": "^3.0.0",
"font-awesome": "^4.7.0",
"lodash.uniqby": "^4.7.0",
"mailto-link": "^1.0.0",
- "prop-types": "^15.7.2",
- "react-bootstrap": "^1.3.0",
- "react-focus-on": "^3.5.0",
- "react-popper": "^2.2.4",
+ "prop-types": "^15.8.1",
+ "react-bootstrap": "^1.6.4",
+ "react-focus-on": "^3.5.4",
+ "react-popper": "^2.2.5",
"react-proptype-conditional-require": "^1.0.4",
"react-responsive": "^8.2.0",
- "react-table": "^7.6.1",
- "react-transition-group": "^4.0.0",
+ "react-table": "^7.7.0",
+ "react-transition-group": "^4.4.2",
"tabbable": "^4.0.0",
- "uncontrollable": "7.2.1"
+ "uncontrollable": "^7.2.1"
},
"dependencies": {
"prop-types": {
@@ -40641,9 +40638,9 @@
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"bootstrap": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.0.tgz",
- "integrity": "sha512-Io55IuQY3kydzHtbGvQya3H+KorS/M9rSNyfCGCg9WZ4pyT/lCxIlpJgG1GXW/PswzC84Tr2fBYi+7+jFVQQBw==",
+ "version": "4.6.1",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.1.tgz",
+ "integrity": "sha512-0dj+VgI9Ecom+rvvpNZ4MUZJz8dcX7WCX+eTID9+/8HgOkv3dsRzi8BGeZJCQU6flWQVYxwTQnEZFrmJSEO7og==",
"requires": {}
},
"bottleneck": {
diff --git a/package.json b/package.json
index ddbfad1..f4bacbf 100755
--- a/package.json
+++ b/package.json
@@ -30,7 +30,7 @@
"@edx/frontend-component-footer": "10.1.6",
"@edx/frontend-component-header": "^2.4.6",
"@edx/frontend-platform": "^1.15.6",
- "@edx/paragon": "16.14.4",
+ "@edx/paragon": "19.25.0",
"@fortawesome/fontawesome-svg-core": "^1.2.36",
"@fortawesome/free-brands-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
diff --git a/src/components/Banner.jsx b/src/components/Banner.jsx
new file mode 100644
index 0000000..1aeaf63
--- /dev/null
+++ b/src/components/Banner.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { Alert } from '@edx/paragon';
+import { Info } from '@edx/paragon/icons';
+
+export const Banner = ({ children, variant, icon }) => (
+
+ {children}
+
+);
+Banner.defaultProps = {
+ icon: Info,
+ variant: 'info',
+};
+Banner.propTypes = {
+ variant: PropTypes.string,
+ icon: PropTypes.string,
+ children: PropTypes.node.isRequired,
+};
+
+export default Banner;
diff --git a/src/containers/CourseCard/CourseCardFooter.jsx b/src/containers/CourseCard/CourseCardFooter.jsx
deleted file mode 100644
index 2155dbc..0000000
--- a/src/containers/CourseCard/CourseCardFooter.jsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import {
- // Button,
- // PageBanner,
- Alert,
-} from '@edx/paragon';
-import {
-// Program
-} from '@edx/paragon/icons';
-
-export const CourseCardFooter = () => (
-
- footer
-
-);
-
-export default CourseCardFooter;
diff --git a/src/containers/CourseCard/components/CourseCardActions.jsx b/src/containers/CourseCard/components/CourseCardActions.jsx
new file mode 100644
index 0000000..466136a
--- /dev/null
+++ b/src/containers/CourseCard/components/CourseCardActions.jsx
@@ -0,0 +1,43 @@
+import React from 'react';
+
+import { Button } from '@edx/paragon';
+import { Locked } from '@edx/paragon/icons';
+
+import shapes from 'data/services/lms/shapes';
+
+export const CourseCardActions = ({ cardData: { enrollment, courseRun } }) => {
+ let primary;
+ let secondary = null;
+ if (!enrollment.isVerified) {
+ secondary = (
+
+ );
+ }
+ if (courseRun.isPending) {
+ primary = (
+
+ );
+ } else if (!courseRun.isEnded) {
+ if (enrollment.isAudit && enrollment.isAuditAccessExpired) {
+ primary = ();
+ } else {
+ primary = ();
+ }
+ } else {
+ primary = ();
+ }
+ return (<>{secondary}{primary}>);
+};
+CourseCardActions.propTypes = {
+ cardData: shapes.courseRunCardData.isRequired,
+};
+
+export default CourseCardActions;
diff --git a/src/containers/CourseCard/components/CourseCardBanners/components/CertificateBanner.jsx b/src/containers/CourseCard/components/CourseCardBanners/components/CertificateBanner.jsx
new file mode 100644
index 0000000..5b9dd9d
--- /dev/null
+++ b/src/containers/CourseCard/components/CourseCardBanners/components/CertificateBanner.jsx
@@ -0,0 +1,91 @@
+/* eslint-disable max-len */
+import React from 'react';
+
+import { Hyperlink } from '@edx/paragon';
+import { CheckCircle } from '@edx/paragon/icons';
+
+import shapes from 'data/services/lms/shapes';
+
+import Banner from 'components/Banner';
+
+const restrictedMessage = 'Your Certificate of Achievement is being held pending confirmation that the issuance of your Certificate is in compliance with strict U.S. embargoes on Iran, Cuba, Syria, and Sudan. If you think our system has mistakenly identified you as being connected with one of those countries, please let us know by contacting ';
+
+export const CertificateBanner = ({ cardData }) => {
+ const {
+ certificates,
+ courseRun,
+ enrollment,
+ grades,
+ } = cardData;
+ if (certificates.isRestricted) {
+ if (enrollment.isAudit) {
+ return (
+
+ {restrictedMessage}info@example.com
+
+ );
+ }
+ return (
+
+ {restrictedMessage}info@example.com
+ If you would like a refund on your Certificate of Achievement, please contact our billing address billing@example.com
+
+ );
+ }
+ if (!grades.isPassing) {
+ if (enrollment.isAudit) {
+ return (
+
+ Grade required to pass the course: {courseRun.minPassingGrade}%
+
+ );
+ }
+ if (courseRun.isFinished) {
+ return (
+
+ You are not eligible for a certificate.
+ {' '}
+ View grades.
+
+ );
+ }
+
+ return (
+
+ Grade required for a certificate: {courseRun.minPassingGrade}%
+
+ );
+ }
+ if (certificates.isDownloadable) {
+ if (certificates.downloadUrls.preview) {
+ return (
+
+ Congratulations. Your certificate is ready.
+ {' '}
+ View Certificate.
+
+ );
+ }
+ return (
+
+ Congratulations. Your certificate is ready.
+ {' '}
+ Download Certificate.
+
+ );
+ }
+ if (certificates.isEarned && !certificates.isAvailable) {
+ return (
+
+ Your grade and certificate will be ready after {certificates.availableDate}.
+
+ );
+ }
+
+ return null;
+};
+CertificateBanner.propTypes = {
+ cardData: shapes.courseRunCardData.isRequired,
+};
+
+export default CertificateBanner;
diff --git a/src/containers/CourseCard/components/CourseCardBanners/components/CourseBanner.jsx b/src/containers/CourseCard/components/CourseCardBanners/components/CourseBanner.jsx
new file mode 100644
index 0000000..f39b609
--- /dev/null
+++ b/src/containers/CourseCard/components/CourseCardBanners/components/CourseBanner.jsx
@@ -0,0 +1,49 @@
+/* eslint-disable max-len */
+import React from 'react';
+import { Hyperlink } from '@edx/paragon';
+
+import shapes from 'data/services/lms/shapes';
+
+import Banner from 'components/Banner';
+
+export const CourseBanner = ({ cardData }) => {
+ const {
+ // course,
+ enrollment,
+ courseRun,
+ } = cardData;
+ if (enrollment.isVerified) {
+ return null;
+ }
+ const isActive = courseRun.isStarted && !courseRun.isFinished;
+ const { canUpgrade, isAuditAccessExpired } = enrollment;
+ if (isAuditAccessExpired) {
+ if (canUpgrade) {
+ return (
+
+ Your audit access to this course has expired. Upgrade now to access your course again.
+
+ );
+ }
+ return (
+
+ Your audit access to this course has expired. Find another course
+
+ );
+ }
+ if (isActive && !canUpgrade) {
+ return (
+
+ Your upgrade deadline for this course has passed. To upgrade, enroll in a session that is farther in the future.
+ {' '}
+ Explore course details.
+
+ );
+ }
+ return null;
+};
+CourseBanner.propTypes = {
+ cardData: shapes.courseRunCardData.isRequired,
+};
+
+export default CourseBanner;
diff --git a/src/containers/CourseCard/components/CourseCardBanners/components/EntitlementBanner.jsx b/src/containers/CourseCard/components/CourseCardBanners/components/EntitlementBanner.jsx
new file mode 100644
index 0000000..1767c62
--- /dev/null
+++ b/src/containers/CourseCard/components/CourseCardBanners/components/EntitlementBanner.jsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { Hyperlink } from '@edx/paragon';
+
+import shapes from 'data/services/lms/shapes';
+
+import Banner from 'components/Banner';
+
+export const EntitlementBanner = ({ cardData }) => {
+ const { entitlements } = cardData;
+ if (!entitlements.isEntitlement) {
+ return null;
+ }
+ if (entitlements.isExpired) {
+ return null;
+ }
+ if (!entitlements.isFulfilled) {
+ if (entitlements.canChange) {
+ return (
+ You must select a session to access the course.
+ );
+ }
+ return (
+ The deadline to select a session has passed
+ );
+ }
+ if (entitlements.canChange) {
+ return (
+
+ You can change sessions until {entitlements.changeDeadline}.
+ {' '}
+ Change or leave session
+
+ );
+ }
+
+ return null;
+};
+EntitlementBanner.propTypes = {
+ cardData: shapes.courseRunCardData.isRequired,
+};
+
+export default EntitlementBanner;
diff --git a/src/containers/CourseCard/components/CourseCardBanners/index.jsx b/src/containers/CourseCard/components/CourseCardBanners/index.jsx
new file mode 100644
index 0000000..6c8aed2
--- /dev/null
+++ b/src/containers/CourseCard/components/CourseCardBanners/index.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+
+import shapes from 'data/services/lms/shapes';
+
+import CourseBanner from './components/CourseBanner';
+import CertificateBanner from './components/CertificateBanner';
+import EntitlementBanner from './components/EntitlementBanner';
+
+export const CourseCardBanners = ({ cardData }) => (
+ <>
+
+
+
+ >
+);
+CourseCardBanners.propTypes = {
+ cardData: shapes.courseRunCardData.isRequired,
+};
+
+export default CourseCardBanners;
diff --git a/src/containers/CourseCard/CourseCardMenu.jsx b/src/containers/CourseCard/components/CourseCardMenu.jsx
similarity index 100%
rename from src/containers/CourseCard/CourseCardMenu.jsx
rename to src/containers/CourseCard/components/CourseCardMenu.jsx
diff --git a/src/containers/CourseCard/RelatedProgram.jsx b/src/containers/CourseCard/components/RelatedProgram.jsx
similarity index 100%
rename from src/containers/CourseCard/RelatedProgram.jsx
rename to src/containers/CourseCard/components/RelatedProgram.jsx
diff --git a/src/containers/CourseCard/index.jsx b/src/containers/CourseCard/index.jsx
index 3273e6a..cfaf29f 100644
--- a/src/containers/CourseCard/index.jsx
+++ b/src/containers/CourseCard/index.jsx
@@ -1,24 +1,28 @@
import React from 'react';
-import PropTypes from 'prop-types';
-import { Locked } from '@edx/paragon/icons';
-import { Button, Card } from '@edx/paragon';
+// import PropTypes from 'prop-types';
+import { Card } from '@edx/paragon';
-import { courseData } from 'data/services/lms/fakeData/courses';
+import shapes from 'data/services/lms/shapes';
-import RelatedProgram from './RelatedProgram';
-import CourseCardMenu from './CourseCardMenu';
-import CourseCardFooter from './CourseCardFooter';
+import RelatedProgram from './components/RelatedProgram';
+import CourseCardMenu from './components/CourseCardMenu';
+import CourseCardBanners from './components/CourseCardBanners';
+import CourseCardActions from './components/CourseCardActions';
-export const CourseCard = ({ courseID }) => {
+export const CourseCard = ({ cardData }) => {
const {
- title,
- imageUrl,
- displayNumber,
- displayOrg,
- accessExpiryDate,
- } = courseData[courseID] || {};
+ course: {
+ title,
+ bannerUrl: imageUrl,
+ },
+ courseRun: {
+ courseNumber,
+ accessExpirationDate,
+ },
+ } = cardData;
+ const providerName = cardData.provider?.name;
return (
-
+
{
actions={}
/>
- {displayOrg} • {displayNumber} • Access expires {accessExpiryDate}
+ {providerName || 'Unkown'} • {courseNumber} • Access expires {accessExpirationDate}
}>
-
-
+
-
+
);
};
CourseCard.propTypes = {
- courseID: PropTypes.string.isRequired,
+ cardData: shapes.courseRunCardData.isRequired,
};
CourseCard.defaultProps = {};
diff --git a/src/containers/CourseList/index.jsx b/src/containers/CourseList/index.jsx
index 01a0376..29ec03b 100644
--- a/src/containers/CourseList/index.jsx
+++ b/src/containers/CourseList/index.jsx
@@ -1,17 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';
+import shapes from 'data/services/lms/shapes';
import CourseCard from 'containers/CourseCard';
-export const CourseList = ({ courseIDs }) => (
+export const CourseList = ({ courseListData }) => (
- {courseIDs.map((id) => (
-
+ {courseListData.map((cardData) => (
+
))}
);
+
CourseList.propTypes = {
- courseIDs: PropTypes.arrayOf(PropTypes.string).isRequired,
+ courseListData: PropTypes.arrayOf(shapes.courseRunCardData).isRequired,
};
export default CourseList;
diff --git a/src/containers/Dashboard/index.jsx b/src/containers/Dashboard/index.jsx
index 743d735..b484c20 100644
--- a/src/containers/Dashboard/index.jsx
+++ b/src/containers/Dashboard/index.jsx
@@ -1,29 +1,51 @@
import React from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+
+import { FormattedMessage } from '@edx/frontend-platform/i18n';
+
+import { selectors, thunkActions } from 'data/redux';
import CourseList from 'containers/CourseList';
import WidgetSidebar from 'containers/WidgetSidebar';
-import { courseIDs } from 'data/services/lms/fakeData/courses';
-import { FormattedMessage } from '@edx/frontend-platform/i18n';
-import EmptyCourse from '../EmptyCourse';
+import EmptyCourse from 'containers/EmptyCourse';
import messages from './messages';
+import * as module from '.';
-export const Dashboard = () => (
-
- {courseIDs.length ? (
- <>
-
-
-
-
-
-
-
- >
- ) : (
-
- )}
-
-);
+export const hooks = ({ dispatch }) => ({
+ initialize: () => React.useEffect(
+ () => { dispatch(thunkActions.app.initialize()); },
+ [],
+ ),
+ enrollments: useSelector(selectors.app.enrollments),
+ entitlements: useSelector(selectors.app.entitlements),
+});
+
+export const Dashboard = () => {
+ const dispatch = useDispatch();
+ const {
+ initialize,
+ enrollments,
+ // entitlements,
+ } = module.hooks({ dispatch });
+ initialize();
+ return (
+
+ {enrollments.length ? (
+ <>
+
+
+
+
+
+
+
+ >
+ ) : (
+
+ )}
+
+ );
+};
export default Dashboard;
diff --git a/src/containers/WidgetSidebar/index.jsx b/src/containers/WidgetSidebar/index.jsx
index 6330e62..adaebfa 100644
--- a/src/containers/WidgetSidebar/index.jsx
+++ b/src/containers/WidgetSidebar/index.jsx
@@ -8,6 +8,7 @@ import './index.scss';
export const WidgetSidebar = () => (
+
{/*
@@ -17,6 +18,7 @@ export const WidgetSidebar = () => (
*/}
+
({ ...state, courseMetadata: payload }),
+ loadEnrollments: (state, { payload }) => ({ ...state, enrollments: payload }),
+ loadEntitlements: (state, { payload }) => ({ ...state, entitlements: payload }),
},
});
diff --git a/src/data/redux/app/selectors.js b/src/data/redux/app/selectors.js
index 9ceeabd..2c57c8f 100644
--- a/src/data/redux/app/selectors.js
+++ b/src/data/redux/app/selectors.js
@@ -10,7 +10,8 @@ const mkSimpleSelector = (cb) => createSelector([module.appSelector], cb);
// top-level app data selectors
export const simpleSelectors = {
- courseMetadata: mkSimpleSelector(app => app.courseMetadata),
+ enrollments: mkSimpleSelector(app => app.enrollments),
+ entitlements: mkSimpleSelector(app => app.entitlements),
};
export default StrictDict({
diff --git a/src/data/redux/thunkActions/app.js b/src/data/redux/thunkActions/app.js
index 537d424..a55ff1b 100644
--- a/src/data/redux/thunkActions/app.js
+++ b/src/data/redux/thunkActions/app.js
@@ -1,6 +1,8 @@
import { StrictDict } from 'utils';
+import { actions } from 'data/redux';
+
+import requests from './requests';
-// import { selectors, actions } from 'data/redux';
// import { locationId } from 'data/constants/app';
// import { } from './requests';
@@ -10,8 +12,14 @@ import { StrictDict } from 'utils';
* initialize the app, loading ora and course metadata from the api, and loading the initial
* submission list data.
*/
-export const initialize = () => () => {
-};
+export const initialize = () => (dispatch) => (
+ requests.initialize().then(
+ ({ enrollments, entitlements }) => {
+ dispatch(actions.app.loadEnrollments(enrollments));
+ dispatch(actions.app.loadEntitlements(entitlements));
+ },
+ )
+);
export default StrictDict({
initialize,
diff --git a/src/data/redux/thunkActions/requests.js b/src/data/redux/thunkActions/requests.js
index c923726..d3a9391 100644
--- a/src/data/redux/thunkActions/requests.js
+++ b/src/data/redux/thunkActions/requests.js
@@ -2,6 +2,7 @@ import { StrictDict } from 'utils';
// import { RequestKeys } from 'data/constants/requests';
import { actions } from 'data/redux';
+import fakeData from 'data/services/lms/fakeData/courses';
// import api from 'data/services/lms/api';
// import * as module from './requests';
@@ -33,5 +34,13 @@ export const networkRequest = ({
});
};
+export const initialize = () => (
+ Promise.resolve({
+ enrollments: fakeData.courseRunData,
+ entitlements: fakeData.entitlementCourses,
+ })
+);
+
export default StrictDict({
+ initialize,
});
diff --git a/src/data/services/lms/fakeData/courses.js b/src/data/services/lms/fakeData/courses.js
index 4cb269e..e399aac 100644
--- a/src/data/services/lms/fakeData/courses.js
+++ b/src/data/services/lms/fakeData/courses.js
@@ -6,7 +6,7 @@ export const providers = StrictDict({
website: 'www.edx.com',
email: 'support@edx.com',
},
- MIT: {
+ mit: {
name: 'MIT',
website: 'www.mit.edu',
email: 'support@mit.edu',
@@ -38,7 +38,7 @@ export const genCourseRunData = (data = {}) => ({
export const genEnrollmentData = (data = {}) => ({
isAudit: true,
isVerified: false,
- canUpgrade: data.verified ? null : false,
+ canUpgrade: data.verified ? null : true,
isAuditAccessExpired: data.verified ? null : false,
...data,
});
@@ -48,10 +48,8 @@ export const genCertificateData = (data = {}) => ({
isRestricted: false,
isAvailable: false,
isEarned: false,
- isRequesting: false,
- isGenerating: false,
isDownloadable: false,
- downloadUrls: null, // { preview, download, honorCertDownload }
+ downloadUrls: null, // { preview, download }
...data,
});
@@ -68,15 +66,15 @@ export const courseRuns = [
grades: { isPassing: true },
courseRun: { isPending: true },
certificates: genCertificateData(),
- entitlement: { isEntitlement: false },
+ entitlements: { isEntitlement: false },
},
// audit, started, cannot upgrade, restricted
{
- enrollment: genEnrollmentData({ isAudit: true }),
+ enrollment: genEnrollmentData({ isAudit: true, canUpgrade: false }),
grades: { isPassing: true },
courseRun: { isStarted: true },
certificates: genCertificateData({ isRestricted: true }),
- entitlement: { isEntitlement: false },
+ entitlements: { isEntitlement: false },
},
// audit, started, can upgrade
{
@@ -84,23 +82,35 @@ export const courseRuns = [
grades: { isPassing: true },
courseRun: { isStarted: true },
certificates: genCertificateData(),
- entitlement: { isEntitlement: false },
+ entitlements: { isEntitlement: false },
},
// audit, started, not passing
{
enrollment: genEnrollmentData({ isAudit: true, canUpgrade: true }),
grades: { isPassing: false },
- courseRun: { isStarted: true, accessExpirationDate: pastDate },
+ courseRun: { isStarted: true },
certificates: genCertificateData(),
- entitlement: { isEntitlement: false },
+ entitlements: { isEntitlement: false },
},
- // audit, started, audit access expired
+ // audit, started, audit access expired, can upgrade
{
enrollment: genEnrollmentData({ isAudit: true, isAuditAccessExpired: true }),
grades: { isPassing: true },
courseRun: { isStarted: true, accessExpirationDate: pastDate },
certificates: genCertificateData(),
- entitlement: { isEntitlement: false },
+ entitlements: { isEntitlement: false },
+ },
+ // audit, started, audit access expired, cannot upgrade
+ {
+ enrollment: genEnrollmentData({
+ isAudit: true,
+ isAuditAccessExpired: true,
+ canUpgrade: false,
+ }),
+ grades: { isPassing: true },
+ courseRun: { isStarted: true, accessExpirationDate: pastDate },
+ certificates: genCertificateData(),
+ entitlements: { isEntitlement: false },
},
// verified, pending, restricted
{
@@ -108,7 +118,7 @@ export const courseRuns = [
grades: { isPassing: true },
courseRun: { isPending: true },
certificates: genCertificateData({ isRestricted: true }),
- entitlement: { isEntitlement: false },
+ entitlements: { isEntitlement: false },
},
// verified, started
{
@@ -116,7 +126,7 @@ export const courseRuns = [
grades: { isPassing: true },
courseRun: { isStarted: true },
certificates: genCertificateData(),
- entitlement: { isEntitlement: false },
+ entitlements: { isEntitlement: false },
},
// verified, not passing
{
@@ -124,7 +134,7 @@ export const courseRuns = [
grades: { isPassing: false },
courseRun: { isStarted: true },
certificates: genCertificateData(),
- entitlement: { isEntitlement: false },
+ entitlements: { isEntitlement: false },
},
// verified, finished, not passing
{
@@ -132,7 +142,7 @@ export const courseRuns = [
grades: { isPassing: false },
courseRun: { isFinished: true },
certificates: genCertificateData(),
- entitlement: { isEntitlement: false },
+ entitlements: { isEntitlement: false },
},
// verified, restricted
{
@@ -140,7 +150,7 @@ export const courseRuns = [
grades: { isPassing: true },
courseRun: { isStarted: true },
certificates: genCertificateData({ isRestricted: true }),
- entitlement: { isEntitlement: false },
+ entitlements: { isEntitlement: false },
},
// verified, earned but not available
{
@@ -151,33 +161,7 @@ export const courseRuns = [
isEarned: true,
availableDate: futureDate,
}),
- entitlement: { isEntitlement: false },
- },
- // verified, earned, requesting
- {
- enrollment: genEnrollmentData({ isVerified: true }),
- grades: { isPassing: true },
- courseRun: { isStarted: true },
- certificates: genCertificateData({
- isEarned: true,
- isAvailable: true,
- isRequesting: true,
- availableDate: pastDate,
- }),
- entitlement: { isEntitlement: false },
- },
- // verified, earned, generating
- {
- enrollment: genEnrollmentData({ isVerified: true }),
- grades: { isPassing: true },
- courseRun: { isStarted: true },
- certificates: genCertificateData({
- isEarned: true,
- isAvailable: true,
- isGenerating: true,
- availableDate: pastDate,
- }),
- entitlement: { isEntitlement: false },
+ entitlements: { isEntitlement: false },
},
// verified, earned, downloadable (web + link)
{
@@ -194,7 +178,7 @@ export const courseRuns = [
download: logos.social,
},
}),
- entitlement: { isEntitlement: false },
+ entitlements: { isEntitlement: false },
},
// verified, earned, downloadable (link)
{
@@ -210,23 +194,7 @@ export const courseRuns = [
download: logos.social,
},
}),
- entitlement: { isEntitlement: false },
- },
- // verified, earned, downloadable (honor cert)
- {
- enrollment: genEnrollmentData({ isVerified: true }),
- grades: { isPassing: true },
- courseRun: { isStarted: true },
- certificates: genCertificateData({
- isEarned: true,
- isAvailable: true,
- isDownloadable: true,
- availableDate: pastDate,
- downloadUrls: {
- honorCertDownload: logos.bio,
- },
- }),
- entitlement: { isEntitlement: false },
+ entitlements: { isEntitlement: false },
},
// Entitlement Course Run - Cannot view yet
{
@@ -234,11 +202,12 @@ export const courseRuns = [
grades: { isPassing: true },
courseRun: { isPending: true },
certificates: genCertificateData(),
- entitlement: {
+ entitlements: {
isEntitlement: true,
isFulfilled: true,
isRefundable: true,
canViewCourse: false,
+ canChange: true,
changeDeadline: futureDate,
isExpired: false,
},
@@ -249,11 +218,12 @@ export const courseRuns = [
grades: { isPassing: true },
courseRun: { isStarted: true },
certificates: genCertificateData(),
- entitlement: {
+ entitlements: {
isEntitlement: true,
isFulfilled: true,
isRefundable: true,
canViewCourse: true,
+ canChange: true,
changeDeadline: futureDate,
isExpired: false,
},
@@ -264,11 +234,12 @@ export const courseRuns = [
grades: { isPassing: true },
courseRun: { isStarted: true },
certificates: genCertificateData(),
- entitlement: {
+ entitlements: {
isEntitlement: true,
isFulfilled: true,
isRefundable: true,
canViewCourse: true,
+ canChange: false,
changeDeadline: pastDate,
isExpired: false,
},
@@ -277,13 +248,14 @@ export const courseRuns = [
{
enrollment: genEnrollmentData({ isVerified: true }),
grades: { isPassing: true },
- courseRun: { isStarted: true },
+ courseRun: { isStarted: true, isFinished: true, isArchived: true },
certificates: genCertificateData(),
- entitlement: {
+ entitlements: {
isEntitlement: true,
isFulfilled: true,
- isRefundable: true,
+ isRefundable: false,
canViewCourse: true,
+ canChange: false,
changeDeadline: pastDate,
isExpired: true,
},
@@ -294,31 +266,37 @@ export const entitlementCourses = [
{
course: { title: genCourseTitle(100) },
entitlements: {
+ isEntitlement: true,
availableSessions,
isRefundable: true,
isFulfilled: false,
canViewCourse: false,
changeDeadline: futureDate,
+ canChange: true,
isExpired: false,
},
}, {
course: { title: genCourseTitle(101) },
entitlements: {
+ isEntitlement: true,
availableSessions,
isRefundable: true,
isFulfilled: false,
canViewCourse: false,
changeDeadline: pastDate,
+ canChange: false,
isExpired: false,
},
}, {
course: { title: genCourseTitle(102) },
entitlements: {
+ isEntitlement: true,
availableSessions,
isRefundable: true,
isFulfilled: false,
canViewCourse: false,
changeDeadline: pastDate,
+ canChange: false,
isExpired: true,
},
},
@@ -328,30 +306,26 @@ export const entitlementCourses = [
// Entitlement Course - cannot view yet
// Entitlement Course - can view and change
// Entitlement Course - expired
-export const courseRunData = courseRuns.reduce(
- (obj, curr, index) => {
- const out = { ...curr };
+export const courseRunData = courseRuns.map(
+ (data, index) => {
+ const title = genCourseTitle(index);
+ const courseNumber = genCourseID(index);
const providerIndex = index % 3;
const iteratedData = [
- {
- provider: providers.edx,
- course: { title: genCourseTitle(index), bannerUrl: logos.edx },
- },
- {
- provider: providers.mit,
- course: { title: genCourseTitle(index), bannerUrl: logos.bio },
- },
- {
- provider: null,
- course: { title: genCourseTitle(index), bannerUrl: logos.social },
- },
+ { provider: providers.edx, course: { title, bannerUrl: logos.edx } },
+ { provider: providers.mit, course: { title, bannerUrl: logos.science } },
+ { provider: null, course: { title, bannerUrl: logos.social } },
];
- out.courseRun.courseNumber = genCourseID(index);
return {
- ...out,
+ ...data,
+ courseRun: genCourseRunData({ ...data.courseRun, courseNumber }),
...iteratedData[providerIndex],
credit: { isPurchased: false, requestStatus: null },
};
},
- {},
);
+
+export default {
+ courseRunData,
+ entitlementCourses,
+};
diff --git a/src/data/services/lms/shapes.js b/src/data/services/lms/shapes.js
new file mode 100644
index 0000000..b148a01
--- /dev/null
+++ b/src/data/services/lms/shapes.js
@@ -0,0 +1,70 @@
+import PropTypes from 'prop-types';
+import { StrictDict } from 'utils';
+
+export const shapes = StrictDict({
+ course: PropTypes.shape({
+ bannerUrl: PropTypes.string,
+ title: PropTypes.string,
+ website: PropTypes.string,
+ }),
+ provider: PropTypes.shape({
+ email: PropTypes.string,
+ name: PropTypes.string,
+ website: PropTypes.string,
+ }),
+ courseRun: PropTypes.shape({
+ accessExpirationDate: PropTypes.string,
+ courseNumber: PropTypes.string,
+ isArchived: PropTypes.bool,
+ isFinished: PropTypes.bool,
+ isPending: PropTypes.bool,
+ isStarted: PropTypes.bool,
+ minPassingGrade: PropTypes.number,
+ }),
+ credit: PropTypes.shape({
+ isPurchased: PropTypes.bool,
+ requestStatus: PropTypes.string,
+ }),
+ certificates: PropTypes.shape({
+ availableDate: PropTypes.string,
+ downloadUrls: PropTypes.shape({
+ preview: PropTypes.string,
+ download: PropTypes.string,
+ }),
+ isAvailable: PropTypes.bool,
+ isDownloadable: PropTypes.bool,
+ isEarned: PropTypes.bool,
+ isRestricted: PropTypes.bool,
+ }),
+ enrollment: PropTypes.shape({
+ canUpgrade: PropTypes.bool,
+ isAudit: PropTypes.bool,
+ isAuditAccessExpired: PropTypes.bol,
+ isVerified: PropTypes.bool,
+ }),
+ entitlement: PropTypes.shape({
+ isEntitlement: PropTypes.bool,
+ canChange: PropTypes.bool,
+ isFulfilled: PropTypes.bool,
+ isRefundable: PropTypes.bool,
+ changeDeadline: PropTypes.string,
+ isExpired: PropTypes.bool,
+ canViewCourse: PropTypes.bool,
+ }),
+ grades: PropTypes.shape({
+ isPassing: PropTypes.bool,
+ }),
+});
+
+shapes.courseRunCardData = PropTypes.shape({
+ course: shapes.course,
+ provider: shapes.provider,
+ courseRun: shapes.courseRun,
+ credit: shapes.credit,
+ certificates: shapes.certificates,
+ enrollment: shapes.enrollment,
+ entitlement: shapes.entitlement,
+ grades: shapes.grades,
+});
+
+export default shapes;