@@ -171,7 +187,7 @@ const ProgressiveProfiling = (props) => {
className="login-button-width"
state={submitState}
labels={{
- default: intl.formatMessage(messages['optional.fields.submit.button']),
+ default: showRecommendationsPage ? intl.formatMessage(messages['optional.fields.next.button']) : intl.formatMessage(messages['optional.fields.submit.button']),
pending: '',
}}
onClick={handleSubmit}
diff --git a/src/progressive-profiling/messages.jsx b/src/progressive-profiling/messages.jsx
index 1a15a014..bdf31c64 100644
--- a/src/progressive-profiling/messages.jsx
+++ b/src/progressive-profiling/messages.jsx
@@ -26,6 +26,11 @@ const messages = defineMessages({
defaultMessage: 'Skip for now',
description: 'Skip button text',
},
+ 'optional.fields.next.button': {
+ id: 'optional.fields.next.button',
+ defaultMessage: 'Next',
+ description: 'Next button text',
+ },
// modal dialog box
'continue.to.platform': {
id: 'continue.to.platform',
diff --git a/src/recommendations/RecommendationCard.jsx b/src/recommendations/RecommendationCard.jsx
new file mode 100644
index 00000000..77fa3d54
--- /dev/null
+++ b/src/recommendations/RecommendationCard.jsx
@@ -0,0 +1,59 @@
+import React from 'react';
+
+import { injectIntl } from '@edx/frontend-platform/i18n';
+import { Card, Hyperlink } from '@edx/paragon';
+import PropTypes from 'prop-types';
+
+const RecommendationCard = (props) => {
+ const { recommendation } = props;
+ const showPartnerLogo = recommendation.owners.length === 1;
+
+ const getOwners = () => {
+ if (recommendation.owners.length === 1) {
+ return recommendation.owners[0].key;
+ }
+
+ let keys = '';
+ recommendation.owners.forEach((owner) => {
+ keys += `${owner.key }, `;
+ });
+ return keys.slice(0, -2);
+ };
+
+ return (
+
+
+
+
+
+
+ Course} />
+
+
+
+ );
+};
+
+RecommendationCard.propTypes = {
+ recommendation: PropTypes.shape({
+ activeRunKey: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ cardImageUrl: PropTypes.string.isRequired,
+ owners: PropTypes.arrayOf(PropTypes.shape({
+ key: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired,
+ logoImageUrl: PropTypes.string.isRequired,
+ })),
+ marketingUrl: PropTypes.string.isRequired,
+ }).isRequired,
+};
+
+export default injectIntl(RecommendationCard);
diff --git a/src/recommendations/RecommendationsList.jsx b/src/recommendations/RecommendationsList.jsx
new file mode 100644
index 00000000..53570554
--- /dev/null
+++ b/src/recommendations/RecommendationsList.jsx
@@ -0,0 +1,50 @@
+import React from 'react';
+
+import { injectIntl } from '@edx/frontend-platform/i18n';
+import { Container } from '@edx/paragon';
+import PropTypes from 'prop-types';
+
+import RecommendationCard from './RecommendationCard';
+
+const RecommendationsList = (props) => {
+ const { title, recommendations } = props;
+
+ return (
+
+
+ {title}
+
+
+ {
+ recommendations.map((recommendation) => (
+
+ ))
+ }
+
+
+ );
+};
+
+RecommendationsList.propTypes = {
+ title: PropTypes.string.isRequired,
+ recommendations: PropTypes.arrayOf(PropTypes.shape({
+ activeRunKey: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ cardImageUrl: PropTypes.string.isRequired,
+ owners: PropTypes.arrayOf(PropTypes.shape({
+ key: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired,
+ logoImageUrl: PropTypes.string.isRequired,
+ })),
+ marketingUrl: PropTypes.string.isRequired,
+ })),
+};
+
+RecommendationsList.defaultProps = {
+ recommendations: [],
+};
+
+export default injectIntl(RecommendationsList);
diff --git a/src/recommendations/RecommendationsPage.jsx b/src/recommendations/RecommendationsPage.jsx
new file mode 100644
index 00000000..5f6a95e7
--- /dev/null
+++ b/src/recommendations/RecommendationsPage.jsx
@@ -0,0 +1,143 @@
+import React from 'react';
+
+import { getConfig } from '@edx/frontend-platform';
+import { injectIntl } from '@edx/frontend-platform/i18n';
+import {
+ Hyperlink, Image, StatefulButton,
+} from '@edx/paragon';
+import PropTypes from 'prop-types';
+
+import { DEFAULT_REDIRECT_URL } from '../data/constants';
+import messages from './messages';
+import RecommendationsList from './RecommendationsList';
+
+const recommendationData = [
+ {
+ activeRunKey: 'course-v1:MITx+6.86x+1T2023',
+ cardImageUrl: 'https://prod-discovery.edx-cdn.org/media/course/image/4c70ad9b-9602-49af-bf00-83fa4bf47708-dc4566d15250.jpg',
+ marketingUrl:
+ 'https://www.edx.org/course/machine-learning-with-python-from-linear-models-to',
+ objectId: 'course-4c70ad9b-9602-49af-bf00-83fa4bf47708',
+ owners: [
+ {
+ key: 'MITx',
+ logoImageUrl: 'https://prod-discovery.edx-cdn.org/organization/logos/2a73d2ce-c34a-4e08-8223-83bca9d2f01d-2cc8854c6fee.png',
+ name: 'Massachusetts Institute of Technology',
+ },
+ ],
+ title: 'Machine Learning with Python: from Linear Models to Deep Learning',
+ },
+ {
+ activeRunKey: 'course-v1:MITx+6.86x+1T2023',
+ cardImageUrl: 'https://prod-discovery.edx-cdn.org/media/course/image/4c70ad9b-9602-49af-bf00-83fa4bf47708-dc4566d15250.jpg',
+ marketingUrl:
+ 'https://www.edx.org/course/machine-learning-with-python-from-linear-models-to',
+ objectId: 'course-4c70ad9b-9602-49af-bf00-83fa4bf47708',
+ owners: [
+ {
+ key: 'MITx',
+ logoImageUrl: 'https://prod-discovery.edx-cdn.org/organization/logos/2a73d2ce-c34a-4e08-8223-83bca9d2f01d-2cc8854c6fee.png',
+ name: 'Massachusetts Institute of Technology',
+ },
+ {
+ key: 'MITx',
+ logoImageUrl: 'https://prod-discovery.edx-cdn.org/organization/logos/2a73d2ce-c34a-4e08-8223-83bca9d2f01d-2cc8854c6fee.png',
+ name: 'Massachusetts Institute of Technology',
+ },
+ ],
+ title: 'Machine Learning with Python: from Linear Models to Deep Learning',
+ },
+ {
+ activeRunKey: 'course-v1:MITx+6.86x+1T2023',
+ cardImageUrl: 'https://prod-discovery.edx-cdn.org/media/course/image/4c70ad9b-9602-49af-bf00-83fa4bf47708-dc4566d15250.jpg',
+ marketingUrl:
+ 'https://www.edx.org/course/machine-learning-with-python-from-linear-models-to',
+ objectId: 'course-4c70ad9b-9602-49af-bf00-83fa4bf47708',
+ owners: [
+ {
+ key: 'MITx',
+ logoImageUrl: 'https://prod-discovery.edx-cdn.org/organization/logos/2a73d2ce-c34a-4e08-8223-83bca9d2f01d-2cc8854c6fee.png',
+ name: 'Massachusetts Institute of Technology',
+ },
+ ],
+ title: 'Machine Learning with Python: from Linear Models to Deep Learning',
+ },
+ {
+ activeRunKey: 'course-v1:MITx+6.86x+1T2023',
+ cardImageUrl: 'https://prod-discovery.edx-cdn.org/media/course/image/4c70ad9b-9602-49af-bf00-83fa4bf47708-dc4566d15250.jpg',
+ marketingUrl:
+ 'https://www.edx.org/course/machine-learning-with-python-from-linear-models-to',
+ objectId: 'course-4c70ad9b-9602-49af-bf00-83fa4bf47708',
+ owners: [
+ {
+ key: 'MITx',
+ logoImageUrl: 'https://prod-discovery.edx-cdn.org/organization/logos/2a73d2ce-c34a-4e08-8223-83bca9d2f01d-2cc8854c6fee.png',
+ name: 'Massachusetts Institute of Technology',
+ },
+ ],
+ title: 'Machine Learning with Python: from Linear Models to Deep Learning',
+ },
+];
+
+const RecommendationsPage = (props) => {
+ const { intl, location } = props;
+ const DASHBOARD_URL = getConfig().LMS_BASE_URL.concat(DEFAULT_REDIRECT_URL);
+ const registrationResponse = location.state?.registrationResult;
+
+ if (!registrationResponse) {
+ global.location.assign(DASHBOARD_URL);
+ return null;
+ }
+
+ const handleSkip = (e) => {
+ e.preventDefault();
+ window.history.replaceState(location.state, null, '');
+ if (registrationResponse) {
+ window.location.href = registrationResponse.redirectUrl;
+ } else {
+ window.location.href = DASHBOARD_URL;
+ }
+ };
+
+ return (
+
+ );
+};
+
+RecommendationsPage.propTypes = {
+ intl: PropTypes.objectOf(PropTypes.object).isRequired,
+ location: PropTypes.shape({
+ state: PropTypes.object,
+ }),
+
+};
+
+RecommendationsPage.defaultProps = {
+ location: { state: {} },
+};
+
+export default injectIntl(RecommendationsPage);
diff --git a/src/recommendations/index.js b/src/recommendations/index.js
new file mode 100644
index 00000000..1c17a099
--- /dev/null
+++ b/src/recommendations/index.js
@@ -0,0 +1 @@
+export { default } from './RecommendationsPage';
diff --git a/src/recommendations/messages.js b/src/recommendations/messages.js
new file mode 100644
index 00000000..3922a264
--- /dev/null
+++ b/src/recommendations/messages.js
@@ -0,0 +1,21 @@
+import { defineMessages } from '@edx/frontend-platform/i18n';
+
+const messages = defineMessages({
+ 'recommendation.page.title': {
+ id: 'recommendation.page.title',
+ defaultMessage: 'Recommendations| {siteName}',
+ description: 'recommendation page title',
+ },
+ 'recommendation.page.heading': {
+ id: 'recommendation.page.heading',
+ defaultMessage: 'We have a few recommendations to get you started.',
+ description: 'recommendation page heading',
+ },
+ 'recommendation.skip.button': {
+ id: 'recommendation.skip.button',
+ defaultMessage: 'Skip for now',
+ description: 'Skip button text',
+ },
+
+});
+export default messages;
diff --git a/src/sass/_recommendations_page.scss b/src/sass/_recommendations_page.scss
new file mode 100644
index 00000000..f37dbf03
--- /dev/null
+++ b/src/sass/_recommendations_page.scss
@@ -0,0 +1,66 @@
+.card-list {
+ padding-left: 0.0625rem;
+ padding-bottom: 0.125;
+ @include media-breakpoint-down(xl) {
+ overflow-x: scroll;
+ overflow-y: hidden;
+ }
+}
+.recommendations-heading {
+ overflow-wrap: break-word;
+}
+
+.recommendations-container {
+ padding: 0 1rem;
+ margin: 0 0 1.875rem 0;
+ @include media-breakpoint-up(lg) {
+ max-width: $max-width-sm + 5 * $grid-gutter-width !important;
+ }
+
+ @include media-breakpoint-up(xl) {
+ max-width: $max-width-md + $grid-gutter-width !important;
+ }
+
+ @include media-breakpoint-up(xxl) {
+ max-width: $max-width-lg + $grid-gutter-width !important;
+ }
+}
+
+.recommendation-card {
+ .pgn__hyperlink {
+ display: block;
+ }
+
+ .pgn__card {
+ width: 281px;
+ height: 332px;
+ margin: 0 !important;
+ }
+
+ .pgn__card-image-cap {
+ height: 6.5rem;
+ }
+
+ .pgn__card-header-title-md {
+ font-weight: 700;
+ font-size: 1.125rem;
+ line-height: 1.5rem;
+ }
+
+ .pgn__card-header-subtitle-md{
+ font-weight: 400;
+ font-size:0.875rem;
+ line-height: 1.5rem;
+ color: $gray-700;
+ }
+ .pgn__card-footer {
+ bottom: 0;
+ position: absolute;
+ padding-bottom: 1rem !important;
+ }
+ .footer-text{
+ font-weight: 400;
+ font-size: 0.75rem;
+ line-height: 1.25rem;
+ }
+}
diff --git a/src/sass/_style.scss b/src/sass/_style.scss
index ce7ac9f9..5972e055 100644
--- a/src/sass/_style.scss
+++ b/src/sass/_style.scss
@@ -1,6 +1,7 @@
// Load component based styles
@import "_base_component.scss";
@import "_registration.scss";
+@import "_recommendations_page.scss";
//
// ----------------------------
// #COLORS