From a017596a1d3aa9071b92eb5d9b25ab7e49d7839e Mon Sep 17 00:00:00 2001 From: Sag Date: Mon, 4 Sep 2023 19:05:32 +0200 Subject: [PATCH] Added a random order and a limit of 5 to the Recommendations modal (#17958) refs https://github.com/TryGhost/Product/issues/3815 - recommendations are rendered in a random order, using Fisher-Yates shuffle - only 5 recommendations are rendered by default, the other ones are hidden behind a "Show all" button - recommendations are fetched all at once from the backend, as we assume there won't be more than 100-ish recommendations per publication --- .../components/pages/RecommendationsPage.js | 56 ++++++++++++++++--- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/apps/portal/src/components/pages/RecommendationsPage.js b/apps/portal/src/components/pages/RecommendationsPage.js index 7b0e9e608b..663900aeb2 100644 --- a/apps/portal/src/components/pages/RecommendationsPage.js +++ b/apps/portal/src/components/pages/RecommendationsPage.js @@ -1,5 +1,5 @@ import AppContext from '../../AppContext'; -import {useContext} from 'react'; +import {useContext, useState, useEffect} from 'react'; export const RecommendationsPageStyles = ` .gh-portal-recommendation-item { @@ -32,6 +32,24 @@ export const RecommendationsPageStyles = ` } `; +const shuffleRecommendations = (array) => { + let currentIndex = array.length; + let randomIndex; + + // While there remain elements to shuffle... + while (currentIndex > 0) { + // Pick a remaining element... + randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex -= 1; + + // And swap it with the current element. + [array[currentIndex], array[randomIndex]] = [ + array[randomIndex], array[currentIndex]]; + } + + return array; +}; + const RecommendationItem = ({title, url, reason, favicon}) => { const {t} = useContext(AppContext); @@ -54,7 +72,27 @@ const RecommendationItem = ({title, url, reason, favicon}) => { const RecommendationsPage = () => { const {site, t} = useContext(AppContext); const {title, icon} = site; - const recommendations = site.recommendations || []; + const {recommendations_enabled: recommendationsEnabled = false} = site; + const {recommendations = []} = site; + + // Show 5 recommendations by default + const [numToShow, setNumToShow] = useState(5); + + // Show recommendations in a random order + const [shuffledRecommendations, setShuffledRecommendations] = useState([]); + + useEffect(() => { + // Shuffle the array once when the component mounts + setShuffledRecommendations(shuffleRecommendations([...recommendations])); + }, [recommendations]); + + const showAllRecommendations = () => { + setNumToShow(recommendations.length); + }; + + if (!recommendationsEnabled || recommendations.length < 1) { + return null; + } return (
@@ -65,16 +103,18 @@ const RecommendationsPage = () => {

{t(`Here are a few other sites ${title} thinks you may enjoy.`)}

- {recommendations.map((recommendation, index) => ( + {shuffledRecommendations.slice(0, numToShow).map((recommendation, index) => ( ))}
-
- -
+ {numToShow < recommendations.length && ( + + )}
); };