From aeda262fb0caddb7e0aaa403a187fb751baa07f7 Mon Sep 17 00:00:00 2001 From: Blue Date: Mon, 31 Jul 2023 14:47:22 +0500 Subject: [PATCH] fix: add location resitriction for popular and trending courses (#1010) Description: Filter courses on the basis of location VAN-1573 --- .../ProductCard/hooks/useProducts.jsx | 20 +++++++++++++ src/recommendations/RecommendationsPage.jsx | 29 ++++++++++++------- src/recommendations/data/tests/utils.test.jsx | 7 ++++- src/recommendations/data/utils.js | 13 +++++++++ .../tests/RecommendationsPage.test.jsx | 6 +++- src/recommendations/tests/mockedData.js | 2 +- 6 files changed, 63 insertions(+), 14 deletions(-) create mode 100644 src/recommendations/ProductCard/hooks/useProducts.jsx diff --git a/src/recommendations/ProductCard/hooks/useProducts.jsx b/src/recommendations/ProductCard/hooks/useProducts.jsx new file mode 100644 index 00000000..52f6b546 --- /dev/null +++ b/src/recommendations/ProductCard/hooks/useProducts.jsx @@ -0,0 +1,20 @@ +import { useEffect, useState } from 'react'; + +import { getConfig } from '@edx/frontend-platform'; + +import { filterLocationRestriction } from '../../data/utils'; + +export default function useProducts(countryCode) { + const [popularProducts, setPopularProducts] = useState([]); + const [trendingProducts, setTrendingProducts] = useState([]); + + useEffect(() => { + const popular = filterLocationRestriction(JSON.parse(getConfig().POPULAR_PRODUCTS), countryCode); + const trending = filterLocationRestriction(JSON.parse(getConfig().TRENDING_PRODUCTS), countryCode); + + setPopularProducts(popular); + setTrendingProducts(trending); + }, [countryCode]); + + return { popularProducts, trendingProducts }; +} diff --git a/src/recommendations/RecommendationsPage.jsx b/src/recommendations/RecommendationsPage.jsx index 25e36e35..0e48c6e5 100644 --- a/src/recommendations/RecommendationsPage.jsx +++ b/src/recommendations/RecommendationsPage.jsx @@ -1,4 +1,5 @@ import React, { useEffect } from 'react'; +import { connect } from 'react-redux'; import { getConfig } from '@edx/frontend-platform'; import { useIntl } from '@edx/frontend-platform/i18n'; @@ -10,22 +11,21 @@ import { Helmet } from 'react-helmet'; import { POPULAR, TRENDING } from './data/constants'; import messages from './messages'; +import useProducts from './ProductCard/hooks/useProducts'; import RecommendationsList from './RecommendationsList'; import { trackRecommendationsViewed } from './track'; import { DEFAULT_REDIRECT_URL } from '../data/constants'; -const RecommendationsPage = ({ location }) => { +const RecommendationsPage = ({ location, countryCode }) => { const { formatMessage } = useIntl(); - const registrationResponse = location.state?.registrationResult; const userId = location.state?.userId; + const { popularProducts, trendingProducts } = useProducts(countryCode); const DASHBOARD_URL = getConfig().LMS_BASE_URL.concat(DEFAULT_REDIRECT_URL); - const POPULAR_PRODUCTS = JSON.parse(getConfig().POPULAR_PRODUCTS); - const TRENDING_PRODUCTS = JSON.parse(getConfig().TRENDING_PRODUCTS); useEffect(() => { - trackRecommendationsViewed(POPULAR_PRODUCTS, POPULAR, false, userId); + trackRecommendationsViewed(popularProducts, POPULAR, false, userId); }, []); // eslint-disable-line react-hooks/exhaustive-deps const handleRedirection = () => { @@ -47,12 +47,12 @@ const RecommendationsPage = ({ location }) => { return null; } - if (!POPULAR_PRODUCTS.length || !TRENDING_PRODUCTS.length) { + if (!popularProducts.length || !trendingProducts.length) { handleRedirection(); } const handleOnSelect = (tabKey) => { - const recommendations = tabKey === POPULAR ? POPULAR_PRODUCTS : TRENDING_PRODUCTS; + const recommendations = tabKey === POPULAR ? popularProducts : trendingProducts; trackRecommendationsViewed(recommendations, tabKey, false, userId); }; @@ -83,13 +83,13 @@ const RecommendationsPage = ({ location }) => { > @@ -121,11 +121,18 @@ RecommendationsPage.propTypes = { userId: PropTypes.number, }), }), - + countryCode: PropTypes.string.isRequired, }; RecommendationsPage.defaultProps = { location: { state: {} }, }; -export default RecommendationsPage; +const mapStateToProps = state => ({ + countryCode: state.register.backendCountryCode, +}); + +export default connect( + mapStateToProps, + null, +)(RecommendationsPage); diff --git a/src/recommendations/data/tests/utils.test.jsx b/src/recommendations/data/tests/utils.test.jsx index 3a1d499e..be69464d 100644 --- a/src/recommendations/data/tests/utils.test.jsx +++ b/src/recommendations/data/tests/utils.test.jsx @@ -1,10 +1,15 @@ -import { convertCourseRunKeytoCourseKey, useProductType } from '../utils'; +import mockedProductData from '../../tests/mockedData'; +import { convertCourseRunKeytoCourseKey, filterLocationRestriction, useProductType } from '../utils'; describe('UtilsTests', () => { it('should return the courseKey after parsing the activeCourseRun key', async () => { const courseKey = convertCourseRunKeytoCourseKey('course-v1:Demox+Test101+2023'); expect(courseKey).toEqual('Demox+Test101'); }); + it('should filter courses on the basis of country code', async () => { + const products = filterLocationRestriction(mockedProductData, 'PK'); + expect(products.length).toEqual(1); + }); it('should return courseType and programType', async () => { const programType = useProductType(undefined, 'Professional Certificate'); expect(programType).toEqual('Professional Certificate'); diff --git a/src/recommendations/data/utils.js b/src/recommendations/data/utils.js index 640fe1b3..b7875c14 100644 --- a/src/recommendations/data/utils.js +++ b/src/recommendations/data/utils.js @@ -49,4 +49,17 @@ export const createCodeFriendlyProduct = (type) => type?.replace(/\s+/g, '-').re export const truncateText = (input) => (input?.length > 50 ? `${input.substring(0, 50)}...` : input); +export const filterLocationRestriction = (products, countryCode) => products.filter((product) => { + if (product.locationRestriction) { + if (product.locationRestriction.restrictionType === 'allowlist') { + return product.locationRestriction.countries.includes(countryCode); + } + if (product.locationRestriction.restrictionType === 'blocklist') { + return !product.locationRestriction.countries.includes(countryCode); + } + } + return true; +}, +); + export default convertCourseRunKeytoCourseKey; diff --git a/src/recommendations/tests/RecommendationsPage.test.jsx b/src/recommendations/tests/RecommendationsPage.test.jsx index 9b81c0e5..966809c7 100644 --- a/src/recommendations/tests/RecommendationsPage.test.jsx +++ b/src/recommendations/tests/RecommendationsPage.test.jsx @@ -44,7 +44,11 @@ describe('RecommendationsPageTests', () => { ); beforeEach(() => { - store = mockStore({}); + store = mockStore({ + register: { + backendCountryCode: 'PK', + }, + }); defaultProps = { location: { state: { diff --git a/src/recommendations/tests/mockedData.js b/src/recommendations/tests/mockedData.js index 981b07cf..997f2d4a 100644 --- a/src/recommendations/tests/mockedData.js +++ b/src/recommendations/tests/mockedData.js @@ -71,9 +71,9 @@ const mockedProductData = [ status: 'active', hidden: false, degree: null, - locationRestriction: null, cardType: 'program', cardIndex: 1, + locationRestriction: { restrictionType: 'blocklist', countries: ['PK'] }, }, ];