diff --git a/src/widgets/ProductRecommendations/components/ProductCard.jsx b/src/widgets/ProductRecommendations/components/ProductCard.jsx
index e69de29..b58498b 100644
--- a/src/widgets/ProductRecommendations/components/ProductCard.jsx
+++ b/src/widgets/ProductRecommendations/components/ProductCard.jsx
@@ -0,0 +1,78 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {
+ Badge,
+ Card,
+ Truncate,
+ Hyperlink,
+} from '@edx/paragon';
+
+const ProductCard = ({
+ title,
+ subtitle,
+ headerImage,
+ schoolLogo,
+ courseType,
+ url,
+}) => {
+ const courseTypeToProductTypeMap = {
+ course: 'Course',
+ 'verified-audit': 'Course',
+ verified: 'Course',
+ audit: 'Course',
+ 'credit-verified-audit': 'Course',
+ 'spoc-verified-audit': 'Course',
+ professional: 'Professional Certificate',
+ 'bootcamp-2u': 'Boot Camp',
+ 'executive-education-2u': 'Executive Education',
+ 'executive-education': 'Executive Education',
+ masters: "Master's",
+ 'masters-verified-audit': "Master's",
+ };
+
+ const productType = courseTypeToProductTypeMap[courseType];
+
+ return (
+
+
+
+
+
+ {title}
+
+ )}
+ subtitle={(
+
+ {subtitle}
+
+ )}
+ />
+
+
+ {productType}
+
+
+
+
+
+ );
+};
+
+ProductCard.propTypes = {
+ title: PropTypes.string.isRequired,
+ subtitle: PropTypes.string.isRequired,
+ headerImage: PropTypes.string.isRequired,
+ schoolLogo: PropTypes.string.isRequired,
+ courseType: PropTypes.string.isRequired,
+ url: PropTypes.string.isRequired,
+};
+
+export default ProductCard;
diff --git a/src/widgets/ProductRecommendations/components/ProductCardContainer.jsx b/src/widgets/ProductRecommendations/components/ProductCardContainer.jsx
index e69de29..126f124 100644
--- a/src/widgets/ProductRecommendations/components/ProductCardContainer.jsx
+++ b/src/widgets/ProductRecommendations/components/ProductCardContainer.jsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import classNames from 'classnames';
+import ProductCard from './ProductCard';
+import ProductCardHeader from './ProductCardHeader';
+
+const ProductCardContainer = ({ courses }) => {
+ const courseTypes = [...new Set(courses.map((item) => item.courseType))];
+
+ return (
+
+ {courses
+ && courseTypes.map((type) => (
+
+
+
+ {courses
+ .filter((course) => course.courseType === type)
+ .map((item) => (
+
+ ))}
+
+
+ ))}
+
+ );
+};
+
+ProductCardContainer.propTypes = {
+ courses: PropTypes.arrayOf(
+ PropTypes.shape({
+ key: PropTypes.string,
+ uuid: PropTypes.string,
+ title: PropTypes.string,
+ image: PropTypes.shape({
+ src: PropTypes.string,
+ }),
+ prospectusPath: PropTypes.string,
+ owners: PropTypes.arrayOf(
+ PropTypes.shape({
+ key: PropTypes.string,
+ name: PropTypes.string,
+ logoImageUrl: PropTypes.string,
+ }),
+ ),
+ activeCourseRun: PropTypes.shape({
+ key: PropTypes.string,
+ marketingUrl: PropTypes.string,
+ }),
+ courseType: PropTypes.string,
+ }),
+ ).isRequired,
+};
+
+export default ProductCardContainer;
diff --git a/src/widgets/ProductRecommendations/components/ProductRecommendationsContainer.jsx b/src/widgets/ProductRecommendations/components/ProductRecommendationsContainer.jsx
index ae8cea7..96c2d20 100644
--- a/src/widgets/ProductRecommendations/components/ProductRecommendationsContainer.jsx
+++ b/src/widgets/ProductRecommendations/components/ProductRecommendationsContainer.jsx
@@ -2,27 +2,25 @@ import React from 'react';
import { Container } from '@edx/paragon';
import { useIntl } from '@edx/frontend-platform/i18n';
-import messages from '../messages';
-import ProductCardHeader from './ProductCardHeader';
import './index.scss';
+import messages from '../messages';
+import ProductCardContainer from './ProductCardContainer';
+import mockCrossProductRecommendations from '../mockData';
const ProductRecommendationsContainer = () => {
const { formatMessage } = useIntl();
- const mockRecommendations = ['executive-education', 'bootcamp-2u', 'course'];
+ const mockRecommendations = mockCrossProductRecommendations.courses;
return (
- {formatMessage(messages.recommendationsHeading)}
- {/* {mockRecommendations.forEach((recommendation) => (
-
- ))} */}
- {mockRecommendations.map((courseType) => (
-
- ))}
+
+ {formatMessage(messages.recommendationsHeading)}
+
+
);
diff --git a/src/widgets/ProductRecommendations/components/index.scss b/src/widgets/ProductRecommendations/components/index.scss
index 3d848ca..d5cb491 100644
--- a/src/widgets/ProductRecommendations/components/index.scss
+++ b/src/widgets/ProductRecommendations/components/index.scss
@@ -1,8 +1,153 @@
+@import "@edx/paragon/scss/core/core";
+
+$horizontal-card-gap: 20px;
+$vertical-card-gap: 24px;
+$card-height: 332px;
+$header-height: 104px;
+$card-width: 270px;
.recommendations-container {
- border: solid
+ border: solid;
+}
+
+.base-card {
+ height: $card-height;
+ width: $card-width !important;
+
+ p {
+ margin-bottom: 0;
+ }
+
+ .pgn__card-image-cap {
+ height: $header-height;
+ object: {
+ fit: cover;
+ position: top center;
+ }
+ }
+
+ .pgn__card-logo-cap {
+ bottom: -1.5rem;
+ object: {
+ fit: scale-down;
+ position: center center;
+ }
+ }
+
+ .product-card-title {
+ font: {
+ size: 1.125rem;
+ weight: 700;
+ }
+
+ line-height: 24px ;
+ }
+
+ .product-card-subtitle {
+ font: {
+ size: 0.875rem;
+ weight: 400;
+ }
+
+ line-height: 24px;
+ }
+
+ .product-badge {
+ position: absolute;
+ bottom: 2.75rem;
+ }
+
+ .footer-content {
+ position: absolute;
+ bottom: 1rem;
+ }
+
+ &.light {
+ background-color: $white;
+
+ .title {
+ color: $black;
+ }
+
+ .subtitle {
+ color: $gray-700;
+ }
+
+ .badge {
+ background-color: $light-500;
+ color: $black;
+ }
+
+ .footer-content {
+ color: $gray-700;
+ }
+ }
+
+ &.dark {
+ background-color: $primary-500;
+
+ .pgn__card-header-title-md {
+ color: $white;
+ }
+
+ .pgn__card-header-subtitle-md {
+ color: $light-200;
+ }
+
+ .title {
+ color: $white;
+ }
+
+ .subtitle {
+ color: $light-200;
+ }
+
+ .badge {
+ background-color: $dark-200;
+ color: $white;
+ }
+
+ .footer-content {
+ color: $light-200;
+ }
+ }
}
.base-card-link:hover {
text-decoration: none;
+}
+
+.base-card:hover {
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.15), 0 0.125rem 0.5rem rgba(0, 0, 0, 0.15);
+}
+
+.base-card-link .base-card {
+ display: flex;
+}
+
+.product-card-container {
+ gap: $vertical-card-gap $horizontal-card-gap;
+ margin: 0 (-$horizontal-card-gap);
+ padding: 0 $horizontal-card-gap;
+
+ .course-subcontainer {
+ display: flex;
+ gap: $vertical-card-gap $horizontal-card-gap;
+ }
+
+ // .base-card-wrapper {
+ // flex: 0 1 calc(100% - #{$horizontal-card-gap});
+
+ // @include media-breakpoint-up(sm) {
+ // flex: 0 1 calc(50% - #{$horizontal-card-gap});
+ // }
+
+ // @include media-breakpoint-up(md) {
+ // flex: 0 1 calc(33.333% - #{$horizontal-card-gap});
+ // }
+
+ // @include media-breakpoint-up(xl) {
+ // flex: 0 1 calc(25% - #{$horizontal-card-gap});
+ // }
+ // }
}
\ No newline at end of file
diff --git a/src/widgets/ProductRecommendations/mockData.js b/src/widgets/ProductRecommendations/mockData.js
new file mode 100644
index 0000000..550db97
--- /dev/null
+++ b/src/widgets/ProductRecommendations/mockData.js
@@ -0,0 +1,100 @@
+const mockCrossProductRecommendations = {
+ courses: [
+ {
+ key: 'HarvardX+CRS',
+ uuid: 'fee0ed87-a122-46a8-b233-3e5c75c755d1',
+ title: 'CRISPR: Gene-editing Applications',
+ image: {
+ src: 'https://prod-discovery.edx-cdn.org/media/course/image/ed79a49b-64c1-48d2-afdc-054bf921e38d-6a76ceb47dea.small.jpg',
+ },
+ prospectusPath:
+ 'course/harvard-vpal-crispr-gene-editing-applications-online-short-course',
+ owners: [
+ {
+ key: 'HarvardX',
+ name: 'Harvard University',
+ logoImageUrl:
+ 'http://localhost:18381/media/organization/logos/ef72daf3-c9a1-4c00-ba37-b3514392bdcf-8839c516815a.png',
+ },
+ ],
+ activeCourseRun: {
+ key: 'course-v1:HarvardX+CRS+1T2023',
+ marketingUrl:
+ 'course/crispr-gene-editing-applications-course-v1-harvardx-crs-1t2023?utm_source=discovery_worker&utm_medium=affiliate_partner',
+ },
+ courseType: 'executive-education-2u',
+ },
+ {
+ key: 'AdelaideX+BC24CYB',
+ uuid: 'dacb53da-35c7-4c6b-b8d0-d7d8c0c78cef',
+ title: 'Cybersecurity Boot Camp',
+ image: {
+ src: 'https://prod-discovery.edx-cdn.org/media/course/image/fbb62b99-9f85-4563-a67c-34ac827560bd-e3e6263b98fd.small.png',
+ },
+ prospectusPath:
+ 'course/the-university-of-adelaide-cybersecurity-boot-camp',
+ owners: [
+ {
+ key: 'AdelaideX',
+ name: 'University of Adelaide',
+ logoImageUrl:
+ 'http://localhost:18381/media/organization/logos/51d054b4-9589-4376-9e9f-15656f3c8d0e-f10fb90c3ff1.png',
+ },
+ ],
+ activeCourseRun: {
+ key: 'course-v1:AdelaideX+BC24CYB+1T2023',
+ marketingUrl:
+ 'course/cybersecurity-boot-camp-course-v1-adelaidex-bc24cyb-1t2023?utm_source=discovery_worker&utm_medium=affiliate_partner',
+ },
+ courseType: 'bootcamp-2u',
+ },
+ {
+ key: 'AA+AA101',
+ uuid: '1e2cae8c-1c67-4067-a3c0-360543e6a9b8',
+ title: 'Data Analytics for Business',
+ image: {
+ src: 'https://prod-discovery.edx-cdn.org/media/course/image/1e2cae8c-1c67-4067-a3c0-360543e6a9b8-50beebb61f2e.small.png',
+ },
+ prospectusPath: '/course/data-analytics-for-business',
+ owners: [
+ {
+ key: 'GTx',
+ name: 'The Georgia Institute of Technology',
+ logoImageUrl:
+ 'https://prod-discovery.edx-cdn.org/organization/logos/8537d31f-01b4-40fd-b652-e17b38eefe41-7956b2a3cd04.png',
+ },
+ ],
+ activeCourseRun: {
+ key: 'course-v1:GTx+MGT6203x+2T2023',
+ marketingUrl:
+ 'https://www.edx.org/course/data-analytics-for-business-course-v1gtxmgt6203x2t2023?utm_source=prospectus_worker&utm_medium=affiliate_partner',
+ },
+ courseType: 'course',
+ },
+ {
+ key: 'AA+AA101',
+ uuid: '876a65e7-425b-437b-bced-bdf8059fec81',
+ title: 'Western and Chinese Art: Masters and Classics',
+ image: {
+ src: 'https://prod-discovery.edx-cdn.org/media/course/image/876a65e7-425b-437b-bced-bdf8059fec81.small.jpg',
+ },
+ prospectusPath: '/course/western-and-chinese-art-masters-and-classics',
+ owners: [
+ {
+ key: 'TsinghuaX',
+ name: 'Tsinghua University',
+ logoImageUrl:
+ 'https://prod-discovery.edx-cdn.org/organization/logos/b5714409-b5f4-4c9d-9348-b0fecbaaddd6-780fbb6c72c7.png',
+ },
+ ],
+ activeCourseRun: {
+ key: 'course-v1:TsinghuaX+00691153.x+1T2015',
+ marketingUrl:
+ 'https://www.edx.org/course/western-chinese-art-masters-classics-tsinghuax-00691153x?utm_source=prospectus_worker&utm_medium=affiliate_partner',
+ },
+ courseType: 'course',
+ },
+ ],
+};
+
+export default mockCrossProductRecommendations;
diff --git a/src/widgets/RecommendationsPanel/index.jsx b/src/widgets/RecommendationsPanel/index.jsx
index c091a8d..b6c68b5 100644
--- a/src/widgets/RecommendationsPanel/index.jsx
+++ b/src/widgets/RecommendationsPanel/index.jsx
@@ -4,6 +4,7 @@ import LookingForChallengeWidget from 'widgets/LookingForChallengeWidget';
import LoadingView from './LoadingView';
import LoadedView from './LoadedView';
import hooks from './hooks';
+import recommendedCoursesData from "../RecommendationsPanel/mockData";
export const RecommendationsPanel = () => {
const {
@@ -17,14 +18,17 @@ export const RecommendationsPanel = () => {
if (isLoading) {
return ();
}
- if (isLoaded && courses.length > 0) {
- return (
-
- );
- }
- if (isFailed) {
- return ();
- }
+
+ const newCourses = recommendedCoursesData.courses;
+
+ // if (newCourses.length > 0) {
+ // return (
+ //
+ // );
+ // }
+ // if (isFailed) {
+ // return ();
+ // }
// default fallback
return ();
};